數據結構圖的拓撲排序總結


在數學中,一個圖(Graph)是表示物件與物件之間的關系的數學對象,是圖論的基本研究對象。

圖是十分重要的數據結構,常常被應用於實際生活的應用之中。生活中常見的問題例如交通路線圖、任務指定分配、工期計算、航空網絡等,都可以使用圖相關的理論來建立模型。

下面是《數據結構與算法分析》對圖的若干定義

一個圖(Graph)G = (V, E)由頂點(vertex)集和邊(Edge)集E組成。每一條邊就是一個點對(v,w),其中v,w屬於集合V。有時也把邊Edge叫做弧(arc)。如果點對是有序的,那么圖就叫做是有序的(directed)。有向的圖有時候叫做有向圖。頂點v和w鄰接(adjacent)當且僅當(v,w)屬於E。在一個具有邊(v,w)從而具有邊(w,v)的無向圖中,w和v鄰接且v和w也鄰接。有時候邊還具有第三種成分,叫做權(weight)或值(cost)。

圖的存儲

一種簡單存儲圖的方式時采用一個被稱為鄰接矩陣的二維數組a[i][j],數組的大小為n * nn 為圖的頂點個數。其中如果頂點i到頂點j連通,那么a[i][j] = 1,否則a[i][j] = 0。這種存儲方式的優點是簡單直觀,實現方便。缺點也很明顯,所需要的存儲空間巨大。

當含有n個頂點的圖G中大多數頂點都不是連通,那么意味中n * n 鄰接矩陣中有大量的元素為0,即此時鄰接矩陣是稀疏矩陣。

另一種常見的存儲方式稱為鄰接表(adjacent list),這種方式是申請一個大小為n 的數組head,數組元素head[i],存放着由頂點i的所有鄰接頂底組成的鏈表的頭地址。此種存儲方式的優點顯而易見,相比於前一種方式,存儲空間的大小明顯減小。但是缺點是不直觀,編碼有難度。

拓撲排序

拓撲排序是對又向無圈圖的頂點的一種排序,它使得如果存在一條從Vi 到Vj 的路徑,那么在排序中Vj 必須出現在 Vi 的后面。

一種簡單的求拓撲排序的算法先是找出任意一個入度為0的頂點。然后我們輸出該頂點,並將它和它的邊一起沖圖中刪除。然后,將其鄰接的頂點的入度減去1。然后重復上述過程,直達圖被完全刪除。

不難看出,此種算法首先是外層循環 n 次,其次是內部循環中在選取入度為0 的頂點時候,會內部循環n次。因此總的時間復雜度會達到n * n

另一種較好的改進方法是,將所有入度為0的頂點壓入某個棧,然后每一次輸出頂底元素A后,再將A的所有鄰接頂點的入度減去1,如果某個鄰接頂點的入度此時為0,那么將其繼續入棧。重復上訴操作指導棧空。

可以看出,對每一個入度為0的頂點入棧的操作執行了n 次,n 為頂點數。對出棧的元素A,將其鄰接頂點的入度減1,然后入棧的操作,最多執行了 m 次, m 為圖邊的條數。因此總的時間復雜度就會是線性的 O(n)

代碼示例

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 
  5 struct Node {
  6     int value;
  7     int indegree;
  8     struct Node *next;
  9 };
 10 
 11 //初始化鄰接表
 12 struct Node* initAdjList(int n) {
 13     struct Node* headers;
 14     headers = (struct Node*)malloc(sizeof(struct Node) * n);
 15     int i = 0;
 16     for(i; i < n; i++) {
 17         headers[i].next = NULL;
 18         headers[i].value = 0;
 19         headers[i].indegree = 0;
 20     }
 21     return headers;
 22 }
 23 
 24 void addAdj(struct Node* header, int m, int n) {
 25     struct Node* p = &header[m];
 26     p->value++;
 27     while(p->next != NULL)
 28         p = p->next;
 29     p->next = (struct Node*)malloc(sizeof(struct Node));
 30     p->next->value = n;
 31     p->next->next = NULL;
 32 }
 33 
 34 //打印鄰接表
 35 void printAdjList(struct Node* header, int n) {
 36     int i = 0;
 37     for(i; i < n; i++) {
 38         struct Node* p = &header[i];
 39         printf("Number of %d' adj : %d\t", i, p->value);
 40         while(p->next!= NULL) {
 41             printf("%d --->%d\t", i, p->next->value);
 42             p = p->next;
 43         }
 44         printf("\n");
 45     }
 46 }
 47 
 48 //拓撲排序
 49 int* topSort(struct Node* headers, int n) {
 50     int* zeroStack = (int*)malloc(sizeof(int) * n);
 51     int* result = (int*)malloc(sizeof(int) * n);
 52     int count = 0;
 53     int pIndex = -1;
 54     int i = 0;
 55     while(i < n) {
 56         struct Node* p = &headers[i];
 57         //入度為0,直接進棧
 58         if(p->indegree == 0)
 59             zeroStack[++pIndex] = i;
 60         i++;
 61     }
 62 
 63     while(1) {
 64         //從top里面出棧一個Node Index
 65         int zeroIndex = zeroStack[pIndex--];
 66         result[count++]  = zeroIndex;
 67         struct Node* zeroNode = &headers[zeroIndex];
 68         //將zeroNode的連接點,對應的頭結點的值減一
 69         while(zeroNode->next != NULL) {
 70             struct Node* q = &headers[zeroNode->next->value];
 71             if(--q->indegree == 0)
 72                 zeroStack[++pIndex] = zeroNode->next->value;
 73             zeroNode = zeroNode->next;
 74         }
 75         //棧空
 76         if(pIndex < 0)
 77             break;
 78     }
 79 
 80     return result;
 81 }
 82 
 83 int main()
 84 {
 85     int a[7][7] = { {0,1,1,1,0,0,0},
 86                     {0,0,0,0,1,1,0},
 87                     {0,0,0,0,0,0,1},
 88                     {0,0,1,0,0,1,1},
 89                     {0,0,0,1,0,0,1},
 90                     {0,0,0,0,0,0,0},
 91                     {0,0,0,0,0,1,0}
 92                     };
 93     int n = 7;
 94     struct Node* headers = initAdjList(n);
 95     int i = 0;
 96     int j = 0;
 97     for(i = 0; i < n; i++)
 98         for(j = 0; j < n; j++) {
 99             if(a[i][j] == 1)
100                 addAdj(headers, i, j);
101     }
102 
103     //生成各節點indegree
104     for(i = 0; i < n; i++) {
105         struct Node* p = &headers[i];
106         while(p->next != NULL) {
107             headers[p->next->value].indegree++;
108             p = p->next;
109         }
110     }
111 
112     int* q = topSort(headers, n);
113     printAdjList(headers, n);
114     for(i = 0; i < n; i++) {
115         printf("%d \n", *q++ + 1);
116     }
117     return 0;
118 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM