1.定義
對一個有向無環圖(Directed Acyclic Graph簡稱DAG) G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序。
在AOV網中,若不存在回路,則所有活動可排列成一個線性序列,使得每個活動的所有前驅活動都排在該活動的前面,我們把此序列叫做拓撲序列(Topological order),由AOV網構造拓撲序列的過程叫做拓撲排序(Topological sort)。AOV網的拓撲序列不是唯一的,滿足上述定義的任一線性序列都稱作它的拓撲序列。
2.拓撲排序的實現步驟
在有向圖中選一個沒有前驅的頂點並且輸出。
從圖中刪除該頂點和所有以它為尾的弧(白話就是:刪除所有和它有關的邊)。
重復上述兩步,直至所有頂點輸出,或者當前圖中不存在無前驅的頂點為止,后者代表我們的有向圖是有環的,因此,也可以通過拓撲排序來判斷一個圖是否有環。
3.拓撲排序實例手動實現
如果我們有如下的一個有向無環圖,我們需要對這個圖的頂點進行拓撲排序,過程如下:
首先,我們發現V6和v1是沒有前驅的,所以我們就隨機選去一個輸出,我們先輸出V6,刪除和V6有關的邊,得到如下圖結果:
然后,我們繼續尋找沒有前驅的頂點,發現V1沒有前驅,所以輸出V1,刪除和V1有關的邊,得到下圖的結果:
然后,我們又發現V4和V3都是沒有前驅的,那么我們就隨機選取一個頂點輸出(具體看你實現的算法和圖存儲結構),我們輸出V4,得到如下圖結果:
然后,我們輸出沒有前驅的頂點V3,得到如下結果:
然后,我們分別輸出V5和V2,最后全部頂點輸出完成,該圖的一個拓撲序列為:
v6–>v1—->v4—>v3—>v5—>v2
過程簡述:
從 DAG 圖中選擇一個 沒有前驅(即入度為0)的頂點並輸出。
從圖中刪除該頂點和所有以它為起點的有向邊。
重復 1 和 2 直到當前的 DAG 圖為空或當前圖中不存在無前驅的頂點為止。若當前圖中不存在無前驅的頂點說明有向圖中必存在環。
4.拓撲排序Java實現
(1) 示例
現在你總共有 n 門課需要選,記為 0 到 n-1。
在選修某些課程之前需要一些先修課程。 例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,判斷是否可能完成所有課程的學習?
示例 1:
輸入: 2, [[1,0]]
輸出: true
解釋: 總共有 2 門課程。學習課程 1 之前,你需要完成課程 0。所以這是可能的。
示例 2:
輸入: 2, [[1,0],[0,1]]
輸出: false
解釋: 總共有 2 門課程。學習課程 1 之前,你需要先完成課程 0;並且學習課程 0 之前,你還應先完成課程 1。這是不可能的。
說明:
輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請參見圖的表示法。
你可以假定輸入的先決條件中沒有重復的邊。
(2) 截圖步驟:
本題思路:采用拓撲排序+廣度優先搜索的方式進行求解。
步驟一:對所有節點建立一個入度表times,times[i]表示第i個節點有多少個入度,(這里入度的意思是當實現此節點時,需要多少個前驅節點的支持)。
步驟二:將入度表中入度為0的節點添加到隊列que中。
步驟三:取出隊列第一個元素temp;並將times中,以該節點作為前驅節點的入度減一,並判斷入度是否等於0,如果等於0加入到隊列中。
步驟四:重復步驟三,知道隊列為空,判斷times中是否存在非0的節點,如果存在則說明有環,不存在說明無環。(其中隊列每次輸出的值就是拓排序的輸出值)
(3) Java代碼:
class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { int []times=new int[numCourses]; for(int i=0;i<prerequisites.length;i++) { int num=prerequisites[i][0]; times[num]=times[num]+1; } Queue<Integer> que=new LinkedList<Integer>(); for(int j=0;j<times.length;j++) { if(times[j]==0) { que.add(j); } } while(!que.isEmpty()) { int temp=que.poll(); for(int m=0;m<prerequisites.length;m++) { if(prerequisites[m][1]==temp) { times[prerequisites[m][0]]--; if(times[prerequisites[m][0]]==0) { que.add(prerequisites[m][0]); } } } } for(int e=0;e<times.length;e++) { if(times[e]!=0) { return false; } } return true; } }