拓撲排序
有先後依賴的工作要排出一個合法順序:每次挑一個沒有前置條件的出來做。圖裡有環就排不出來,而這正好能用來偵測循環依賴。
課程規劃
1/20
剛排入可以上:先修課都排完了已排入(數字是順序)還在等/卡在環上
可以上的佇列
- 程式設計
- 離散數學
- 線性代數
目前的順序
(還沒有)先數每門課有幾門先修課(小圓圈裡的數字)。沒有先修課的可以先上:程式設計、離散數學、線性代數。
已排
0 / 9
卡在環上
–
取出+減一的次數
18
亮起來的是這一步執行的程式碼
function topologicalSort(n: number, edges: [number, number][]): number[] | null { const out: number[][] = Array.from({ length: n }, () => []); const indegree = new Array(n).fill(0); for (const [u, v] of edges) { out[u].push(v); indegree[v]++; } for (const list of out) list.sort((a, b) => a - b); const queue: number[] = []; for (let v = 0; v < n; v++) { if (indegree[v] === 0) queue.push(v); } const order: number[] = []; for (let head = 0; head < queue.length; head++) { const u = queue[head]; order.push(u); for (const v of out[u]) { indegree[v]--; if (indegree[v] === 0) queue.push(v); } } return order.length === n ? order : null;}模型假設與範圍
- Big O 與實測步數以頁面列出的基本操作為單位;視覺化的快照、畫圖、程式高亮和輸出成本另計,不是執行時間 benchmark。
什麼時候用
- 一堆工作之間有「A 要在 B 之前」的關係,要排出一個做得完的順序:建置步驟、課程先修、資料管線、試算表的公式重算。
- 要檢查有沒有循環依賴:排不完,就代表有環。
- 想知道哪些工作可以同時做:同一輪一起變成「可以做」的,彼此沒有依賴。
和其他主題的關係
- 延伸閱讀
- BFS 與 DFS
時間與空間複雜度(Big O)
| 操作 | 平均 | 最差 |
|---|---|---|
| Kahn 拓撲排序 每個點進出佇列一次,每條邊減一次 | O(V + E) | O(V + E) |
| 順便偵測環 排完時還有點沒排到,就有環 | O(V + E) | O(V + E) |
| 每輪重新掃找可做的工作 | O(V² + E) | O(V² + E) |
空間:O(V + E),每個點的出邊清單與剩餘前置數
Big O 實測:n 變大時步數怎麼長
數的是:取出+減一的次數(n 個工作、每個約 3 個前置的隨機依賴圖)
| Big O | n = 500 | n = 5,000 | n = 50,000 | 成長倍數:實測(理論) | |
|---|---|---|---|---|---|
| Kahn | O(n) | 1,997 | 19,997 | 199,997 | ×100 (×100) |
和其他做法比
| 邊數 | Kahn:佇列 | 每輪重新掃一遍 | |
|---|---|---|---|
| 100 個工作 | 297 | 397 | 5,347 |
| 1,000 個工作 | 2,997 | 3,997 | 503,497 |
| 3,000 個工作 | 8,997 | 11,997 | 4,510,497 |
同一張隨機依賴圖(每個工作平均 3 個前置),數的是「看了幾個工作+減了幾次」。不用佇列、每輪都從頭找一個沒有前置的工作,成本隨工作數平方成長;Kahn 把「剛好歸零的」直接排進佇列,就不用再找。
真實世界裡的它
- make、Bazel、Gradle 決定先編譯哪個模組。
- npm、pip、apt 安裝套件時的依賴順序,以及「循環依賴」錯誤訊息。
- Airflow、dbt 這類資料管線工具把工作畫成 DAG(Directed Acyclic Graph,有向無環圖)來排程。
- 試算表改一格之後,依照公式的參照關係決定重算順序。
取捨與陷阱
- 合法的順序通常不只一個:同時可以做的工作誰先誰後都對,別把某一個順序當成唯一答案。
- 邊的方向要定清楚:「A → B」是 A 要先做,還是 A 依賴 B?反了,整個順序就倒過來。
- 只有有向無環圖(DAG)排得出來;遇到環時要回報是哪些工作卡住,不要默默輸出一個不完整的順序。