BFS與DFS兩種視角下的拓撲排序
阿新 • • 發佈:2020-11-26
拓撲排序一般用來解決求一個有先後關係的排序問題。如果在一連串事件中,有著必要的先後關係或依賴關係,就可以抽象成圖中的拓撲排序。
出度和入度
拓撲排序需要用到出度和入度的概念。
出度:以該點為起點的邊的數量
入度:以該點為終點的邊的數量
如果把圖中每個結點看作一個事件,邊看作一種依賴關係。那麼一個點的入度就是該點所需的先決條件數量,一個點的出度就是 以該點作為其他點先決條件 的 點的數量。顯然,入度為0的點,就是序列的起始點。
顯然,一個圖可以進行拓撲排序的充要條件是他是一個有向無環圖(DAG)
BFS進行拓撲排序
bfs下的拓撲排序有兩種思路:
- 無前驅優先型
- 無後繼優先型
無前驅優先型的演算法思路是:先找出圖中入度為0的點(沒有前驅)加入佇列,然後將該點所有的後繼點的入度減一(相當與把加入佇列的點從圖中刪除)。
然後重複這一步驟,直到所有點加入佇列,則完成拓撲排序。
無後繼優先型的思路與無前驅型相同,不過在佇列中的結點順序的逆序才是它的拓撲排序。
無法完成拓撲排序(不是DAG)的情況:如果圖中不存在入度(或出度)為0的點,但仍有點未加入佇列,證明它不是一個有向無環圖,沒有拓撲排序。
DFS進行拓撲排序
dfs天然適合拓撲排序,因為它的訪問過程本身就需要(在一定程度上)按照拓撲排序。
具體思路就是,先找到一個入度為0的點,對其進行dfs,回溯時的順序就是就是拓撲排序的逆序。
有以下幾個要注意的點:
- 每次訪問的結點必須入度為零
- 不能出現回退邊(訪問到一個在前邊的遞迴過程中沒有處理完的點),出現回退邊意味著這個圖不是一個有向無環圖
按最小的字典序輸出拓撲排序
一個圖的拓撲排序往往不只有一種,所以有時題目要求輸出字典序最小的拓撲排序,這時我們只需要把bfs中的佇列換成優先佇列就好,同時入度為0的點字典序小的先出隊。
(這時不能用dfs的方法,因為dfs是按層搜尋,無法區分同一層結點的優先順序)
幾道練手水題
to be continued..