Elementary Graph Algorithms
CSE 680
Suggested Reading: Appendix B4, Chapter 22
1 Graphs
• G(V, E) — V : vertex set; E: edge set.
• Directed graphs, undirected graphs, weighted graphs.
• No self-loops.
• Degree, in-degree, out-degree of a vertex.
• A path from a vertex v to a vertex v 0 is a sequence of vertices, (v0 , v1 , . . . , vk ),
such that v = v0 , v 0 = vk and (vi−1 , vi ) ∈ E for i = 1, 2, . . . , k.
• Length of path: either the number of edges in the path or the total
weight.
• Simple path: all vertices in the path are distinct.
• Cycle, simple cycle
• Acyclic graph
• Graph representations
– Adjacency matrix
– Adjacency lists
1
2 Basic Depth-First Search
procedure Search(G = (V, E))
// Assume V = {1, 2, . . . , n} //
// global array visited[1..n] //
visited[1..n] ← 0;
for i ← 1 to n
if visited[i] = 0 then call df s(i)
procedure df s(v)
visited[v] ← 1;
for each node w such that (v, w) ∈ E do
if visited[w] = 0 then call df s(w)
• How to implement the for-loop if an adjacency matrix A is used to
represent the graph?
• In the entire depth frist search, how many times in total is df s() called?
• In the entire depth frist search, how many times in total is the “if
visited[w] = 0” part of the “if visited[w] = 0 then call df s(w)” state-
ment executed?
• Time complexity
– Using adjacency matrix: O(n2 )
– Using adjacency lists: O(|V | + |E|)
2
3 Connectivity
• An undirected graph is connected if every pair of vertices are connected
by a path.
• A connected component is a subgraph which is connected and is not
contained in any bigger connected subgraph.
• A connected component is usually identified by the vertices in that
component.
• Problem: Given an undirected graph, identify all its connected com-
ponents.
procedure Connected Components(G = (V, E))
// Assume V = {1, 2, . . . , n} //
// global array component[1..n] //
component[1..n] ← 0
cn ← 0
for i ← 1 to n
if component[i] = 0 then
cn ← cn + 1
call df s(i, cn)
procedure df s(v, cn)
component[v] ← cn;
for each node w such that (v, w) ∈ E do
if component[w] = 0 then call df s(w, cn)
3
4 Bipartite Graph
• Definition: An undirected graph G(V, E) is said to be bipartite if V can
be divided into two sets V1 and V2 such that all edges in G go between
V1 and V2 .
• Theorem: An undirected graph is bipartite if and only it contains no
cycle of odd length.
• Problem: Given a graph, determine if it is bipartite.
procedure Bipartite(G = (V, E))
// Assume V = {1, 2, . . . , n} //
// global array visited[1..n], f lag //
visited[1..n] ← 0;
f lag ← true;
for i ← 1 to n
if visited[i] = 0 then call df s(i, 1)
return(flag)
procedure df s(v, c)
visited[v] ← c;
for each node w such that (v, w) ∈ E do
if visited[w] = 0 then call df s(w, −c)
elseif visited[w] = c then f lag ← f alse;
4
5 Advanced Depth-First Search
procedure Search(G = (V, E))
// Assume V = {1, 2, . . . , n} //
time ← 0;
vn[1..n] ← 0; /* vn stands for visit number */
for i ← 1 to n
if vn[i] = 0 then call df s(i)
procedure df s(v)
vn[v] ← time ← time + 1;
for each node w such that (v, w) ∈ E do
if vn[w] = 0 then call df s(w);
f n[v] ← time ← time + 1 /* f n stands for finish number */
• Depth first tree/forest, denoted as Gπ
• Tree edges: those edges in Gπ
• Forward edges: those non-tree edges (u, v) connecting a vertex u to a
descendant v.
• Back edges: those edges (u, v) connecting a vertex u to an ancestor v.
• Cross edges: all other edges.
• If G is undirected, then there is no distinction between forward edges
and back edges. Just call them back edges.
5
6 Topological Sort
• Problem: given a directed graph G = (V, E), sort the vertices into a
linear list such that for every edge (u, v) ∈ E, u is ahead of v in the
list.
• Observation: the finish numbers in descending order gives such a list.
• Algorithm:
– Use depth-first search, with an initially empty list L.
– At the end of procedure df s(v), insert v to the front of L.
– L gives a topological sort of the vertices.
6
7 Strongly Connected Components
• A directed graph is strongly connected if for every two nodes u and v
there is a path from u to v and one from v to u.
• Decide if a graph G is strongly connected:
– G is strongly connected iff (i) there is a path from node 1 to every
other node and (ii) there is a path from every other node to node
1.
– Condition (1) can be checked by calling df s(1) on G and then
checking if all nodes have been visited.
– Condition (2) can be checked by calling df s(1) on GT and then
checking if all nodes have been visited, where GT is the graph
obtained from G by reversing the edges.
• A strongly connected component of a directed graph is a subgraph which
is strongly connected and is not contained in any bigger strongly con-
nected subgraph.
• An interesting problem is to find all strongly connected components of
a directed graph.
• Each node belongs in exactly one component. So, we identify each
component by its vertices.
• The component containing v equals
{df s(v) on G} ∩ {df s(v) on GT },
where {df s(v) on G} denotes the set of all vertices visited during df s(v)
on G.
7
• Algorithm:
1. Apply depth-first search to G and compute f n[u] for each node.
2. Compute GT .
3. Apply depth-first search to GT :
visited[1..n] ← 0
for each vertex u in decreasing order of f n[u] do
if visited[u] = 0 then call df s(u)
4. The vertices on each tree in the depth-first forest of the preceding
step form a strongly connected component.