拓撲排序(解析)
通常我們把計劃、施工過程、生產流程、程式流程等都當成一個工程,一個大的工程常常被劃分成許多較小的子工程,這些子工程稱為活動。這些活動完成時,整個工程也就完成了。
例如,計算機專業學生的課程開設可看成是一個工程,每一門課程就是工程中的活動,下圖給出了若干門所開設的課程,其中有些課程的開設有先後關係,有些則沒有先後關係,有先後關係的課程必須按先後關係開設,如開設資料結構課程之前必須先學完程式設計基礎及離散數學,而開設離散數學則必須先並行學完高等數學、程式設計基礎課程
AOV網——Activity On Vertex Network
用頂點表示活動,用弧表示活動間的優先關係
AOV 網中不能有迴路
拓撲排序:
假設G=(V,E)是一個具有n個頂點的有向圖,V中頂點序列vl,v2,…,vn稱做一個拓撲序列(TopologicalOrder),當且僅當該頂點序列滿足下列條件:若在有向圖G中存在從頂點vi到vj的一條路徑,則在頂點序列中頂點vi必須排在頂點vj之前。通常,在AOV網中,將所有活動排列成一個拓撲序列的過程叫做拓撲排序(TopologicalSort)。
進行拓撲排序的方法:
輸入AOV網路。令 n 為頂點個數。
·在AOV網路中選一個沒有直接前驅的頂點, 並輸出之;
¸從圖中刪去該頂點,同時刪去所有它發出的有向邊;重複以上 ·、¸ 步,直到全部頂點均已輸出,拓撲有序序列形成,拓撲排序完成;或圖中還有未輸出的頂點,但已跳出處理迴圈。這說明圖中還剩下一些頂點,它們都有直接前驅,再也找不到沒有前驅的頂點了。這時AOV網路中必定存在有向環。
在實現拓撲排序的演算法中,採用鄰接表作為有向圖的儲存結構,每個頂點設定一個單鏈表,每個單鏈表有一個表頭結點,在表頭結點中增加一個存放頂點入度的域count,這些表頭結點構成一個數組,表頭結點定義如下:
typedefstruct //表頭結點
{ Vertex data; //頂點資訊
int count; //存放頂點入度
ArcNode *firstarc; //指向第一條弧
}Vnode;
在執行拓撲排序的過程中,當某個頂點的入度為零(沒有前驅頂點)時,就將此頂點輸出,同時將該頂點的所有後繼頂點的入度減1void topsort(VNode adj[],int n)
{ int i,j;
int stack[MAXV],top=0; //棧stack的指標為top
ArcNode *p;
for(i=0;i<n;i++)
if(adj[i].count==0)
{ top++; stack[top]=i;
}
while(top>0) //棧不為空
{ i=stack[top];
top--; //頂點vi出棧
printf(“%d”,i); //輸出vi
p=adj[i].firstarc; //指向以vi為弧尾的第一條弧
while(p!=NULL)
{ j=p->adjvex; //以vi為弧尾的弧的另一頂點vj
adj[j].count--; //頂點vj的入度減1
if(adj[j].count==0) //入度為0的相鄰頂點入棧
{ top++; stack[top]=j;
}
p=p->nextarc; //指向以vi為弧尾的下一條弧
}
}
}
對於有n個頂點和e條邊的有向圖而言,for迴圈中建立入度為0的頂點棧時間為O(n);若在拓撲排序過程中不出現有向環,則每個頂點出棧、入棧和入度減1的操作在while(top>0)迴圈語句中均執行e次,因此拓撲排序總的時間花費為O (n+e)。看下面例題來了解拓撲排序