1. 程式人生 > >資料結構——圖(9)——拓撲排序與DFS

資料結構——圖(9)——拓撲排序與DFS

DAG圖與AOV網

一個無環的有向圖稱為有向無環圖(DAG)。圖的頂點可以表示要執行的任務,並且邊可以表示一個任務必須在另一個之前執行的約束; 在這個應用程式中,拓撲排序只是任務的有效序列。 當且僅當圖形沒有有向迴圈時,即如果它是有向無環圖(DAG),則可以進行拓撲排序。 任何DAG都具有至少一個拓撲排序。這種用弧來表示活動之間的優先順序關係的有向圖,稱為頂點表示的活動的網(簡稱AOV網)

拓撲排序(Topological sorting)

在電腦科學領域,有向圖的拓撲排序或拓撲排序是其頂點的線性排序。在圖中假設從頂點 i 到頂點 j 中有一條有向路徑 i -> j。那麼我們稱 i 為 j 的前驅,稱 j 為 i 的後繼。
拓撲排序的演算法非常簡單,常用的方式為Kahn’s algorithm演算法

。基本步驟為:

  • 在給定的有向圖中,選擇其中一個沒有前驅的頂點放入容器中
  • 從圖中刪除該頂點及其所有的以其為尾的弧。
  • 重複上述兩步,直至全部頂點輸出或者不存在沒有前驅的頂點為止。

該演算法的虛擬碼如下:

L ← 用來存放輸出的節點的列表
S ← 沒有前驅的所有點的集合
while S is non-empty do //當S不為空時
    remove a node n from S //從集合S中移除節點N,
    add n to tail of L //並將節點N放在列表的尾部
    //迴圈遍歷每一個從節點N到節點M的邊e
    for each node m with an edge e from n to m do 
    //j將該邊從圖中移除
        remove edge e from the graph
        //如果移除後節點m沒有以它為入度的邊,便將m插入到集合S中
        if m has no other incoming edges then
            insert m into S
            //否則,圖中必定含有其他方向的邊
if graph has edges then
//於是返回錯誤,表明此時圖中至少含有一個環
    return error   (graph has at least one cycle)
else 
    return L   (a topologically sorted order)
    

下面用一個例項來說明一下拓撲排序的整個流程;

  1. 假定給我們一個有向圖如下圖所示:
    在這裡插入圖片描述
    找出它的拓撲排序。那麼我們可以這樣來。

  2. 先找沒有直接前驅的節點,在這裡V1,v6都沒有直接前驅,那麼任意選擇一個,並刪除所有以其為尾的弧。(假定我們選擇的是v6),那麼此時L的列表中的元素為 L = {v6}
    在這裡插入圖片描述

  3. 重複上述步驟我們可以移除V1,得到L = {v6,v1}.
    在這裡插入圖片描述

  4. 反覆如此,直到所有的頂點都輸出完畢或者不存在沒有前驅的頂點為止。整個流程如下:
    在這裡插入圖片描述

由此我們可以看出拓撲排序的順序並不是唯一的。對於下面這幅圖就可以有多種拓撲順序:
在這裡插入圖片描述

利用DFS實現拓撲排序

當一個有向圖無環的時候,我們可以利用DFS演算法來實現拓撲排序。原理很簡單,由於圖中沒有環,那麼由圖中某點出發的時候,最先退出DFS的頂點一定是出度為0的頂點,也就是拓撲排序中最後的一個頂點(逆向思維)。因此按DFS退出的先後記錄下的頂點序列就是逆向的拓撲排序的序列。
具體的分析就不來了,虛擬碼貼上:

L ← Empty list that will contain the sorted nodes
while there are unmarked nodes do
    select an unmarked node n
    visit(n) 
    //定義這樣的visit函式
 function visit(node n)
    if n has a permanent mark then return
    if n has a temporary mark then stop   (not a DAG)
    mark n temporarily
    for each node m with an edge from n to m do
        visit(m)
    mark n permanently
    add n to head of L

拓撲排序的應用

拓撲排序最常見的應用是基於其依賴性來排程一系列作業或任務。作業由頂點表示,如果在作業y開始之前必須完成作業x,那麼就存在從x到y的邊(例如,洗衣服時,洗衣機必須在我們將衣服放入烘乾機之前完成) 。然後,拓撲排序給出了執行作業的順序。 20世紀60年代早期,在PERT技術專案管理排程的背景下,首次研究了拓撲排序演算法的密切相關應用(Jarnagin 1960);在此應用程式中,圖形的頂點表示專案的里程碑,邊表示必須在一個里程碑與另一個里程碑之間執行的任務。拓撲排序構成了線性時間演算法的基礎,用於查詢專案的關鍵路徑,一系列里程碑和任務,用於控制整個專案進度的長度。

而對於上面4中的第二種情況我們可以知道,這個時候圖中的所有節點肯定是沒能全部輸出來的,因此我們可以得到一個判斷AOV網中是否存在環的判定方法:對於有向圖構造其頂點的拓撲序列,若網中的所有頂點都在該拓撲序列中,那麼該AOV網就不存在環。反之有環。這個結論學過計算機作業系統的人來說並不陌生。一個作業必須在另外一個作業完成之後才能執行,這在作業系統中對應程序間的同步關係。而我們常用前驅圖來表示其關係。而在程序間的關係中往往存在死鎖。而檢測死鎖的方法,就是拓撲排序法。(更多詳細內容去學習《作業系統》課程吧)