1. 程式人生 > >BFS與DFS兩種視角下的拓撲排序

BFS與DFS兩種視角下的拓撲排序

  拓撲排序一般用來解決求一個有先後關係的排序問題。如果在一連串事件中,有著必要的先後關係或依賴關係,就可以抽象成圖中的拓撲排序。

出度和入度

  拓撲排序需要用到出度和入度的概念。

  出度:以該點為起點的邊的數量

  入度:以該點為終點的邊的數量

  如果把圖中每個結點看作一個事件,邊看作一種依賴關係。那麼一個點的入度就是該點所需的先決條件數量,一個點的出度就是 以該點作為其他點先決條件 的 點的數量。顯然,入度為0的點,就是序列的起始點。

顯然,一個圖可以進行拓撲排序的充要條件是他是一個有向無環圖(DAG)

BFS進行拓撲排序

  bfs下的拓撲排序有兩種思路:

  • 無前驅優先型
  • 無後繼優先型

  無前驅優先型的演算法思路是:先找出圖中入度為0的點(沒有前驅)加入佇列,然後將該點所有的後繼點的入度減一(相當與把加入佇列的點從圖中刪除)。

然後重複這一步驟,直到所有點加入佇列,則完成拓撲排序。

  無後繼優先型的思路與無前驅型相同,不過在佇列中的結點順序的逆序才是它的拓撲排序。

  無法完成拓撲排序(不是DAG)的情況:如果圖中不存在入度(或出度)為0的點,但仍有點未加入佇列,證明它不是一個有向無環圖,沒有拓撲排序。

DFS進行拓撲排序

  dfs天然適合拓撲排序,因為它的訪問過程本身就需要(在一定程度上)按照拓撲排序。

  具體思路就是,先找到一個入度為0的點,對其進行dfs,回溯時的順序就是就是拓撲排序的逆序。

  有以下幾個要注意的點:

  1. 每次訪問的結點必須入度為零
  2. 不能出現回退邊(訪問到一個在前邊的遞迴過程中沒有處理完的點),出現回退邊意味著這個圖不是一個有向無環圖

按最小的字典序輸出拓撲排序

  一個圖的拓撲排序往往不只有一種,所以有時題目要求輸出字典序最小的拓撲排序,這時我們只需要把bfs中的佇列換成優先佇列就好,同時入度為0的點字典序小的先出隊。

  (這時不能用dfs的方法,因為dfs是按層搜尋,無法區分同一層結點的優先順序)

幾道練手水題

  to be continued..