圖的拓撲排序算法

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

關鍵概念定義

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

AOV網:在一個表示工程的有向圖中怔揩,用頂點表示活動捉邢,用弧表示活動之間的優(yōu)先關系,這樣的有向圖為頂點表示活動的網商膊,就是AOV網伏伐。

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

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

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

#define OK 1 // 執(zhí)行成功
#define ERROR 0 // 執(zhí)行失敗

typedef int Status; // 執(zhí)行狀態(tài)

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

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

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

// 頂點表節(jié)點
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; // 邊表節(jié)點

    *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)); // 為邊表節(jié)點分配存儲空間
                e->adjvex = j; // 設置鄰接序號為j
                e->next = (*GL)->adjList[i].firstEdge; // 新節(jié)點指針指向邊表的頭節(jié)點
                (*GL)->adjList[i].firstEdge = e; // 讓新節(jié)點成為邊表的頭節(jié)點
                (*GL)->adjList[j].in++; // 邊終點所指向的節(jié)點入度加1
            }
        }
    }
}

/**
 * 拓撲排序
 * 若鄰接表無回路,則輸出拓撲排序序列并返回OK整吆,若有回路則返回ERROR
 * @param GL 鄰接表
 * @return 執(zhí)行狀態(tài)
 */
Status TopologicalSort(GraphAdjList GL) {
    EdgeNode *e; // 邊表節(jié)點
    int i, k, gettop; // i用于遍歷元素拱撵,k用來獲取頂點下標,gettop用來獲取棧頂元素下標
    int top = 0; // 用于棧指針下標
    int count = 0; // 用于統(tǒng)計輸出頂點的個數
    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; // 將該節(jié)點入棧
        }
    }

    // 未把所有入度為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; // 獲取下個頂點(邊終點所指向的節(jié)點)的下標

            // 將邊終點所指向的節(jié)點的入度減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; // 執(zhí)行狀態(tài)

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

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

    return 0;
}
運行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末欲诺,一起剝皮案震驚了整個濱河市抄谐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扰法,老刑警劉巖蛹含,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異塞颁,居然都是意外死亡浦箱,警方通過查閱死者的電腦和手機吸耿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酷窥,“玉大人咽安,你說我怎么就攤上這事∨钔疲” “怎么了妆棒?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沸伏。 經常有香客問我糕珊,道長,這世上最難降的妖魔是什么毅糟? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任红选,我火速辦了婚禮,結果婚禮上姆另,老公的妹妹穿的比我還像新娘喇肋。我一直安慰自己,他們只是感情好迹辐,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布蝶防。 她就那樣靜靜地躺著,像睡著了一般右核。 火紅的嫁衣襯著肌膚如雪慧脱。 梳的紋絲不亂的頭發(fā)上渺绒,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天贺喝,我揣著相機與錄音,去河邊找鬼宗兼。 笑死躏鱼,一個胖子當著我的面吹牛,可吹牛的內容都是我干的殷绍。 我是一名探鬼主播染苛,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼主到!你這毒婦竟也來了茶行?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤登钥,失蹤者是張志新(化名)和其女友劉穎畔师,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體牧牢,經...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡看锉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年姿锭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伯铣。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡呻此,死狀恐怖,靈堂內的尸體忽然破棺而出腔寡,到底是詐尸還是另有隱情焚鲜,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布放前,位于F島的核電站恃泪,受9級特大地震影響,放射性物質發(fā)生泄漏犀斋。R本人自食惡果不足惜贝乎,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叽粹。 院中可真熱鬧览效,春花似錦、人聲如沸虫几。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辆脸。三九已至但校,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間啡氢,已是汗流浹背状囱。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倘是,地道東北人亭枷。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像搀崭,于是被迫代替她去往敵國和親叨粘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內容

  • https://zh.visualgo.net/graphds 淺談圖形結構https://zh.visualgo...
    狼之獨步閱讀 4,148評論 0 0
  • 第一章 緒論 什么是數據結構瘤睹? 數據結構的定義:數據結構是相互之間存在一種或多種特定關系的數據元素的集合升敲。 第二章...
    SeanCheney閱讀 5,771評論 0 19
  • 圖的定義與術語 1、圖按照有無方向分為無向圖和有向圖轰传。無向圖由頂點和邊構成驴党,有向圖由頂點和弧構成〕裎弧有弧尾和弧頭之...
    unravelW閱讀 404評論 0 0
  • 黑豆湯的用量與煮法:30粒黑豆(綠心鼻弧、黃心设江、圓形、腎形都可以)攘轩、10敛娲妫花生(白皮、紅皮度帮、黑皮都可以)歼捏,泡4-6個小...
    如然_天之明閱讀 1,304評論 0 1
  • 在16年,發(fā)現(xiàn)工作之余還有很多空余時間笨篷,那時候烘焙剛好流行瞳秽,自己又偏愛做手藝類的。有段時間就在知乎關注了很多...
    馮馮7閱讀 181評論 0 2