1. 程式人生 > >【筆記】AOV網與拓撲排序

【筆記】AOV網與拓撲排序

1.無環路有向圖

  不存在有向環路的有向圖稱為無環路有向圖(簡寫為dag)。一個無環路有向圖對應的無向圖可能存在環路,但它不存在有向環路。除非特別宣告,有向圖中的環路均指有向環路。
  無環路有向圖可用於表示偏序集。

2.AOV網

  在每一個工程中,可以將工程分為若干個子工程,這些子工程稱為活動。如果用圖中的頂點表示活動,以有向圖的弧表示活動之間的優先關係,這樣的有向圖稱為AOV網,即頂點表示活動的網。在AOV網中,如果從頂點vi到頂點vj之間存在一條路徑<vi,vj>,則頂點vi是頂點vj的直接前驅,頂點vj是頂點vi的直接後繼。活動中的制約關係可以通過AOV網中的表示。
  在AOV網中,不允許出現環,如果出現環就表示某個活動是自己的先決條件。因此需要對AOV網判斷是否存在環,可以利用有向圖的拓撲排序進行判斷。


這裡寫圖片描述
這裡寫圖片描述

3.拓撲排序

  拓撲排序就是將AOV網中的所有頂點排列成一個線性序列,並且序列滿足以下條件:在AOV網中,如果從頂點vivj存在一條路徑,則在該線性序列中,頂點vi一定出現在頂點vj之前。因此拓撲排序的過程就是將AOV網中的各個活動組成一個可行的實施方案。

  對AOV網進行拓撲排序的演算法:
  1. 在AOV網中任意選擇一個沒有前驅的頂點,即頂點入度為零,將該頂點輸出。
  2. 從AOV網中刪除該頂點,並刪除從該頂點出發的弧。
  3. 重複執行步驟1和步驟2,直達AOV網中所有都已經被輸出,或者AOV網中不存在無前驅的頂點為止。

  按照上述步驟,AOV網的拓撲序列為(

C1,C2,C3,C4,C5,C6,C7,C8,C9,C10)(C6,C7,C8,C9,C1,C2,C3,C4,C5,C10)
  下圖是AOV網的拓撲序列的構造過程,其拓撲序列為V1,V2,V3,V5,V4,V6


這裡寫圖片描述

  在對AOV網進行拓撲排序結束後,可能會出現兩種情況:一種是AOV網中的頂點全部輸出,表示網中不存在迴路;另一種是AOV網中還存在沒有輸出的頂點,剩餘的未輸出頂點的入度都不為零,表示網中存在迴路。

4.AOV網的拓撲排序演算法實現

  採用鄰接表儲存的AOV網的拓撲排序的演算法實現:遍歷鄰接表,將各個頂點入度儲存在陣列indegree中。將入度為零的頂點入棧,依次將棧頂元素出棧並輸出該頂點,對該頂點的鄰接頂點的入度減1,如果鄰接頂點的入度為零,則入棧;否則,將下一個鄰接頂點的入度減1並進行相同的處理。然後繼續將棧中元素出棧,重複執行以上過程,直到棧空為止。

int TopologicalSort(AdjGraph N)
/*有向圖G的拓撲排序。如果圖G沒有迴路,則輸出G的一個拓撲序列並返回1,否則返回0*/
{
    int i,k,count=0;
    int indegree[MaxSize];      /*陣列indegree儲存各頂點的入度*/
    SeqStack S;
    ArcNode *p;
    /*將圖中各頂點的入度儲存在陣列indegree中*/
    for(i=0;i<N.vexnum;i++)     /*將陣列indegree賦初值*/
        indegree[i]=0;
    for(i=0;i<N.vexnum;i++)
    {
        p=N.vertex[i].firstarc;
        while(p!=NULL)
        {
            k=p->adjvex;
            indegree[k]++;
            p=p->nextarc;
        }
    }
    InitStack(&S);              /*初始化棧S*/
    printf("拓撲序列:");
    for(i=0;i<N.vexnum;i++)
        if(!indegree[i])        /*將入度為零的頂點入棧*/
            PushStack(&S,i);
        while(!StackEmpty(S))   /*如果棧S不為空*/
        {
            PopStack(&S,&i);    /*從棧S將頂點j彈出,輸出該頂點*/
            printf("%s ",N.vertex[i].data);
            count++;            /*對入棧T的頂點計數*/
            for(p=N.vertex[i].firstarc;p;p=p->nextarc)  /*處理編號為i的頂點的每個鄰接點*/
            {
                k=p->adjvex;            /*頂點序號為k*/
                if(--indegree[k]==0)    /*如果k的入度減1後變為0,則將k入棧S*/
                    PushStack(&S,k);
            }
        }
        if(count<N.vexnum)
        {
            printf("該有向網有迴路\n");
            return 0;
        }
        else
            return 1;
}

  對有n個頂點和e條弧的有向圖來說,建立求各頂點的入度的時間複雜度為O(e),將零入度的頂點入棧的時間複雜度為O(n);在拓撲排序過程中,若有向圖無環,則每個頂點進一次棧,出一次棧,入度減1操作在while語句中總共執行e次,因此拓撲排序總的時間複雜度為O(n+e)