揭開「拓撲排序」的神秘面紗

2020-12-22 AI科技大本營

作者 | 小齊本齊

責編 | Carol

來源 | 碼農田小齊

Topological sort 又稱 Topological order,這個名字有點迷惑性,因為拓撲排序並不是一個純粹的排序算法,它只是針對某一類圖,找到一個可以執行的線性順序。

這個算法聽起來高大上,如今的面試也很愛考,比如當時我在面我司時有整整一輪是基於拓撲排序的設計。

但它其實是一個很好理解的算法,跟著我的思路,讓你再也不會忘記她。

有向無環圖

剛剛我們提到,拓撲排序只是針對特定的一類圖,那麼是針對哪類圖的呢?

答:Directed acyclic graph (DAG),有向無環圖。即:

這個圖的邊必須是有方向的;圖內無環。那麼什麼是方向呢?

比如微信好友就是有向的,你加了他好友他可能把你刪了你卻不知道。。。那這個朋友關係就是單向的。。

什麼是環?環是和方向有關的,從一個點出發能回到自己,這是環。

所以下圖左邊不是環,右邊是。

那麼如果一個圖裡有環,比如右圖,想執行1就要先執行3,想執行3就要先執行2,想執行2就要先執行1,這成了個死循環,無法找到正確的打開方式,所以找不到它的一個拓撲序。

總結:

如果這個圖不是 DAG,那麼它是沒有拓撲序的;如果是 DAG,那麼它至少有一個拓撲序;反之,如果它存在一個拓撲序,那麼這個圖必定是 DGA.所以這是一個充分必要條件。

拓撲排序

那麼這麼一個圖的「拓撲序」是什麼意思呢?

我們借用百度百科[1]的這個課程表來說明。

這裡有 9 門課程,有些課程是有先修課程的要求的,就是你要先學了「最右側這一欄要求的這個課」才能再去選「高階」的課程。

那麼這個例子中拓撲排序的意思就是:就是求解一種可行的順序,能夠讓我把所有課都學了。

那怎麼做呢?

首先我們可以用來描述它,圖的兩個要素是頂點和邊,那麼在這裡:

頂點:每門課 邊:起點的課程是終點的課程的先修課

畫出來長這個樣:

這種圖叫AOV(Activity On Vertex) 網絡,在這種圖裡:

頂點:表示活動; 邊:表示活動間的先後關係

所以一個 AOV 網應該是一個 DAG,即有向無環圖,否則某些活動會無法進行。

那麼所有活動可以排成一個可行線性序列,這個序列就是拓撲序列。

那麼這個序列的實際意義是:

按照這個順序,在每個項目開始時,能夠保證它的前驅活動都已完成,從而使整個工程順利進行。

回到我們這個例子中:

我們一眼可以看出來要先學 C1, C2,因為這兩門課沒有任何要求嘛,大一的時候就學唄;大二就可以學第二行的 C3, C5, C8 了,因為這三門課的先修課程就是 C1, C2,我們都學完了;大三可以學第三行的 C4, C9;最後一年選剩下的 C6, C7。這樣,我們就把所有課程學完了,也就得到了這個圖的一個拓撲排序

注意,有時候拓撲序並不是唯一的,比如在這個例子中,先學 C1 再學 C2,和先 C2 後 C1 都行,都是這個圖的正確的拓撲序,但這是兩個順序了。

所以面試的時候要問下面試官,是要求解任意解,還是列出所有解。

我們總結一下,

在這個圖裡的表示的是一種依賴關係,如果要修下一門課,就要先把前一門課修了。

這和打遊戲裡一樣一樣的嘛,要拿到一個道具,就要先做 A 任務,再完成 B 任務,最終終於能到達目的地了。

算法詳解

在上面的圖裡,大家很容易就看出來了它的拓撲序,但當工程越來越龐大時,依賴關係也會變得錯綜複雜,那就需要用一種系統性的方式方法來求解了。

那麼我們回想一下剛剛自己找拓撲序的過程,為什麼我們先看上了 C1, C2?

因為它們沒有依賴別人啊,也就是它的入度為 0.

入度:頂點的入度是指「指向該頂點的邊」的數量;出度:頂點的出度是指該頂點指向其他點的邊的數量。

所以我們先執行入度為 0 的那些點,

那也就是要記錄每個頂點的入度。

因為只有當它的入度為 0的時候,我們才能執行它。

在剛才的例子裡,最開始 C1, C2 的入度就是 0,所以我們可以先執行這兩個。

那在這個算法裡第一步就是得到每個頂點的入度。

