Technopedia

The technologist’s encyclopedia

Graphs

Graphs model arbitrary connectivity between entities: social networks, road maps, dependency graphs, circuits. They are relevant whenever the relationship between items is not a simple hierarchy or key-value mapping but an arbitrary set of edges.

The generalization chain is: a tree is a connected acyclic graph; a DAG (directed acyclic graph) generalizes a tree by allowing multiple parents; a general graph allows arbitrary cycles and multi-edges. Every structure that is a tree or DAG is also a graph, so graph algorithms subsume tree and DAG algorithms.

Authoritative sources

Definitions

A graph G=(V,E)G = (V, E) has a set of vertices VV and a set of edges EE.

Every algorithm below behaves differently for directed vs. undirected graphs: topological sort applies only to DAGs, cycle detection differs (back edges in DFS for directed; any non-tree edge for undirected), and MST is defined only for undirected graphs.

Representation

A graph G=(V,E)G = (V, E) with ∣V∣=n|V| = n, ∣E∣=m|E| = m:

RepresentationSpaceEdge queryIterate neighbors
Adjacency listO(n + m)O(deg(v))O(deg(v))
Adjacency matrixO(n2)O(1)O(n)
Hash set of edgesO(n + m)O(1) expectedO(deg(v))
Details

Adjacency list: an array of lists (or vectors). Best for sparse graphs (m≪n2m \ll n^2). The standard choice for most algorithms. Each list is a List structure.

Adjacency matrix: a 2D boolean array. Best for dense graphs or when edge queries are frequent. Supports fast matrix multiplication for transitive closure: the naive algorithm is O(n3)O(n^3); Strassen’s divide-and-conquer gives O(nlog⁡27)≈O(n2.807)O(n^{\log_2 7}) \approx O(n^{2.807}); the best-known algorithms achieve O(nω)O(n^{\omega}) with ω<2.373\omega < 2.373.

Edge list: a flat array of (u, v, weight) tuples. Compact, good for external-memory algorithms and GPU parallelism.

Complexity context: the Big-O bounds above are analyzed in the framework of Computability and Complexity Classes, which defines time and space complexity and complexity classes.

Traversal: BFS and DFS

BFS (Breadth-First Search): explore level by level using a queue.

DFS (Depth-First Search): explore as deep as possible using a stack (or recursion).

Details

BFS: maintain a queue. Start from source ss, mark visited, enqueue neighbors. The first time a vertex is dequeued, the path to it is shortest (in edge count).

Worked example — BFS on a 6-node graph:

Consider the undirected graph with edges: 0-1, 0-2, 1-3, 2-4, 3-4, 4-5. Start from node 0.

StepDequeueQueue (front→back)VisitedDistances
0—[0]{0}d(0)=0
10[1, 2]{0,1,2}d(1)=1, d(2)=1
21[2, 3]{0,1,2,3}d(3)=2
32[3, 4]{0,1,2,3,4}d(4)=2
43[4]{0,1,2,3,4}(4 already visited)
54[5]{0,1,2,3,4,5}d(5)=3
65[]{0,1,2,3,4,5}(done)

The BFS levels are:

0 1 2 3 4 5 level 0 level 1 level 2 level 3

DFS: maintain a stack (or call stack). Three states per vertex: white (unvisited), gray (in progress), black (done). A back edge (to a gray vertex) indicates a cycle in a directed graph; in an undirected graph, any edge to an already-visited vertex that is not the parent indicates a cycle.

Topological sort (Kahn’s algorithm): repeatedly remove vertices with in-degree 0. O(n+m)O(n + m). Fails (detects a cycle) if not all vertices are removed. Used in build systems (make, Bazel), dependency resolution (npm, cargo), and course scheduling.

Interactive visualization: see the Graphs simulation for animated BFS, DFS, and Dijkstra.

Shortest paths

Dijkstra’s algorithm: single-source shortest paths in graphs with non-negative edge weights.

Bellman-Ford: handles negative weights (but not negative cycles).

A*: Dijkstra + a heuristic h(v)h(v).

Details

Dijkstra: maintain a priority queue of (distance, vertex). Pop the minimum, relax its outgoing edges. Each vertex is finalized once. The binary heap gives O(log⁡n)O(\log n) per extract-min and O(log⁡n)O(\log n) per decrease-key.

Worked example — Dijkstra on a 5-node weighted graph:

Edges: A→B (4), A→C (2), B→C (1), B→D (5), C→D (8), C→E (10), D→E (2). Source: A.

IterationExtract-minRelax edgesPQ state (dist, node)
1A (0)A→B: d(B)=4; A→C: d(C)=2[(2,C), (4,B)]
2C (2)C→D: d(D)=10; C→E: d(E)=12; C→B: 2+1=3 < 4 → d(B)=3[(3,B), (10,D), (12,E)]
3B (3)B→D: 3+5=8 < 10 → d(D)=8; B→C: already finalized[(8,D), (12,E)]
4D (8)D→E: 8+2=10 < 12 → d(E)=10[(10,E)]
5E (10)(no outgoing edges)[]

Shortest distances from A: d(A)=0, d(B)=3, d(C)=2, d(D)=8, d(E)=10.

A B C D E 4 2 1 5 8 10 2 Shortest path A→C→D→E (cost 10)

Floyd-Warshall: all-pairs shortest paths in O(n3)O(n^3). Dynamic programming over the set of allowed intermediate vertices.

A*: the heuristic h(v)h(v) estimates the remaining cost to the target. In a grid, Manhattan distance is admissible. In a road network, the crow-fly (Euclidean) distance is admissible. A* is the basis of GPS navigation and game pathfinding.

