拓撲排序:
按照有向圖給出的次序關系,將圖中頂點排成一個線性序列,對於有向圖中沒有限定次序關系的頂點,則可以人為加上任意的次序關系,由此所得頂點的線性序列稱之為拓撲有序序列。顯然對於有回路的有向圖得不到拓撲有序序列,因為有回路的話,頂點的先后次序就不確定了。
例如:例如,下圖,我們可以人為限定次序:A B C D 或 A C B D
解釋:該輸出順序特點就是后面的頂點輸出必然后於該頂點的前驅頂點
算法:
- 從有向圖中選取一個沒有前驅(沒有在它之前活動)的頂點,輸出之;
- 從有向圖中刪去此頂點以及所有以它為尾的弧;
- 重復上述兩步,直至圖空,或者圖不空但找不到無前驅的頂點為止。
- 沒有被打印輸出的頂點構成回路了。
那么、如何找到一個沒有前驅的頂點呢?
通過解釋看出,沒有前驅的頂點的入度為零。我們每次重復第一個操作就是找到圖中入度為零的點並且輸出。
當然問題來了,如果圖中有多個入度為零的頂點,如何判斷誰先輸出。或者怎么依次輸出它們?
答:這里可以利用棧(隊列),暫時將其入棧(入隊),每次輸出棧頂(隊頭)元素。因為每次都是輸出的入度為零的節點,不同的存儲方式可能造成輸出順序的不同,但是他們都遵循拓撲排序。都是拓撲排序的一種情況。
注意:
- ingress[]:用來存每個頂點的入度
- 圖的存儲結構:鄰接表(不懂可以看我的上一篇隨筆)
獲取各頂點入度的函數:
void FindID(AdjList G, int indegree[MAX_VERTEX_NUM]){
int i;
ArcNode *p;
for(i=0;i<G.vexnum;i++) /*--初始化度數組----*/
indegree[i]=0;
for(i=0;i<G.vexnum;i++){
p=G.vertexes[i].firstarc; //找鄰接點
while(p!=NULL){
indegree[p->adjvex]++;
p=p->nextarc;
}
}
}
入棧方法輸出拓撲排序
bool TopologicalSort(ALGraph G)
{
SeqStack *s;
s = (SeqStack*)malloc(sizeof(SeqStack));
InitStack(s); /*---初始化棧---*/
int count,indegree[G.vexnum]; /*--count:用來計數---*/
ArcNode *p;
FindIndegree(G, indegree); /*---獲取各頂點入度的函數---*/
int j;
for(j = 0;j<G.vexnum;j++)
{
if(indegree[j]==0)
push(s,j); /*--找到一個度為零的入棧----*/
}
count = 0;
while(!IsEmpty(s)) /*---棧非空---*/
{
int i = 0;
Pop(s,&i); /*---度為零的出棧並輸出---*/
printf("%d ",i);
count++;
for( p = G.adjlist[i].firstarc;p;p = p->nextarc)
{ /*---將出棧的頂點尾部的弧’刪除‘(其實是將所尾部連接的頂點的度減一)---*/
indegree[p->adjvex]--;
if(!indegree[p->adjvex]) push(s,p->adjvex);
}
}
if(count == G.vexnum) /*---出棧頂點數目等於圖的頂點數說明圖中無回路,否則有回路---*/
{
return true;
}
return false;
}
入對方法輸出拓撲排序
int TopoSort(AdjList G){
Queue Q; /*隊列存儲入度為0*/
int indegree[MAX_VERTEX_NUM]; //存放每個頂點的入度值
int i,count,k; //count計數,然后和有向圖中頂點總數比較
ArcNode*p;
FindID(G,indegree);
InitStack(&S); //初始化隊列
for(i=0;i<G.vexnum;i++)
if(indegree[i]==0) EnterQueue(&Q,i); //入隊
count=0;
while(!StackEmpty(S)){
DeleteQueue(&Q,&i); //一個入度為0的點出隊
printf("%c",G.vertex[i].data);
count++;
p=G.vertexes[i].firstarc;
while(p!=NULL){
k=p->adjvex;
indegree[k]--;
if(indegree[k]==0) EnterQueue(&S,k);
p=p->nextarc;
}
}
if(count<G.vexnum) return(Error); //有向圖中有回路
else return(Ok);
}
時間復雜度
如果AOV網絡有n個頂點,e條邊,在拓撲排序的過程中,搜索入度為零的頂點所需的時間是O(n)。在正常情況下,每個頂點進一次棧,出一次棧,所需時間O(n)。每個頂點入度減1的運算共執行了e次。所以總的時間復雜為O(n+e)。
oj題目要求:(入棧)拓撲排序