Step0: 預處理得到每個點的入度

我們可以用一個 HashMap 來存放這個信息,或者用一個數組會更精巧。

在文中為了方便展示,我就用表格了:

Step1

拿到了這個之後,就可以執行入度為 0 的這些點了,也就是 C1, C2.

那我們把可以被執行的這些點,放入一個待執行的容器裡,這樣之後我們一個個的從這個容器裡取頂點就好了。

至於這個容器究竟選哪種數據結構,這取決於我們需要做哪些操作,再看哪種數據結構可以為之服務。

那麼首先可以把[C1, C2]放入容器中,

然後想想我們需要哪些操作吧!

我們最常做的操作無非就是把點放進來,把點拿出去執行了,也就是需要一個offer 和poll操作比較高效的數據結構,那麼 queue 就夠用了。

(其他的也行,放進來這個容器裡的頂點的地位都是一樣的,都是可以執行的,和進來的順序無關,但何必非得給自己找麻煩呢?一個常規順序的簡簡單單的 queue 就夠用了。)

然後就需要把某些點拿出去執行了。

【劃重點】當我們把 C1 拿出來執行,那這意味這什麼?

答:意味著「以 C1 為頂點」的「指向其他點」的「邊」都消失了,也就是 C1 的出度變成了 0.

如下圖,也就是這兩條邊可以消失了。

那麼此時我們就可以更新 C1 所指向的那些點也就是 C3 和 C8 的 入度 了,更新後的數組如下:

那我們這裡看到很關鍵的一步,C8 的入度變成了 0!

也就意味著 C8 此時沒有了任何依賴,可以放到我們的 queue 裡等待執行了。

此時我們的 queue 裡就是:[C2, C8].

Step2

下一個我們再執行 C2,

那麼 C2 所指向的 C3, C5 的 入度-1,

更新表格:

也就是 C3 和 C5 都沒有了任何束縛,可以放進 queue 裡執行了。

queue 此時變成:[C8, C3, C5]

Step3

那麼下一步我們執行 C8,

相應的 C8 所指的 C9 的入度-1.更新表格:

那麼 C9 沒有了任何要求,可以放進 queue 裡執行了。

queue 此時變成:[C3, C5, C9]

Step4

接下來執行 C3,

相應的 C3 所指的 C4 的入度-1.更新表格:

但是 C4 的入度並沒有變成 0,所以這一步沒有任何點可以加入 queue。

queue 此時變成 [C5, C9]

Step5

再執行 C5,

那麼 C5 所指的 C4 和 C6 的入度- 1.更新表格:

這裡 C4 的依賴全都消失啦,那麼可以把 C4 放進 queue 裡了:

queue = [C9, C4]

Step6

然後執行 C9,

那麼 C9 所指的 C7 的入度- 1.

這裡 C7 的入度並不為 0,還不能加入 queue,

此時 queue = [C4]

Step7

接著執行 C4,

所以 C4 所指向的 C6 和 C7 的入度-1,更新表格:

C6 和 C7 的入度都變成 0 啦!!把它們放入 queue,繼續執行到直到 queue 為空即可。

總結

好了,那我們梳理一下這個算法:

數據結構這裡我們的入度表格可以用 map 來存放

Map: <key = Vertex, value = 入度>

但實際代碼中,我們用一個 int array 來存儲也就夠了,數組的 index 表示每個頂點,數組裡的數值來表示每個頂點的入度,這樣比 Map 更精巧。

然後用了一個普通的 queue,用來存放可以被執行的那些 node.

過程

我們把入度為 0 的那些頂點放入 queue 中,然後通過每次執行 queue 中的頂點,就可以讓依賴這個被執行的頂點的那些點的 入度-1,如果有頂點的入度變成了 0,就可以放入 queue 了,直到 queue 為空。

細節

這裡有幾點實現上的細節:

當我們 check 是否有新的頂點的 入度 == 0 時,沒必要過一遍整個 map 或者數組,只需要 check 剛剛改動過的就好了。

另一個是如果題目沒有給這個圖是 DAG 的條件的話,那麼有可能是不存在可行解的,那怎麼判斷呢?很簡單的一個方法就是比較一下最後結果中的頂點的個數和圖中所有頂點的個數是否相等,或者加個計數器,如果不相等,說明就不存在有效解。所以這個算法也可以用來判斷一個圖是不是有向無環圖。

很多題目給的條件可能是給這個圖的 edge list,也是表示圖的一種常用的方式。那麼給的這個 list 就是表示圖中的邊。這裡要注意審題哦,看清楚是誰 depends on 誰。其實圖的題一般都不會直接給你這個圖,而是給一個場景,需要你把它變回一個圖。

