概念
DAG是指有向無環圖,而拓撲排序是有向無環圖的一個具體應用。拓撲排序是指將DAG圖的頂點排成一個線性的序列。這個線性的序列是滿足一下規則的:如果在DAG圖中存在v->u,那麼在這個序列中v一定是排在u的前面的
思想
拓撲排序在實際生活中有着廣泛的應用。比如排課。如下圖就是一個拓撲排序的例子:
要求按照上圖給出一個合理的排課序列。觀察有向圖的先序關係,我們可以很容易發現比如:
A -> B -> C -> D -> E -> F -> G -> H
就是一個合理的序列。當然,我們發現,如果一個DAG圖中存在沒有直接或是間接關係的先導的頂點的話,這兩個頂點的先後順序是任意的。對於該圖拓撲排序的結果是不唯一的。
那麼,我們如何來實現拓撲排序呢?可以這樣來想:
- 首先定義一個隊列Q,將圖中所有入度爲0的頂點入隊
- 取出隊首的元素,輸出(就會得到排序的元素),然後刪除以該頂點爲起點的邊,並且將連接該頂點的其他頂點的入度減一。若某個頂點的入度減爲0,那麼就將改頂點加入到隊列中。
- 反覆執行(2)操作,知道隊列爲空,如果隊列爲空時如果隊的結點數目恰好爲N,說明拓撲排序成功,否則說明G中存在環。
代碼
vector<int>G[maxn];//存儲圖
int n,m,inDegree[maxn]; //頂點數,邊數,每個頂點的入度
bool toplogicalSort(){
//返回true表示排序成功
int num=0; //記錄入隊頂點數
queue_priority<int,vector<int>,greater<int>> Q; //設置數字小的優先級高
//將入度爲0的頂點全部入隊
for(int i=1; i<=n; i++){
if(inDegree[i]==0){
Q.push(i);
}
}
while(!Q.empty()){
int u = Q.top();
printf("%d ",u); //輸出
Q.pop();
for(int i=0; i<G[u].size(); i++){
int v = G[u][i]; //u的後繼結點
inDegree[v]--;
if(inDegree[v] == 0){
Q.push(v);
}
}
//清空以u爲起點的邊
G[u].clear();
num++;
}
if(num == n)return true;
else return false;
}
應用
拓撲排序的一個重要的應用就是判斷給定的有向圖是否存在環,上面的代碼當返回爲false時就是表明存在環。