排序是確定某序列的順序,之前我們學過很多的排序,他們基本上是對陣列進行排序,意在把一組元素序列按照某種自定義的順序進行排序(廣義)。它們的特點是,被排序的序列的元素之間存在某種大小關係,這種大小關係我們可以用數學意義上的**「大於」和「小於」來體現。但是如果這種「大小關係」**我們不能用數學邏輯裡的:』>』 和 『
舉個最直觀的例子:我們在安排大學四年的上課順序的時候,每一門課,都有它的先修課和後續繼續深入的課,就像是上**設計之前要學一些程式語言和技巧,例如c/c++/sql,這樣才有利於php和mysql的學習,學**設計之後還要深入學習web系統設計。在這個關係種我們可以建立有向圖,先修課將指向後繼課程!所以大家可以想到,我們的拓撲排序是針對有向圖的,但是光是有向圖其實不夠,還必須是有向無環圖,從抽象的角度去理解,可以這麼認為,如果有環,那那個環中的元素,到底誰先誰後是不清楚的,後面我會用**來告訴大家,其實如果有環,那個環根本無法被處理!
我們不妨以這個為例,我們可以看到,這是乙個有向無環圖!
還是看之前的上課安排的例子,什麼課會第乙個被安排??很明顯,最基礎的課會被先安排,那什麼課是最基礎的呢?就是沒有先修課的課!那這個沒有先修課,就可以理解為當前有向無環圖的點,它的入度為0!在上面這個圖種我們很容易看到,有兩個入度為0的點:v1、v6,演算法步驟如下:
第一步:
度為0的點:v1 v6入佇列;
佇列狀態:v1、v6;
第二步:v1出佇列,v1直接指向的點:v2、v3、v4入佇列
佇列狀態:v6、v2、v3、v4;
第三步:v6出佇列,v6直接指向的點:v5入佇列
佇列狀態:v2、v3、v4、v5;
第四步:v2出佇列,v2直接指向的點:無入佇列
……接下來的步驟自己去模擬就好了,實際上大家可以看得出,這個拓撲排序我使用的是bfs的思想!
#include
#include
using
namespace std;
const
int maxn =
1e4+5;
vector<
int> g[maxn]
;int n, m, u, v, in[maxn]
, q[maxn]
;//陣列模擬佇列
intsort()
while
(l < r)
}// l < r 相當於佇列不空
return r;
// 檢查是否存在環路!
}int
main()
int cnt =
sort()
;if(n == cnt)
else
cout <<
"it is a circle!"
;return0;
}
值得注意的是:我這裡用陣列來模擬佇列操作,然後用鄰接表來存圖。用陣列是因為stl提供的佇列很容易爆(類內開闢空間不是在自由區開闢的,不能開那麼大),其實我這樣寫也還是很容易爆,在競賽種最好還是用迴圈佇列模擬、並且用鏈式前向星來存圖,這裡我只是為了來描述拓撲排序,於是就不搞那麼複雜了!
回顧dfs的特點:沿著一條可行路徑,一直搜素到最底層,然後逐層回溯,這個過程實際上正好反映了點與點之間的先後關係,天然符合拓撲排序!
演算法分析:
在乙個有向無環圖種,如果有乙個點u,它的入度是0,那麼我們就從這個點開始做dfs。dfs返回的順序恰好就是乙個拓撲序!
處理一些細節:
我們應該是以入度為0的點為dfs的開始,那我們該如何找到這個點?如果有很多入度為0的點,我們要乙個個去做dfs嗎?有這麼一種方法可以解決這個問題,我們可以假設乙個虛擬的點,這個點是圖中唯一乙個入度為0的點,圖中其他的所有點都是它的下一層遞迴!然而在實際程式設計的時候是不需要考慮這個點的,我們只需要在main()函式中把每乙個點輪流執行一遍dfs就可以了!這樣做就相當於顯式地遞迴了虛擬假象點的下一層點!
#include
#include
#include
#include
#include
using
namespace std;
const
int maxn =
1e4+5;
vector<
int> g[maxn]
;stack<
int> s;
int n, m, u, v, vis[maxn]
;bool
dfs(
int pos)
vis[pos]=1
;// 表示成功被處理
s.push
(pos)
;return
true;}
bool
sort()
return
true;}
intmain()
if(!sort()
) cout <<
"it has a circle!"
;else
}return0;
}
拓撲排序 kahn演算法及dfs的拓撲排序
有個人的家族很大,輩分關係很混亂,請你幫整理一下這種關係。給出每個人的孩子的資訊。輸出乙個序列,使得每個人的後輩都比那個人後列出 sample input 5 0 4 5 1 0 1 0 5 3 0 3 0樣例輸出 sample output 2 4 5 3 1 因為需輸出字典序最小的因而要使用優先...
拓撲排序的原理與實現
拓撲排序顧名思義是一種排序演算法,它用於給有向圖排序。有向圖是由一組頂點和一組有方向的邊組成的圖,每條有方向的邊都連線著有序的一對頂點,因此a b代表a可以到達b,並不代表b就能到達a。拓撲排序的結果就是乙個有向圖的頂點序列 或稱為拓撲序列 想要學習 c 程式設計 就需要先學習 計算機導論 想要學習...
tarjan演算法與拓撲排序
tarjan演算法要求使有向圖。tarjan就是乙個輔助作用,把有環圖縮為無環圖,也就是將強聯通分量縮成乙個點。對於每乙個節點,我們用dfn i 記錄它的時間戳,用low i 記錄它的回溯值 即不經過流圖搜尋樹上該節點父親能返回的最小的時間戳 dag縮點後的陣列,ins是否在棧中。樹邊 dfs孩子,...