圖的拓撲排序算法

拓撲排序:對一個有向圖構造拓撲序列的過程。

關鍵概念定義

拓撲序列:設G=(V,E)是一個具有n個頂點的有向圖,V中的頂點序列v1,v2,……,vn,若滿足從頂點vi到vj有一條路徑,則在頂點序列中頂點vi必須出現在vj之前。符合這樣定義的序列叫拓撲序列。

AOV網:在一個表示工程的有向圖中,用頂點表示活動,用弧表示活動之間的優先關系,這樣的有向圖為頂點表示活動的網,就是AOV網。

拓撲排序算法思路:從AOV網中選擇一個入度為0的頂點輸出,然后刪除此頂點,并刪除此頂點為尾的弧,重復此步驟,直到輸出全部頂點或者AOV網中不存在入度為0的頂點為止。

// 圖的拓撲排序算法
#include <stdio.h>
#include <malloc.h>

#define MAXEDGE 20 // 最大邊數
#define MAXVEX 14 // 最大頂點數

#define OK 1 // 執行成功
#define ERROR 0 // 執行失敗

typedef int Status; // 執行狀態

// 鄰接矩陣結構
typedef struct {
    int vexs[MAXVEX]; // 頂點表
    int arc[MAXVEX][MAXVEX]; // 邊表
    int numNodes, numEdges; // 圖中當前的頂點數,邊數
} MGraph;

/**************** 用到的鄰接表結構 ****************/

// 邊表節點
typedef struct EdgeNode {
    int adjvex; // 鄰接點域,存儲該頂點對應的下標
    int weight; // 用來存儲權值(非網圖可沒有)
    struct EdgeNode *next; // 指向下一個鄰接點
} EdgeNode;

// 頂點表節點
typedef struct VertexNode {
    int in; // 頂點入度
    int data; // 頂點域,存儲頂點信息
    EdgeNode *firstEdge; // 邊表頭指針
} VertexNode, AdjList[MAXVEX];

// 鄰接表結構
typedef struct {
    AdjList adjList;// 頂點表數組
    int numNodes, numEdges; // 圖中當前頂點數,邊數
} graphAdjList, *GraphAdjList;

/*************************************************/

/**
 * 生成鄰接矩陣(圖)
 * @param G 鄰接矩陣(圖)
 */
void CreateMGraph(MGraph *G) {
    int i, j; // 用于遍歷元素

    G->numEdges = MAXEDGE; // 設置邊數
    G->numNodes = MAXVEX; // 設置頂點數

    // 初始化圖的頂點表
    for (i = 0; i < G->numNodes; i++) {
        G->vexs[i] = i;
    }

    // 初始化圖的邊表
    for (i = 0; i < G->numNodes; i++) {
        for (j = 0; j < G->numNodes; j++) {
            G->arc[i][j] = 0; // 設置所有邊的默認值為0
        }
    }

    // 設置特定邊的權(值為1表示該位置有邊)
    G->arc[0][4] = 1;
    G->arc[0][5] = 1;
    G->arc[0][11] = 1;

    G->arc[1][2] = 1;
    G->arc[1][4] = 1;
    G->arc[1][8] = 1;

    G->arc[2][5] = 1;
    G->arc[2][6] = 1;
    G->arc[2][9] = 1;

    G->arc[3][2] = 1;
    G->arc[3][13] = 1;

    G->arc[4][7] = 1;

    G->arc[5][8] = 1;
    G->arc[5][12] = 1;

    G->arc[6][5] = 1;

    G->arc[8][7] = 1;

    G->arc[9][10] = 1;
    G->arc[9][11] = 1;

    G->arc[10][13] = 1;

    G->arc[12][9] = 1;
}

/**
 * 使用鄰接矩陣生成鄰接表
 * @param G 鄰接矩陣
 * @param GL 鄰接表
 */