時間複雜度

注意:對於圖的時間複雜度分析一定是兩個參數,因為圖的頂點數和邊的數量沒有固定的關係,然而面試的時候很多同學張口就是 O(n)...

對於有 v 個頂點和 e 條邊的圖來說,

第一步,預處理得到 map 或者 array,需要過一遍所有的邊才行,所以是 O(e);

第二步,把 入度 == 0 的點入隊出隊的操作是 O(v),如果是一個 DAG,那所有的點都需要入隊出隊一次;

第三步,每次執行一個頂點的時候,要把它指向的那條邊消除了,這個總共執行 e 次;

總:O(v + e)

空間複雜度

用了一個數組來存所有點的 indegree,之後的 queue 也是最多把所有的點放進去,所以是 O(v).

代碼

關於這課程排序的問題,Leetcode 上有兩道題,一道是 207,問你能否完成所有課程,也就是問拓撲排序是否存在;另一道是 210 題,是讓你返回任意一個拓撲順序,如果不能完成,那就返回一個空 array。

這裡我們以 210 這道題來寫,更完整也更常考一些。

這裡給的 input 就是我們剛剛說到的 edge list.

Example 1.

Input: 2, [[1,0]]

Output: [0,1]

Explanation: 這裡一共2門課,1的先修課程是0. 所以正確的選課順序是[0, 1].

Example 2.

Input: 4, [[1,0],[2,0],[3,1],[3,2]]

Output: [0,1,2,3] or [0,2,1,3]

Explanation: 這裡這個例子畫出來如下圖

Example 3.

Input: 2, [[1,0],[0,1]]

Output:

Explanation: 這課沒法上了

class Solution {

public int findOrder(int numCourses, int[][] prerequisites) {

int res = new int[numCourses];

int indegree = new int[numCourses];

// get the indegree for each course

for(int[] pre : prerequisites) {

indegree[pre[0]] ++;

}

// put courses with indegree == 0 to queue

Queue<Integer> queue = new ArrayDeque<>;

for(int i = 0; i < numCourses; i++) {

if(indegree[i] == 0) {

queue.offer(i);

}

}

// execute the course

int i = 0;

while(!queue.isEmpty) {

Integer curr = queue.poll;

res[i++] = curr;

// remove the pre = curr

for(int[] pre : prerequisites) {

if(pre[1] == curr) {

indegree[pre[0]] --;

if(indegree[pre[0]] == 0) {

queue.offer(pre[0]);

}

}

}

}

return i == numCourses ? res : new int{};

}

}

還是附上題目吧,just in case, if you want to see the details.

另外,拓撲排序還可以用 DFS - 深度優先搜索 來實現,限於篇幅就不在這裡展開了,大家可以參考GeeksforGeeks[2]的這個資料。

實際應用

我們上文已經提到了它的一個 use case,就是選課系統,這也是最常考的題目。

而拓撲排序最重要的應用就是關鍵路徑問題,這個問題對應的是 AOE (Activity on Edge) 網絡。

AOE 網絡:頂點表示事件,邊表示活動,邊上的權重來表示活動所需要的時間。AOV 網絡:頂點表示活動,邊表示活動之間的依賴關係。

在 AOE 網中,從起點到終點具有最大長度的路徑稱為關鍵路徑,在關鍵路徑上的活動稱為關鍵活動。AOE 網絡一般用來分析一個大項目的工序,分析至少需要花多少時間完成,以及每個活動能有多少機動時間。

具體是怎麼應用分析的,大家可以參考這個視頻[3] 的14分46秒,這個例子還是講的很好的。

其實對於任何一個任務之間有依賴關係的圖,都是適用的。

比如 pom 依賴引入 jar 包時,大家有沒有想過它是怎麼導進來一些你並沒有直接引入的 jar 包的?比如你並沒有引入 aop 的 jar 包,但它自動出現了,這就是因為你導入的一些包是依賴於 aop 這個 jar 包的,那麼 maven 就自動幫你導入了。

其他的實際應用,知乎上專門有個帖子[4],在這裡我總結一下:

語音識別系統的預處理;管理目標文件之間的依賴關係,就像我剛剛說的 jar 包導入;深度學習中的網絡結構處理。

如有其他補充,歡迎大家在評論區不吝賜教。

以上就是本文的全部內容了,拓撲排序是非常重要也是非常愛考的一類算法,面試大廠前一定要熟練掌握。

今日福利

