808-topological-sort-dfs — Topological Sort (DFS)
Tutorial Video
Text description (accessibility)
This video demonstrates the "808-topological-sort-dfs — Topological Sort (DFS)" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. Topological sort orders the vertices of a Directed Acyclic Graph (DAG) so that every edge goes from earlier to later in the order. Key difference from OCaml: 1. **Three
Tutorial
The Problem
Topological sort orders the vertices of a Directed Acyclic Graph (DAG) so that every edge goes from earlier to later in the order. It is fundamental to build systems (Makefile, Cargo, Bazel — dependency ordering), task schedulers, course prerequisite ordering, and package managers. The DFS-based algorithm by Tarjan (1976) runs in O(V+E) and also detects cycles (where topological sort is undefined).
🎯 Learning Outcomes
None for cyclic graphs and Some(Vec<usize>) for DAGsCode Example
#![allow(clippy::all)]
//! # Topological Sort (DFS)
pub fn topological_sort(n: usize, edges: &[(usize, usize)]) -> Option<Vec<usize>> {
let mut adj = vec![vec![]; n];
for &(u, v) in edges {
adj[u].push(v);
}
let mut visited = vec![0u8; n];
let mut result = vec![];
fn dfs(v: usize, adj: &[Vec<usize>], vis: &mut [u8], res: &mut Vec<usize>) -> bool {
vis[v] = 1;
for &u in &adj[v] {
if vis[u] == 1 {
return false;
}
if vis[u] == 0 && !dfs(u, adj, vis, res) {
return false;
}
}
vis[v] = 2;
res.push(v);
true
}
for v in 0..n {
if visited[v] == 0 && !dfs(v, &adj, &mut visited, &mut result) {
return None;
}
}
result.reverse();
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_topo() {
let r = topological_sort(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
assert!(r.is_some());
}
}Key Differences
u8 array and OCaml's int array are equivalent.false / None; OCaml can raise an exception (exception Cycle) for a more functional early-exit.OCaml Approach
OCaml implements with color: int array and let rec dfs v = .... The exception Cycle can short-circuit the entire DFS cleanly. OCaml's List.rev reverses the finish order. Ocamlgraph.Topological.fold provides a functional topological traversal. Kahn's algorithm (in-degree + queue) is simpler to implement in OCaml due to its BFS nature.
Full Source
#![allow(clippy::all)]
//! # Topological Sort (DFS)
pub fn topological_sort(n: usize, edges: &[(usize, usize)]) -> Option<Vec<usize>> {
let mut adj = vec![vec![]; n];
for &(u, v) in edges {
adj[u].push(v);
}
let mut visited = vec![0u8; n];
let mut result = vec![];
fn dfs(v: usize, adj: &[Vec<usize>], vis: &mut [u8], res: &mut Vec<usize>) -> bool {
vis[v] = 1;
for &u in &adj[v] {
if vis[u] == 1 {
return false;
}
if vis[u] == 0 && !dfs(u, adj, vis, res) {
return false;
}
}
vis[v] = 2;
res.push(v);
true
}
for v in 0..n {
if visited[v] == 0 && !dfs(v, &adj, &mut visited, &mut result) {
return None;
}
}
result.reverse();
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_topo() {
let r = topological_sort(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
assert!(r.is_some());
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_topo() {
let r = topological_sort(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
assert!(r.is_some());
}
}
Deep Comparison
OCaml vs Rust: Topological Sort Dfs
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.