【數據結構】【圖文】【oj習題】 圖的拓撲排序(鄰接表)


image

拓撲排序:

按照有向圖給出的次序關系,將圖中頂點排成一個線性序列,對於有向圖中沒有限定次序關系的頂點,則可以人為加上任意的次序關系,由此所得頂點的線性序列稱之為拓撲有序序列。顯然對於有回路的有向圖得不到拓撲有序序列,因為有回路的話,頂點的先后次序就不確定了。
例如:例如,下圖,我們可以人為限定次序:A B C D 或 A C B D
image
解釋:該輸出順序特點就是后面的頂點輸出必然后於該頂點的前驅頂點

算法:

  1. 從有向圖中選取一個沒有前驅(沒有在它之前活動)的頂點,輸出之;
  2. 從有向圖中刪去此頂點以及所有以它為尾的弧;
  3. 重復上述兩步,直至圖空,或者圖不空但找不到無前驅的頂點為止。
  4. 沒有被打印輸出的頂點構成回路了。

那么、如何找到一個沒有前驅的頂點呢?

通過解釋看出,沒有前驅的頂點的入度為零。我們每次重復第一個操作就是找到圖中入度為零的點並且輸出。

當然問題來了,如果圖中有多個入度為零的頂點,如何判斷誰先輸出。或者怎么依次輸出它們?

答:這里可以利用棧(隊列),暫時將其入棧(入隊),每次輸出棧頂(隊頭)元素。因為每次都是輸出的入度為零的節點,不同的存儲方式可能造成輸出順序的不同,但是他們都遵循拓撲排序。都是拓撲排序的一種情況。

image

注意:

  • 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題目要求:(入棧)拓撲排序


免責聲明!

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



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