遇見大咖

由 CSDN 全新專為技術人打造的高端對話欄目《大咖來了》來啦!

CSDN 創始人&董事長、極客幫創投創始合伙人蔣濤攜手京東集團技術副總裁、IEEE Fellow、京東人工智慧研究院常務副院長、深度學習及語音和語言實驗室負責人何曉冬,來也科技 CTO 胡一川,共話中國 AI 應用元年來了,開發者及企業的路徑及發展方向!

相關焦點

  • 雲計算開發實例:Python3 拓撲排序
    對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前。
  • 《刺客信條》中文故事導覽 揭開聖殿騎士的神秘面紗
    《刺客信條》中文故事導覽 揭開聖殿騎士的神秘面紗視頻欣賞:在本次的故事導覽視頻中,《刺客信條》系列的敘事導演Darby McDevitt向玩家揭秘精於操控且神秘莫測的聖殿騎士,一個視秩序和權力高於一切的神秘組織。視頻畫面:
  • 那些蒙面的古裝美女揭開面紗時,哪一個驚豔了你?兩個周芷若比美
    古裝劇裡有不少蒙面美女,她們輕紗遮面,給人以唯美朦朧之感,揭開面紗露出真顏時,大多是驚豔了觀眾。你都記得哪些蒙面的古裝美女?她們揭開面紗時,你被誰驚豔到了?小編整理了以下十位揭開面紗的蒙面美女:雪文曦(鞠婧禕 飾):出自《漂亮書生》她冰雪聰明,秀外慧中,能在清秀溫婉的小家碧玉與儒雅俊俏的學堂書生間切換自如。一襲白衣勝雪,清麗脫俗,揭開面紗時那一瞬間驚為天人,宛若仙女下凡,仙氣飄飄,氣質出塵。
  • 《執念師2》第21集 執念師聯盟揭開神秘面紗
    執念師聯盟揭開神秘面紗   搜狐娛樂訊 由肖順堯、禹童、艾曉琪、梁大維等主演的中國首部科幻網絡周播劇《執念師》第二季5月20日起每周五、周六在搜狐視頻上線。本周我們迎來新故事《天演》。 http://yule.sohu.com/20160623/n455993025.shtml yule.sohu.com true 搜狐娛樂 http://yule.sohu.com/20160623/n455993025.shtml report 878 執念師聯盟揭開神秘面紗
  • 揭開南部沙漠的神秘面紗《黑色沙漠 MOBILE》瓦倫西亞新地區「新月神殿」開放
    韓國遊戲開發商珍艾碧絲(Pearl Abyss)旗下 MMORPG 手機遊戲《黑色沙漠 MOBILE》,於今(31)日進行瓦倫西亞南部地區的內容更新,揭開南部沙漠的真面貌
  • 月塵測量儀:揭開月亮女神的神秘面紗
    原標題:月塵測量儀:揭開月亮女神的神秘面紗   12月15日下午16時15分,由中國航天科技集團公司所屬中國空間技術研究院510所研製的嫦娥三號月塵測量儀首次開機進行月面環境月塵量測量。這些顆粒一方面像麵粉一樣細小,一方面又像鋼珠一樣堅硬耐磨,它們很容易在自然或人為的因素作用下,被擾動而懸浮在月球表面,就像一層薄薄的面紗,為月球探測器順利工作設置下第一道障礙。
  • 全球購騎士卡全面解析,揭開神秘「面紗」
    這麼看來,全球購騎士卡對於用戶來說,它的價值就是在於「優惠」,但全球購騎士卡的價值僅僅只有優惠嗎?其實並不是,下面來揭開優惠背後的「面紗」吧!
  • 《錦衣衛》:揭開明代錦衣衛的神秘面紗
    通過對上述問題的回答,《錦衣衛》這本書將為您揭開明代錦衣衛的神秘面紗。著者簡介易強,歷史作家,自由撰稿人,畢業於中國人民大學新聞系。致力於中西方歷史研究,著有《蒙古帝國》《晚清殘錄》等作品。
  • 徵服原子—揭開原子的神秘面紗
    徵服原子-揭開原子的神秘面紗偉大的科學家費曼說:「假如只允許把人類的科學史壓縮成一句話,它就會是——一切東西都是由原子構成」。人類在探索物質是由什麼構成的歷史長河中,充滿了智慧。
  • 獨家揭開落腳地君哥的神秘面紗
    大連海島遊一直流傳著一個傳說,落腳的君哥,今天就為大家獨家揭開落腳地君哥的神秘面紗。獨家揭開落腳地君哥的神秘面紗
  • 揭開《你莫走》歌曲走紅的神秘面紗
    今天,湘江觀事就幫您一一揭開《你莫走》歌曲走紅的神秘面紗。第一層神秘面紗:這首歌第一次在藝術上最真實地表達了一個被社會忽略而又十分顯著的時代特徵。改革開放以來,大批農村青年湧入城市,尤其是年輕女性,在那些偏遠的農村已所剩無幾,剩下一批沒條件、沒膽量去闖蕩城市的男青年。
  • 金義東市域軌道首列車揭開神秘面紗
    婺劇臉譜車頭彰顯金華元素| 金義東市域軌道首列車揭開神秘面紗 婺劇臉譜車頭彰顯金華元素|
  • 《夢回西遊》神秘裝備—全屬性魔靈珠揭開神秘面紗!
    除了能夠隨人物等級提升而提高戰力的傳世套裝之外,還有主加生命的長生鎖、代表競技榮譽的榮譽勳章、冠軍勳章,戀人獨有的蝶戀戒指……然而,還有兩個沒有空缺的裝備欄久久不見公布,神秘的裝備吸引玩家高度關注,一直猜測這兩個裝備會是如何的強力!《夢回西遊》角色裝備欄,為最強裝備而保留的兩個空位一直讓玩家心癢不已。
  • 揭開「散爆新品」神秘面紗 今冬育碧或成最大贏家
    揭開「散爆新品」神秘面紗 今冬育碧或成最大贏家 來源:www.18183.com作者:曉鏑時間:2020-05-17 分享到:
  • 洋河股份夢之藍水晶版揭開神秘面紗
    原標題:洋河股份夢之藍水晶版揭開神秘面紗2009年高端白酒業界標杆洋河股份發布夢之藍系列產品。經十一年的時間夢之藍系列以時尚優雅的外形外俘獲千萬粉絲,更是以其晶亮明澈的酒液,獨到醇厚的酒香久久留於消費者的唇齒之間,深深刻畫於消費者的心間上。而今,備受關注的明星產品夢之藍水晶版神秘面紗的揭開更是引起了廣大消費者的注意與傳播,夢之藍水晶版到底有什麼獨特的魅力呢?
  • 《幻靈之歌 Soul of Phantasm》合作角色「終端少女」技能搶先曝光...
    作者:曉鏑時間:2020-10-02 分享到: 奇幻RPG手遊《幻靈之歌 Soul of Phantasm》於今(30)日公開最新遊戲世界觀和多名幻靈角色介紹,提前揭開幻想世界的神秘面紗
  • 恆馳1路跑及內飾曝光 恆大汽車研發團隊揭開神秘面紗
    恆馳1路跑及內飾曝光 恆大汽車研發團隊揭開神秘面紗金羊網  作者:莫曉航  2020-12-09 隨著恆馳1路跑曝光,其背後的恆大汽車研發團隊也逐漸揭開神秘的面紗。
  • 科學家發現化石,神秘面紗終於揭開!
    科學家發現化石,神秘面紗終於揭開!自恐龍徹底滅絕之後,地球的中生代也結束了,並開啟全新的新生代,當時的地質時代主要分為三個紀,分別是古近紀、新近紀和第四紀,等到了第4紀的時候,哺乳動物便成為地球上的支配者,其中就包含一種飛行動物,那就是蝙蝠。很多人對蝙蝠的了解都比較局限,認為它是一種黑黝黝的飛行動物,沒有什麼美觀可言。
  • iKON新專主打曲《Dive》揭開神秘面紗
    iKON迷你3輯《i DECIDE》主打歌揭開了神秘面紗!YG娛樂30日上午9時通過官方網站上發布了iKON新專主打曲《Dive》宣傳海報。海報中以象徵著iKON的紅色天空為背景,6名成員在空蕩蕩的橋上全力奔跑著,在紅色和黑色鮮明對比下僅通過輪廓就給人強烈的印象和可塑性,壓倒觀眾視線。
  • 瀋陽萬象城「文藝復興三傑藝術展」帶你重回...
    化身「文藝三傑」致敬大師經典,揭開「文藝復興迷案」,瀋陽萬象城「文藝復興三傑藝術展」,開啟時間機器,直奔鎏金之境。重返文藝復興「達文西、米開朗基羅、拉裴爾」文藝復興三傑代表作首次國內集結展出,在文藝巨匠雄渾凝重的筆觸裡,領略長達500多年厚重的歷史意蘊,赴一場恢弘的漫步時空之旅.站在穿越時空的審視視角