【数据结构与算法】【算法思想】拓扑排序
一、拓撲排序
拓撲排序是基于依賴關系的節點,根據依賴關系而生成的序列。節點和依賴關系往往要生成有向無環圖。類似的問題有:穿衣服褲子的先后關系,生成穿衣序列/專業課程與前置課程形成的課程學習序列/代碼編譯依賴關系形成的編譯順序序列。
public class Graph {private int v; // 頂點的個數private LinkedList<Integer> adj[]; // 鄰接表public Graph(int v) {this.v = v;adj = new LinkedList[v];for (int i=0; i<v; ++i) {adj[i] = new LinkedList<>();}}public void addEdge(int s, int t) { // s先于t,邊s->tadj[s].add(t);} }二、實現
0x00Kahn 算法
根據鄰接表,很容易計算出每個節點的入度。
遍歷每個入度,將入度為0的節點,放入隊列。
隊列不空,循環:
取出隊首元素,輸出他,然后遍歷他的鄰接節點,將鄰接節點入度-1,如果鄰接節點恰好為0,將節點放入隊列。
時間復雜度:求入度:O(v+e),循環輸出O(v+e)合起來O(v+e)
空間復雜度:入度數組O(v),隊列<O(v)
0x01 DFS 深度優先搜索算法
空間復雜度:入度數組O(v),隊列<O(v)
顯然用于拓撲排序的圖是不可以成環的。自然拓撲排序算法可以用于檢測圖中的環。對于kahn算法,極端化思維:如果所有的節點形成大環,那么沒有入度為0的節點,也就不會有任何輸出。普通思維:如果存在環,總會到一個位置,沒有任何節點入度為0。就會少輸出節點。如果輸出的節點<總結點,意味著存在環。
三、思考題
[1]在今天的講解中,我們用圖表示依賴關系的時候,如果 a 先于 b 執行,我們就畫一條從 a 到 b 的有向邊;反過來,如果 a 先于 b,我們畫一條從 b 到 a 的有向邊,表示 b 依賴 a,那今天講的 Kahn 算法和 DFS 算法還能否正確工作呢?如果不能,應該如何改造一下呢?
1.如果有向邊反向,代表依賴關系,則Kahn算法無法工作,改造方法是:1.1把對入度的計算改為對出度的計算,即首先輸出出度為0的節點,然后依次把與該節點相鄰的節點的出度都減1,重復此過程直到輸出所有節點;1.2 改成逆連接表,計算入度;而DFS算法中,則會輸出相反的結果,由于鄰接表和逆鄰接表正好是相反的,因此改造方法是:在DFS中,把對逆鄰接表的的訪問改為對鄰接表的訪問即可。
[2]我們今天講了兩種拓撲排序算法的實現思路,Kahn 算法和 DFS 深度優先搜索算法,如果換做 BFS 廣度優先搜索算法,還可以實現嗎?
2.采用BFS算法,無法保證在某個結點輸出之前,先輸出其所有依賴的節點,因為有可能該節點和其所依賴的某個節點,可能在BFS算法中處于同一個層次,因為這兩個節點可能都和某個節點相鄰,因此,采用BFS算法,有可能會輸出不正確的拓撲次序。
筆記整理來源: 王爭 數據結構與算法之美
總結
以上是生活随笔為你收集整理的【数据结构与算法】【算法思想】拓扑排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php支付接口要改动的参数,京东支付接口
- 下一篇: Maven中使用本地JAR包