void CreateALGraph(MGraph G, GraphAdjList *GL) {
    int i, j; // 用于遍歷元素
    EdgeNode *e; // 邊表節點

    *GL = (GraphAdjList) malloc(sizeof(graphAdjList)); // 為鄰接表表分配存儲空間

    (*GL)->numNodes = G.numNodes; // 設置鄰接表的頂點數
    (*GL)->numEdges = G.numEdges; // 設置鄰接表的邊數

    // 建立頂點表
    for (i = 0; i < G.numNodes; i++) {
        (*GL)->adjList[i].in = 0; // 設置下標為i位置的頂點入讀為0
        (*GL)->adjList[i].data = G.vexs[i]; // 存入該頂點的權值
        (*GL)->adjList[i].firstEdge = NULL; // 設置頂點對應的邊表為空
    }

    // 建立邊表
    for (i = 0; i < G.numNodes; i++) {
        for (j = 0; j < G.numNodes; j++) {
            if (G.arc[i][j] == 1) {
                e = (EdgeNode *) malloc(sizeof(EdgeNode)); // 為邊表節點分配存儲空間
                e->adjvex = j; // 設置鄰接序號為j
                e->next = (*GL)->adjList[i].firstEdge; // 新節點指針指向邊表的頭節點
                (*GL)->adjList[i].firstEdge = e; // 讓新節點成為邊表的頭節點
                (*GL)->adjList[j].in++; // 邊終點所指向的節點入度加1
            }
        }
    }
}

/**
 * 拓撲排序
 * 若鄰接表無回路,則輸出拓撲排序序列并返回OK,若有回路則返回ERROR
 * @param GL 鄰接表
 * @return 執行狀態
 */
Status TopologicalSort(GraphAdjList GL) {
    EdgeNode *e; // 邊表節點
    int i, k, gettop; // i用于遍歷元素,k用來獲取頂點下標,gettop用來獲取棧頂元素下標
    int top = 0; // 用于棧指針下標
    int count = 0; // 用于統計輸出頂點的個數
    int *stack; // 存儲入度為0的頂點的棧

    stack = (int *) malloc(GL->numNodes * sizeof(int)); // 為棧分配存儲空間

    // 將所有入度為0的頂點入棧
    for (i = 0; i < GL->numNodes; i++) {
        if (GL->adjList[i].in == 0) { // 頂點入度為0
            stack[++top] = i; // 將該節點入棧
        }
    }

    // 未把所有入度為0的頂點出棧
    while (top != 0) {
        gettop = stack[top--]; // 獲取入度為0的棧的棧頂元素
        printf("%d -> ", GL->adjList[gettop].data); // 打印該元素的頂點信息
        count++; // 輸入頂點個數加1

        // 遍歷該頂點的邊表
        for (e = GL->adjList[gettop].firstEdge; e; e = e->next) {
            k = e->adjvex; // 獲取下個頂點(邊終點所指向的節點)的下標

            // 將邊終點所指向的節點的入度減1,如果該頂點入讀為0,將頂點入棧
            if (!(--GL->adjList[k].in)) {
                stack[++top] = k; // 將頂點入棧
            }
        }
    }
    printf("\n");

    // 輸出的頂點數小于鄰接表的頂點數,鄰接表中有回路,拓撲排序失敗
    if (count < GL->numNodes) {
        return ERROR;
    } else { // 鄰接表中無回路,拓撲排序成功
        return OK;
    }
}

int main() {
    MGraph G; // 鄰接矩陣
    GraphAdjList GL; // 鄰接表
    Status status; // 執行狀態

    CreateMGraph(&G); // 創建鄰接矩陣
    CreateALGraph(G, &GL); // 使用鄰接矩陣創建鄰接表

    status = TopologicalSort(GL); // 將鄰接表進行拓撲排序,獲取執行狀態
    printf("status: %s", status == OK ? "執行成功" : "執行失敗");

    return 0;
}
運行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容

  • https://zh.visualgo.net/graphds 淺談圖形結構https://zh.visualgo...
    狼之獨步閱讀 4,186評論 0 0
  • 第一章 緒論 什么是數據結構? 數據結構的定義:數據結構是相互之間存在一種或多種特定關系的數據元素的集合。 第二章...
    SeanCheney閱讀 5,803評論 0 19
  • 圖的定義與術語 1、圖按照有無方向分為無向圖和有向圖。無向圖由頂點和邊構成,有向圖由頂點和弧構成。弧有弧尾和弧頭之...
    unravelW閱讀 419評論 0 0
  • 黑豆湯的用量與煮法:30粒黑豆(綠心、黃心、圓形、腎形都可以)、10粒花生(白皮、紅皮、黑皮都可以),泡4-6個小...
    如然_天之明閱讀 1,323評論 0 1
  • 在16年,發現工作之余還有很多空余時間,那時候烘焙剛好流行,自己又偏愛做手藝類的。有段時間就在知乎關注了很多...
    馮馮7閱讀 187評論 0 2