拓扑排序(完整案列及C语言完整代码实现)
寫在前面:博主是一位普普通通的19屆雙非軟工在讀生,平時最大的愛好就是聽聽歌,逛逛B站。博主很喜歡的一句話花開堪折直須折,莫待無花空折枝:博主的理解是頭一次為人,就應該做自己想做的事,做自己不后悔的事,做自己以后不會留有遺憾的事,做自己覺得有意義的事,不浪費這大好的青春年華。博主寫博客目的是記錄所學到的知識并方便自己復習,在記錄知識的同時獲得部分瀏覽量,得到更多人的認可,滿足小小的成就感,同時在寫博客的途中結交更多志同道合的朋友,讓自己在技術的路上并不孤單。
目錄:
1.全序和偏序
2.拓撲排序的方法
3.拓撲排序C語言完整代碼實現
4.拓撲排序小結
1.全序和偏序
拓撲排序指的是將有向無環圖(又稱“DAG”圖)中的頂點按照圖中指定的先后順序進行排序。
例如,上圖 中的兩個圖都是有向無環圖,都可以使用拓撲排序對圖中的頂點進行排序,兩個圖形的區別是:左圖中的 V2 和 V3之間沒有明確的前后順序;而右圖中任意兩個頂點之間都有前后順序。
所以,左圖中頂點之間的關系被稱為“偏序”關系;右圖中頂點之間的關系被稱為”全序“關系。全序是偏序的一種特殊情況。對于任意一個有向無環圖來說,通過拓撲排序得到的序列首先一定是偏序,如果任意兩個頂點都具有前后順序,那么此序列是全序。
2.拓撲排序的方法
對有向無環圖進行拓撲排序,只需要遵循兩個原則:
上面左圖拓撲排序如下:
對于此圖來說,拓撲排序有兩種:
1.V1 -> V2 -> V3 -> V4
2.V1 -> V3 -> V2 -> V4
如果頂點之間只是具有偏序關系,那么拓撲排序的結果肯定不唯一;如果頂點之間是全序關系,那么拓撲排序得到的序列唯一
有向無環圖如果頂點本身具有某種實際意義,例如用有向無環圖表示大學期間所學習的全部課程,每個頂點都表示一門課程,有向邊表示課程學習的先后次序,例如要先學《程序設計基礎》和《離散數學》,然后才能學習《數據結構》。所以用來表示某種活動間的優先關系的有向圖簡稱為“AOV 網”。
3.拓撲排序C語言完整代碼實現
在編寫程序解決拓撲排序的問題時,大致思路為:首先通過鄰接表將 AOV 網進行存儲,由于拓撲排序的整個過程中,都是以頂 點的入度為依據進行排序,所以需要根據建立的鄰接表統計出各頂點的入度。 在得到各頂點的入度后,首先找到入度為 0 的頂點作為拓撲排序的起始點,然后查找以該頂點為起始點的所有頂點,如果入度 為 1,說明如果刪除前一個頂點后,該頂點的入度為 0,為拓撲排序的下一個對象
#include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 20//最大頂點個數 #define VertexType int//頂點數據的類型 typedef enum{false,true} bool; typedef struct ArcNode{int adjvex;//鄰接點在數組中的位置下標struct ArcNode * nextarc;//指向下一個鄰接點的指針 }ArcNode; typedef struct VNode{VertexType data;//頂點的數據域ArcNode * firstarc;//指向鄰接點的指針 }VNode,AdjList[MAX_VERTEX_NUM];//存儲各鏈表頭結點的數組 typedef struct {AdjList vertices;//圖中頂點及各鄰接點數組int vexnum,arcnum;//記錄圖中頂點數和邊或弧數 }ALGraph; //找到頂點對應在鄰接表數組中的位置下標 int LocateVex(ALGraph G,VertexType u){for (int i=0; i<G.vexnum; i++) {if (G.vertices[i].data==u) {return i;}}return -1; } //創建 AOV 網,構建鄰接表 void CreateAOV(ALGraph **G){*G=(ALGraph*)malloc(sizeof(ALGraph)); scanf("%d,%d",&((*G)->vexnum),&((*G)->arcnum));for (int i=0; i<(*G)->vexnum; i++) {scanf("%d",&((*G)->vertices[i].data));(*G)->vertices[i].firstarc=NULL;}VertexType initial,end;for (int i=0; i<(*G)->arcnum; i++) { scanf("%d,%d",&initial,&end);ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=LocateVex(*(*G), end);p->nextarc=NULL;int locate=LocateVex(*(*G), initial);p->nextarc=(*G)->vertices[locate].firstarc;(*G)->vertices[locate].firstarc=p;} } //結構體定義棧結構 typedef struct stack{VertexType data; struct stack * next; }stack; //初始化棧結構 void initStack(stack* *S){ (*S)=(stack*)malloc(sizeof(stack)); (*S)->next=NULL; } //判斷鏈表是否為空 bool StackEmpty(stack S){if (S.next==NULL) { return true;}return false; } //進棧,以頭插法將新結點插入到鏈表中 void push(stack *S,VertexType u){stack *p=(stack*)malloc(sizeof(stack));p->data=u;p->next=NULL;p->next=S->next;S->next=p; } //彈棧函數,刪除鏈表首元結點的同時,釋放該空間,并將該結點中的數據域通過地址傳值給變量 i; void pop(stack *S,VertexType *i){ stack *p=S->next; *i=p->data;S->next=S->next->next;free(p); } //統計各頂點的入度 void FindInDegree(ALGraph G,int indegree[]){ //初始化數組,默認初始值全部為 0for (int i=0; i<G.vexnum; i++) {indegree[i]=0;} //遍歷鄰接表,根據各鏈表中結點的數據域存儲的各頂點位置下標,在 indegree 數組相應位置+1for (int i=0; i<G.vexnum; i++) {ArcNode *p=G.vertices[i].firstarc; while (p) {indegree[p->adjvex]++;p=p->nextarc;} } } void TopologicalSort(ALGraph G){int indegree[G.vexnum];//創建記錄各頂點入度的數組FindInDegree(G,indegree);//統計各頂點的入度 //建立棧結構,程序中使用的是鏈表stack *S;initStack(&S); //查找度為 0 的頂點,作為起始點for (int i=0; i<G.vexnum; i++) {if (!indegree[i]) {push(S, i);}}int count=0; //當棧為空,說明排序完成while (!StackEmpty(*S)) {int index; //彈棧,并記錄棧中保存的頂點所在鄰接表數組中的位置pop(S,&index);printf("%d",G.vertices[index].data);++count; //依次查找跟該頂點相鏈接的頂點,如果初始入度為 1,當刪除前一個頂點后,該頂點入度為 0for (ArcNode *p=G.vertices[index].firstarc; p; p=p->nextarc) {VertexType k=p->adjvex;if (!(--indegree[k])) {//頂點入度為 0,入棧push(S, k);}}} //如果 count 值小于頂點數量,表明該有向圖有環if (count<G.vexnum) {printf("該圖有回路"); return;} } int main(){ALGraph *G;CreateAOV(&G);//創建 AOV 網TopologicalSort(*G);//進行拓撲排序return 0; }對于下面例子
進行拓撲排序:
4.拓撲排序小結
對于含有n個頂點和e條邊的有向圖而言,建立求各個頂點的入度的時間復雜度為O(e);建立0入度頂點棧的時間復雜度為O(n),在拓撲排序中若有向圖無環,則每個頂點進一次棧出一次棧,所以總的時間復雜度為O(n+e)
本篇博客轉載C語言中文網
總結
以上是生活随笔為你收集整理的拓扑排序(完整案列及C语言完整代码实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最短路径之迪杰斯特拉(Dijkstra
- 下一篇: 分块查找(完整案例与C语言完整代码实现)