概念
拓撲排序是將有向無環圖G的所有頂點排成一個線性序列,使得對圖G的任意兩個頂點u、v,如果存在邊u->v,那麼在序列中u一定在v的前面,這個序列稱爲拓撲序列
步驟
(1)定義一個隊列Q,並把所有入度爲0的結點加入隊列;
(2)取隊首結點,輸出。然後刪去所有從它出發的邊,並令這些邊到達的頂點的入度減1,如果某個頂點的入度減爲0,則將其加入隊列。
(3)反覆進行(2)操作,直到隊列爲空。如果隊列爲空時入過隊的結點數目恰好爲N,說明拓撲排序成功,圖G爲有向無環圖;否則,拓撲排序失敗,圖G中有環。
實例演示
引用自:https://blog.csdn.net/qq_35644234/article/details/60578189utm_source=distribute.pc_relevant.none-task
如果我們有如下的一個有向無環圖,我們需要對這個圖的頂點進行拓撲排序,過程如下:
首先,我們發現V6和v1是沒有前驅的,所以我們就隨機選去一個輸出,我們先輸出V6,刪除和V6有關的邊,得到如下圖結果:
然後,我們繼續尋找沒有前驅的頂點,發現V1沒有前驅,所以輸出V1,刪除和V1有關的邊,得到下圖的結果:
然後,我們又發現V4和V3都是沒有前驅的,那麼我們就隨機選取一個頂點輸出(具體看你實現的算法和圖存儲結構),我們輸出V4,得到如下圖結果:
然後,我們輸出沒有前驅的頂點V3,得到如下結果:
然後,我們分別輸出V5和V2,最後全部頂點輸出完成,該圖的一個拓撲序列爲:
v6–>v1—->v4—>v3—>v5—>v2
實現代碼
vector<int> adj[maxv]; //鄰接表
int n,m,inDegree[maxv]; //頂點數,入度
bool topologicalSort(){
int num=0; //記錄加入拓撲序列的頂點數
queue<int> q;
for(int i=0;i<n;i++){
if(inDegree[i]==0) q.push(i);
}
while(!q.empty()){
int u=q.front();
//printf("%d",u) //可輸出該頂點
q.pop();
for(int i=0;i<adj[u].size();i++){
int v=adj[u][i];
inDegree[v]--;
if(inDegree[v]==0) q.push(v);
}
adj[u].clear(); //清空頂點u的所有出邊(如果沒有必要可以不寫)
num++; //加入拓撲序列的頂點數加1
}
return num==n?true:false;
}
注:如果要求有多個入度爲0的頂點時選擇編號最小的頂點,可以把queue改爲priority_queue,並使用小頂堆。(改爲set也可以)
重要應用
拓撲排序的很重要的應用就是判斷一個給定的圖是否是有向無環圖。