Kahn’s Algorithm is an algorithm that finds a topological sort for a directed acyclic graph in time and space.
Algorithm 0
Lemma
Let denote the in-degree of , then
Proof
If , let be a vertex such that there exists an edge directed from to .
Let be a sequence of vertices in such that
Then applying the Pigeonhole Principle yields
Therefore, is a cycle in .
By contradiction, it follows that .
-
Let be a vertex in .
-
Find a topological sort of recursively.
-
is a topological sort of .
This algorithm solves the problem in time and space.
std::vector<int> kahn(int n, int m, const std::vector<int> &u, const std::vector<int> &v) {
std::vector<std::vector<int>> adj(n);
std::vector deg(n, 0);
for (int i = 0; i < m; i++) {
adj[u[i]].push_back(v[i]);
deg[v[i]]++;
}
std::vector<int> s(n), o;
std::iota(s.begin(), s.end(), 0);
while (!s.empty()) {
int u = std::ranges::min(s, std::less(), [&](int u) -> int {
return deg[u];
});
std::erase(s, u);
o.push_back(u);
for (int v : adj[u]) {
deg[v]--;
}
}
return o;
}Algorithm 1
Based on Algorithm 0, maintaining yields an algorithm that solves the problem in time and space.
std::vector<int> kahn(int n, int m, const std::vector<int> &u, const std::vector<int> &v) {
std::vector<std::vector<int>> adj(n);
std::vector deg(n, 0);
for (int i = 0; i < m; i++) {
adj[u[i]].push_back(v[i]);
deg[v[i]]++;
}
std::queue<int> q;
for (int i = 0; i < n; i++) {
if (!deg[i]) {
q.push(i);
}
}
std::vector<int> o;
while (!q.empty()) {
int u = q.front();
q.pop();
o.push_back(u);
for (int v : adj[u]) {
if (!--deg[v]) {
q.push(v);
}
}
}
return o;
}