拓撲排序是有向無環圖 (DAG) 頂點的一種線性排序,使得對於任意邊 (u,v),u 總排在 v 之前。它是任務調度、編譯依賴解析、課程先修關係等場景的核心算法,本質是貪婪策略的應用。
(i,j) = 任務 i 必須在任務 j 之前完成「每步從剩餘頂點中選入度為 0 的頂點 (無前驅依賴) 加入序列。」
若某步無入度為 0 的頂點可選,說明圖中存在環,**拓撲序列不存在**。
初始入度:[0,0,1,3,1,3] (1-based)
候選棧:{1,2}
可能序列 (非唯一):2→5→1→3→4→6, 1→2→3→4→5→6, 2→1→5→3→4→6 等。
indeg[v]:頂點 v 當前入度O(n+e)n 即成功,否則有環
#include
#include
struct Network {
int n; // 頂點數 (1..n)
std::vector> adj; // 鄰接表 adj[u] = {v1,v2,...}
Network(int n_) : n(n_), adj(n_ + 1) {}
void addEdge(int u, int v) { adj[u].push_back(v); }
// 拓撲排序,成功返回 true 並將序列存入 topo (0-based 索引)
bool Topological(std::vector &topo) {
topo.clear();
std::vector indeg(n + 1, 0);
// 統計入度
for (int u = 1; u <= n; ++u)
for (int v : adj[u])
++indeg[v];
// 初始零入度頂點入棧
std::stack st;
for (int i = 1; i <= n; ++i)
if (indeg[i] == 0) st.push(i);
// 貪婪構造序列
while (!st.empty()) {
int u = st.top(); st.pop();
topo.push_back(u);
for (int v : adj[u]) {
if (--indeg[v] == 0) st.push(v);
}
}
return topo.size() == n;
}
};
| 圖表示 | 初始化入度 | 主循環 | 總計 |
|---|---|---|---|
| 鄰接矩陣 | O(n²) | O(n²) | O(n²) |
| 鄰接表 | O(n+e) | O(n+e) | O(n+e) |
稀疏圖 (e ≪ n²) 必用鄰接表。
priority_queue (小根堆)拓撲排序是圖論中最實用的算法之一,掌握其貪婪本質、Kahn 算法實現與 O(n+e) 複雜度分析,是解決一切「有依賴順序的調度問題」的鑰匙。