See also Learning Paradigms and Models for the RL framing of shortest-path problems.

Minimum spanning trees

An MST of a weighted connected undirected graph is a tree spanning all vertices with minimum total edge weight.

Kruskal’s algorithm: sort edges by weight; add an edge if it doesn’t form a cycle (union-find).

Prim’s algorithm: grow the tree from a root; at each step, add the cheapest edge crossing the cut.

Details

Union-Find (disjoint set union): supports make-set, find, union in O(α(n))O(\alpha(n)) amortized per operation (inverse Ackermann, effectively constant). Path compression + union by rank.

Cut property: for any cut of the graph, the minimum-weight edge crossing the cut is in some MST. Both Kruskal and Prim exploit this property.

Worked example — Kruskal on a 6-node weighted graph:

Edges (sorted by weight): AB(1), BC(2), CD(3), DE(4), EF(5), AC(6), BE(7), DF(8).

StepEdge consideredWeightUnion-Find setsAction
1AB1{A,B}, {C}, {D}, {E}, {F}Add (no cycle)
2BC2{A,B,C}, {D}, {E}, {F}Add (no cycle)
3CD3{A,B,C,D}, {E}, {F}Add (no cycle)
4DE4{A,B,C,D,E}, {F}Add (no cycle)
5EF5{A,B,C,D,E,F}Add (no cycle)
6AC6{A,B,C,D,E,F}Skip (cycle)
7BE7{A,B,C,D,E,F}Skip (cycle)
8DF8{A,B,C,D,E,F}Skip (cycle)

MST edges: AB, BC, CD, DE, EF. Total weight: 1+2+3+4+5 = 15.

A B C D E F 1 2 3 4 5 MST (solid) vs. rejected edges (dashed)

Applications: network design (minimize cable length), clustering (single-linkage), image segmentation (minimum spanning tree of a pixel graph), and approximation algorithms (Christofides: MST gives a 1.5-approximation for TSP).

Network flows

A flow network is a directed graph with a source ss, a sink tt, and a capacity c(u,v)≥0c(u,v) \geq 0 on each edge. A flow assigns a value f(u,v)f(u,v) to each edge such that:

The max-flow problem finds the maximum value of flow from ss to tt.

Ford-Fulkerson method: repeatedly find an augmenting path in the residual graph and push flow along it.

Edmonds-Karp: Ford-Fulkerson with BFS to find the shortest augmenting path.

Max-flow min-cut theorem: the maximum flow value equals the minimum cut capacity. A cut $(S, T)$ partitions vertices with s∈Ss \in S, t∈Tt \in T; its capacity is $\sum_{u \in S, v \in T} c(u,v)$.

Details

Residual graph: after pushing flow, the residual graph has forward edges with residual capacity c(u,v)−f(u,v)c(u,v) - f(u,v) and backward edges with capacity f(u,v)f(u,v) (allowing “undo”). An augmenting path is any s→ts \to t path in the residual graph.

Worked example — Ford-Fulkerson on a small network:

Nodes: s, a, b, t. Edges and capacities: s→a (3), s→b (2), a→b (1), a→t (2), b→t (3).

IterationAugmenting pathBottleneckFlow pushedResidual capacities
1s→a→tmin(3,2)=22s→a:1, a→t:0, s→b:2, a→b:1, b→t:3
2s→b→tmin(2,3)=22s→a:1, s→b:0, a→b:1, b→t:1
3s→a→b→tmin(1,1,1)=11s→a:0, a→b:0, b→t:0

No more augmenting paths exist. Max flow = 2 + 2 + 1 = 5.

The min cut is S={s,a,b}S = \{s, a, b\}, T={t}T = \{t\}: capacity = c(a,t) + c(b,t) = 2 + 3 = 5. ✓

s a b t 3/3 2/2 1/1 2/2 3/3 min cut (cap=5) flow/capacity on each edge

Applications:

Graph properties

Several structural properties classify a graph and determine which algorithms apply:

PropertyDefinitionTypical application
BipartiteVertices split into two sets; every edge crosses between sets (no odd cycle)Scheduling, matching, map coloring (2-color)
PlanarCan be drawn in the plane with no edge crossingsCircuit routing, map coloring (4-color theorem), VLSI layout
EulerianHas a cycle that uses every edge exactly once (all vertices have even degree)Route inspection (postal routes), network design
HamiltonianHas a cycle that visits every vertex exactly onceTSP, circuit design, scheduling

Quizz

Problem: Given a directed graph with 500 nodes and 2000 weighted edges (all weights positive), find the shortest path from node 1 to node 500. Which algorithm do you choose and why?

Solution

Choice: Dijkstra’s algorithm with a binary heap.

Reasoning:

  1. All weights are positive → Dijkstra applies (Bellman-Ford is unnecessary).
  2. The graph is sparse: m=2000≪n2=250,000m = 2000 \ll n^2 = 250{,}000 → adjacency list representation.
  3. Time: O((n+m)log⁡n)=O(2500⋅log⁡500)≈22,500O((n + m) \log n) = O(2500 \cdot \log 500) \approx 22{,}500 operations.
  4. A* would be faster in practice if a good admissible heuristic is available (e.g., geographic distance for a road network), but without domain-specific structure, Dijkstra is the safe default.
  5. Floyd-Warshall (O(n3)=125,000,000O(n^3) = 125{,}000{,}000) is overkill for a single-source query.

If weights could be negative: switch to Bellman-Ford, O(nm)=1,000,000O(nm) = 1{,}000{,}000 operations.

If the graph were undirected and unweighted: BFS in O(n+m)=2500O(n + m) = 2500 operations.