之前在https://www.cnblogs.com/wkfvawl/p/9129325.html上已經介紹了拓撲排序,我這里再根據圖論書上的內容對拓撲排序進行一下補充,和進一步的說明。
主要摘自《圖論算法理論、實現及應用》
1.拓撲排序中棧的使用
拓撲排序在實現時,還需建立一個存放入度為 0 的頂點的棧,供選擇和輸出無前驅的頂點。只要出現入度為 0 的頂點,就將它壓入棧中。使用這種棧的拓撲排序算法可以描述如下:
(1) 建立入度為 0 的頂點棧,初始時將所有入度為 0 的頂點依次入棧;
(2) 當入度為 0 的頂點棧不為空時,重復執行
{
從入度為 0 的頂點棧中彈出棧頂頂點,並輸出該頂點;
從 AOV 網絡中刪除該頂點和它發出的每條邊,邊的終點入度減 1;
如果邊的終點入度減至 0,則將該頂點推進入度為 0 的頂點棧;
}
(3) 如果輸出頂點個數少於 AOV 網絡中的頂點個數,則報告網絡中存在有向環。//在有向環中的點不會入棧
那么思考:是否可以采用隊列來存儲入度為 0 的頂點?
其實這是可以的!在算法執行過程中,如果同時存在多個入度為 0 的頂點,則首先選擇刪除哪個頂點不會影響算法的正確性。所以,在拓撲排序算法中,可以使用隊列或棧來存儲入度為 0 的頂點
2.拓撲排序與 BFS 算法的對比分析
與用鄰接表實現 BFS 算法的偽代碼相比,拓撲排序與其有相似之處也有不同之處。
相同點:拓撲排序實質上就是一種廣度優先搜索,在算法執行過程中,通過棧頂頂點訪問它的每個鄰接點,整個算法執行過程中,每個頂點訪問一次且僅一次,每條邊掃描一次且僅一次。
不同點:BFS 算法在掃描每條邊時,如果邊的終點沒有訪問過,則入隊列;而拓撲排序算法在掃描每條邊時,終點的入度要減 1,當減至 0 時才將該終點入棧。
3. 拓撲排序與 BFS 算法棧或隊列的使用
請注意,在BFS 算法中是用隊列來存儲待擴展的頂點,在 拓撲排序算法中是用棧來存儲入度為 0 的頂點。那么,在 BFS 算法中是否可以用棧來存儲待擴展的頂點?在拓撲排序算法中是否可以用隊列來存儲入度為 0 的頂點?隊列和棧的區別在於頂點出隊列(或棧)的順序,隊列是先進先出,棧是后進先出。所以,能否用隊列(或棧)關鍵要看這種順序是否會影響算法的正確性。
BFS 算法:如果用棧存儲待擴展的頂點,如圖所示,其中圖(a)為正確的搜索過程,圖(b)為用棧存儲待擴展頂點時各頂點入棧和出棧的過程。在圖(b)中,依次出棧的頂點是 A→E→D→F→H→I→B→C→G,很明顯,這與 BFS 算法的實現過程和頂點訪問順序大相徑庭。因此,在 BFS算法中不能用棧來存儲待擴展的頂點。
4.拓撲排序的時間復雜度
序在實現拓撲排序過程中,搜索入度為 0 的頂點,建立鏈式棧所需時間為 O(n)。當有向圖中不存在有向環時,每個頂點要進一次棧,出一次棧,每條邊掃描一次且僅一次,其復雜度為 O(m)。所以,總的時間復雜度為 O(n+m)