日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构与算法】【算法思想】拓扑排序

發布時間:2023/12/10 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构与算法】【算法思想】拓扑排序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、拓撲排序

拓撲排序是基于依賴關系的節點,根據依賴關系而生成的序列。節點和依賴關系往往要生成有向無環圖。類似的問題有:穿衣服褲子的先后關系,生成穿衣序列/專業課程與前置課程形成的課程學習序列/代碼編譯依賴關系形成的編譯順序序列。

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)

public void topoSortByKahn() {int[] inDegree = new int[v]; // 統計每個頂點的入度for (int i = 0; i < v; ++i) {for (int j = 0; j < adj[i].size(); ++j) {int w = adj[i].get(j); // i->winDegree[w]++;}}LinkedList<Integer> queue = new LinkedList<>();for (int i = 0; i < v; ++i) {if (inDegree[i] == 0) queue.add(i);}while (!queue.isEmpty()) {int i = queue.remove();System.out.print("->" + i);for (int j = 0; j < adj[i].size(); ++j) {int k = adj[i].get(j);inDegree[k]--;if (inDegree[k] == 0) queue.add(k);}} }
0x01 DFS 深度優先搜索算法
  • 深度優先搜索是要一通到底的,所以需要將鄰接表返過來,改成逆鄰接表。方法:遍歷鄰接表,對i的每個鄰接節點j,都將i加到j的逆鄰接表中。
  • 圖的深度優先搜索不跟樹一樣:沒有根節點,所以要嘗試從每個節點都開始一次,自然需要visited數組防止重復。對某個節點深度遍歷完之后,再輸出。
  • 時間復雜度:求入度:O(v+e),頂點兩次 邊一次
    空間復雜度:入度數組O(v),隊列<O(v)
  • public void topoSortByDFS() {// 先構建逆鄰接表,邊s->t表示,s依賴于t,t先于sLinkedList<Integer> inverseAdj[] = new LinkedList[v];for (int i = 0; i < v; ++i) { // 申請空間inverseAdj[i] = new LinkedList<>();}for (int i = 0; i < v; ++i) { // 通過鄰接表生成逆鄰接表for (int j = 0; j < adj[i].size(); ++j) {int w = adj[i].get(j); // i->winverseAdj[w].add(i); // w->i}}boolean[] visited = new boolean[v];for (int i = 0; i < v; ++i) { // 深度優先遍歷圖if (visited[i] == false) {visited[i] = true;dfs(i, inverseAdj, visited);}} }private void dfs(int vertex, LinkedList<Integer> inverseAdj[], boolean[] visited) {for (int i = 0; i < inverseAdj[vertex].size(); ++i) {int w = inverseAdj[vertex].get(i);if (visited[w] == true) continue;visited[w] = true;dfs(w, inverseAdj, visited);} // 先把vertex這個頂點可達的所有頂點都打印出來之后,再打印它自己System.out.print("->" + vertex); }

    顯然用于拓撲排序的圖是不可以成環的。自然拓撲排序算法可以用于檢測圖中的環。對于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算法,有可能會輸出不正確的拓撲次序。

    筆記整理來源: 王爭 數據結構與算法之美

    總結

    以上是生活随笔為你收集整理的【数据结构与算法】【算法思想】拓扑排序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。