C語言 拓補排序 有向無環圖

拓補排序簡介

對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前

首先需要知道一個概念:入度。

通常指有向圖中某點作爲圖中邊的終點的次數之和。

比如:
這裏寫圖片描述

節點 A B C D E
入度 0 1 1 1 3

實現過程

對圖進行深度優化搜索,將頂點放入數組中,改變與之連接的下個節點的入度。

圖片取自:拓撲排序(Topological Sorting)
這裏寫圖片描述

代碼實現

核心代碼:

BOOLEAN isInTop(VTYPE *topNum, int length, VTYPE key) {
    for (int i = 0; i < length; i++) {
        if (topNum[i] == key) {
            return TRUE;
        }
    }
    return FALSE;
}

int degreePos(AdjGraphPtr adj, VTYPE *topNum , int length) {
    int pos = -1;
    for (int i = 0; i < adj->vNum; i++) {
        if (adj->vertexList[i]->degree == 0) {
            if (isInTop(topNum, length, adj->vertexList[i]->v) == FALSE) {
                pos = i;
                return pos;
            }
        }
    }
    return pos;
}

int getEmptyPos(VTYPE *topNum, int length) {
    //獲得未使用的位置
    for (int i = 0; i < 5; i++) {
        if (topNum[i] == 0) {
            return i;
        }
    }
    return -1;
}

int dfs(AdjGraphPtr adj, VTYPE *topNum, int length, int pos) {
    EdgePtr tmp = adj->vertexList[pos]->firstEdge;
    while (tmp != NULL) {
        VTYPE w = tmp->w;
        int w_pos = getVertexPos(adj, w);
        adj->vertexList[w_pos]->degree--;
        if (adj->vertexList[w_pos]->degree == 0)
            continue;

        if (isInTop(topNum, length, w) == FALSE) {
            int emptyPos = getEmptyPos(topNum, length);
            if(emptyPos != -1)
                topNum[emptyPos] = w;
        }
        dfs(adj, topNum, length, w_pos);
        tmp = tmp->next;
    }
}


void topSort(AdjGraphPtr adj, int length) {
    VTYPE topNum[5];
    for (int i = 0; i < length; i++) {
        topNum[i] = 0;
    }

    for (int i = 0; i < length; i++) {
        int pos = degreePos(adj, topNum, length);
        if (pos == -1) {
            return;
        }

        int emptyPos = getEmptyPos(topNum, length);
        if (emptyPos != -1)
            topNum[emptyPos] = adj->vertexList[pos]->v;

        dfs(adj, topNum, length, pos);
    }
}

這裏寫圖片描述
完整代碼:

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#define MAXVEX 100
#define MAXNUM 10
#define INFINITE 65525

#define VTYPE char
#define QUETYPE EdgePtr
#define SORTTYPE int

#define BOOLEAN int
#define TRUE 1
#define FALSE 0

typedef struct EdgeNode {
    VTYPE v;
    VTYPE w;
    int weight;
    struct EdgeNode *next;
} Edge, *EdgePtr;

typedef struct VertexNode {
    VTYPE v;
    int degree;
    EdgePtr firstEdge;
} Vertex, *VertexPtr;

typedef struct {
    VertexPtr vertexList[MAXVEX];
    int vNum;
    int eNum;
} AdjGraph, *AdjGraphPtr;


void freeAdj(AdjGraphPtr a);
EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight);
int getVertexPos(const AdjGraphPtr m, const VTYPE key);
void insertVertex(AdjGraphPtr adj, const VTYPE key);
void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2);
AdjGraphPtr createDirectedGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2);

void print(int *a, int length);

BOOLEAN isInTop(VTYPE *topNum, int length, VTYPE key) {
    for (int i = 0; i < length; i++) {
        if (topNum[i] == key) {
            return TRUE;
        }
    }
    return FALSE;
}

int degreePos(AdjGraphPtr adj, VTYPE *topNum , int length) {
    int pos = -1;
    for (int i = 0; i < adj->vNum; i++) {
        if (adj->vertexList[i]->degree == 0) {
            if (isInTop(topNum, length, adj->vertexList[i]->v) == FALSE) {
                pos = i;
                return pos;
            }
        }
    }
    return pos;
}

int getEmptyPos(VTYPE *topNum, int length) {
    //獲得未使用的位置
    for (int i = 0; i < 5; i++) {
        if (topNum[i] == 0) {
            return i;
        }
    }
    return -1;
}

int dfs(AdjGraphPtr adj, VTYPE *topNum, int length, int pos) {
    EdgePtr tmp = adj->vertexList[pos]->firstEdge;
    while (tmp != NULL) {
        VTYPE w = tmp->w;
        int w_pos = getVertexPos(adj, w);
        adj->vertexList[w_pos]->degree--;
        if (adj->vertexList[w_pos]->degree == 0)
            continue;

        if (isInTop(topNum, length, w) == FALSE) {
            int emptyPos = getEmptyPos(topNum, length);
            if(emptyPos != -1)
                topNum[emptyPos] = w;
        }
        dfs(adj, topNum, length, w_pos);
        tmp = tmp->next;
    }
}


