1. 程式人生 > >拓撲排序(解析)

拓撲排序(解析)

拓撲排序

     通常我們把計劃、施工過程、生產流程、程式流程等都當成一個工程,一個大的工程常常被劃分成許多較小的子工程,這些子工程稱為活動。這些活動完成時,整個工程也就完成了。

  例如,計算機專業學生的課程開設可看成是一個工程,每一門課程就是工程中的活動,下圖給出了若干門所開設的課程,其中有些課程的開設有先後關係,有些則沒有先後關係,有先後關係的課程必須按先後關係開設,如開設資料結構課程之前必須先學完程式設計基礎及離散數學,而開設離散數學則必須先並行學完高等數學、程式設計基礎課程


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;

在執行拓撲排序的過程中,當某個頂點的入度為零(沒有前驅頂點)時,就將此頂點輸出,同時將該頂點的所有後繼頂點的入度減1
,相當於刪除所有以該頂點為尾的弧。為了避免重複檢測頂點的入度是否為零,需要設立一個棧來存放入度為零的頂點。執行拓撲排序的演算法如下:

void 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)

看下面例題來了解拓撲排序