void topSort(AdjGraphPtr adj, int length) {
    VTYPE topNum[5];
    for (int i = 0; i < length; i++) {
        topNum[i] = 0;
    }

    for (int i = 0; i < length; i++) {
        int pos = degreePos(adj, topNum, length);
        if (pos == -1) {
            return;
        }

        int emptyPos = getEmptyPos(topNum, length);
        if (emptyPos != -1)
            topNum[emptyPos] = adj->vertexList[pos]->v;

        dfs(adj, topNum, length, pos);
    }
}

void main() {

    int e[6][3] = {
        { 'A', 'B', 3 },
        { 'B', 'D', 1 },
        { 'B', 'E', 5 },
        { 'B', 'C', 6 },
        { 'D', 'E', 7 },
        { 'C', 'E', 6 },
    };

    const int e_length_1 = 6;
    const int e_length_2 = 3;

    VTYPE v[5] = { 'A','B','C','D','E' };
    const int v_length = 5;

    AdjGraphPtr adj = createDirectedGraph(v, v_length, e, e_length_1, e_length_2);
    topSort(adj, v_length);
    freeAdj(adj);
}



void freeAdj(AdjGraphPtr a) {
    for (int i = 0; i < a->vNum; i++) {
        if (a->vertexList[i]->firstEdge != NULL) {
            EdgePtr tmp = a->vertexList[i]->firstEdge;
            while (tmp->next != NULL) {
                EdgePtr t = tmp;
                tmp = tmp->next;
                free(t);
            }
            free(tmp);
        }
        free(a->vertexList[i]);
    }
    free(a);
}


EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight) {
    EdgePtr a = (EdgePtr)malloc(sizeof(Edge));
    memset(a, 0, sizeof(Edge));
    a->v = v;
    a->w = w;
    a->weight = weight;
    a->next = NULL;
    return a;
}


int getVertexPos(const AdjGraphPtr m, const VTYPE key) {
    for (int i = 0; i < m->vNum; i++) {
        if (m->vertexList[i]->v == key)
            return i;
    }
    return -1;
}


void insertVertex(AdjGraphPtr adj, const VTYPE key) {
    for (int i = 0; i < adj->vNum; i++) {
        if (adj->vertexList[i]->v == key)
            return;
    }

    VertexPtr vNode = (VertexPtr)malloc(sizeof(Vertex));
    memset(vNode, 0, sizeof(Vertex));
    vNode->v = key;
    vNode->firstEdge = NULL;

    adj->vertexList[adj->vNum] = vNode;
    adj->vNum++;
}

void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
    int pos_a = getVertexPos(adj, a);
    EdgePtr avex = createEdgeNode(a, b, weight);

    if (adj->vertexList[pos_a]->firstEdge == NULL) {
        adj->vertexList[pos_a]->firstEdge = avex;
    }
    else {
        EdgePtr tmp = adj->vertexList[pos_a]->firstEdge;
        while (tmp->next != NULL) {
            tmp = tmp->next;
        }
        tmp->next = avex;
    }

    int pos_b = getVertexPos(adj, b);
    adj->vertexList[pos_b]->degree++;
}

void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
    insertEdge(adj, a, b, weight);
    insertEdge(adj, b, a, weight);
    adj->eNum++;
}

AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2) {
    AdjGraphPtr adj = (AdjGraphPtr)malloc(sizeof(AdjGraph));
    memset(adj, 0, sizeof(AdjGraph));

    for (int i = 0; i < v_length; i++) {
        insertVertex(adj, v[i]);
    }

    for (int i = 0; i < e_length_1; i++) {
        VTYPE a = *(e + e_length_2 * i + 0);
        VTYPE b = *(e + e_length_2 * i + 1);
        int weight = *(e + e_length_2 * i + 2);

        addEdge(adj, a, b, weight);
    }
    return adj;
}

AdjGraphPtr createDirectedGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2) {
    AdjGraphPtr adj = (AdjGraphPtr)malloc(sizeof(AdjGraph));
    memset(adj, 0, sizeof(AdjGraph));

    for (int i = 0; i < v_length; i++) {
        insertVertex(adj, v[i]);
    }

    for (int i = 0; i < e_length_1; i++) {
        VTYPE a = *(e + e_length_2 * i + 0);
        VTYPE b = *(e + e_length_2 * i + 1);
        int weight = *(e + e_length_2 * i + 2);

        insertEdge(adj, a, b, weight);
    }
    adj->eNum++;
    return adj;
}

void print(int *a, int length) {
    for (int i = 0; i < length; i++) {
        printf("%d ", a[i]);
    }
    putchar('\n');
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章