Why study graph algorithms?








| graph | vertex | edge |
|---|---|---|
| communication | telephone, computer | fiber optic cable |
| circuit | gate, register, processor | wire |
| mechanical | joint | rod, beam, spring |
| financial | stock, currency | transactions |
| transportation | intersection | street |
| internet | class C network | connection |
| game | board position | legal move |
| social relationship | person | friendship |
| neural network | neuron | synapse |
| protein network | protein | protein-protein interaction |
| molecule | atom | bond |
| polygonal mesh | geometry | adjacency |
Graph is made up of vertices (nodes, points) connected with edges (links, lines, arcs)
Two vertices are connected if there is a path between them

vertex: black dot; edge: line; path: green lines (len=4); cycle: blue lines (len=5); 3 connected components; red vertex has degree 4
| problem | description |
|---|---|
| s-t path | Is there a path between \(s\) and \(t\)? |
| shortest s-t path | What is the shortest path between \(s\) and \(t\)? |
| cycle | Is there a cycle in the graph? |
| Euler cycle | Is there a cycle that uses each edge exactly once? |
| Hamilton cycle | Is there a cycle that uses each vertex exactly once? |
| connectivity | Is there a path between every pair of vertices? |
| biconnectivity | Is there a vertex whose removal disconnects the graph? |
| planarity | Can the graph be drawn in the plane with no crossing edges? |
| graph isomorphism | Are two graphs isomorphic? |
Challenge: Which graph problems are easy? difficult? intractable?
Graph drawing provides intuition about the structure of the graph


Caveat: Intuition can be misleading
Vertex representation


Anomalies: Not all graph representations can handle these


// degree of vertex v in Graph G
public static int degree(Graph G, int V) {
int degree = 0;
for(int w : G.adj(v)) degree++;
return degree;
}
Maintain a list of edges as pairs of vertices.
![]() |
edges = [(0,1), (0,2), (0,5), (0,6),
(3,4), (3,5), (4,5), (4,6),
(7,8), (9,10), (9,11),
(9,12), (11,12)]
|
Note: (0,1) implies (1,0) is also an edge
Which is order of growth of running time of the following code fragment if the graph uses the edge-list representation, where \(V\) is the number of vertices and \(E\) is the number of edges?
// prints each edge exactly once
for(int v = 0; v < G.V(); v++)
for(int w : G.adj(v))
if(v < w)
StdOut.println(v + "-" + w);
\(V\)
\(E+V\)
\(V^2\)
\(VE\)
Maintain a two-dimensional \(V\)-by-\(V\) boolean array;
for each edge \(v\)-\(w\) in graph: adj[v][w] = adj[w][v] = true.
Two entries for each edge
Which is order of growth of running time of the following code fragment if the graph uses the adjacency-matrix representation, where \(V\) is the number of vertices and \(E\) is the number of edges?
// prints each edge exactly once
for(int v = 0; v < G.V(); v++)
for(int w : G.adj(v))
if(v < w)
StdOut.println(v + "-" + w);
\(V\)
\(E+V\)
\(V^2\)
\(VE\)
Maintain vertex-indexed array of lists
![]() |
![]() |
Which is order of growth of running time of the following code fragment if the graph uses the adjacency-lists representation, where \(V\) is the number of vertices and \(E\) is the number of edges?
// prints each edge exactly once
for(int v = 0; v < G.V(); v++)
for(int w : G.adj(v))
if(v < w)
StdOut.println(v + "-" + w);
\(V\)
\(E+V\)
\(V^2\)
\(VE\)
In practice, use adjacency-lists representation

representation |
space |
add edge |
edge between \(v\) and \(w\) |
iterate over verts adj to \(v\) |
|---|---|---|---|---|
| list of edges | \(E\) | \(1\) | \(E\) | \(E\) |
| adjacency matrix | \(V^2\) | \(1^\dagger\) | \(1\) | \(V\) |
| adjacency lists | \(E+V\) | \(1\) | \(\degree(v)\) | \(\degree(v)\) |
\(^\dagger\)disallows parallel edges
public class Graph {
private final int V;
private Bag<Integer>[] adj; // adj lists
public Graph(int V) {
// create empty graph with V vertices
this.V = V;
adj = (Bag<Integer>[]) new Bag[V];
for(int v = 0; v < V; v++)
adj[v] = new Bag<Integer>();
}
public void addEdge(int v, int w) {
// add edge v-w (parallel edges and self-loops allowed)
adj[v].add(w);
adj[w].add(v);
}
// iterator for vertices adjacent to v
public Iterable<Integer> adj(int v) {
return adj[v];
}
}
Maze graph:

Graph: vertex for every intersection, edge for every passage
Goal: Explore every intersection in the maze

Algorithm:




Goal: systematically traverse a graph
Idea: mimic maze exploration (function-call stack acts as ball of string)
DFS (to visit a vertex v)
Mark vertex v
Recursively visit all unmarked verts w adj to v
Typical applications:
Design challenge: how to implement?
To visit a vertex \(v\):
Design pattern: decouple graph data type from graph processing
Graph objectGraph to a graph-processing routine
// print all verts connected to s
Paths paths = new Paths(G, s);
for(int v = 0; v < G.V(); v++)
if(paths.hasPathTo(v))
StdOut.println(v);
To visit a vertex \(v\)
Data structures:
marked[] to mark verticesedgeTo[] to keep track of paths (edgeTo[w] == v) means that edge \(v\)-\(w\) taken to discover vertex \(w\)public class DepthFirstPaths {
private int s;
private boolean[] marked; // true if v connected to s
private int[] edgeTo; // prev vertex on path from s to v
public DepthFirstPaths(Graph G, int s) {
// initialize data structures
/* ... */
// find vertices connected to s
dfs(G, s);
}
// recursive DFS does the work
private void dfs(Graph G, int v) {
marked[v] = true;
for(int w : G.adj(v)) {
if(!marked[w]) {
edgeTo[w] = v;
dfs(G, w);
}
}
}
}
Proposition: DFS marks all vertices connected to \(s\) in time proportional to the sum of their degrees (plus time to initialize the marked[] array).
Proposition: After DFS, can check if vertex \(v\) is connected to \(s\) in constant time and can find \(v\)-\(s\) path (if one exists) in time proportional to its length.
Pf. edgeTo[] is parent-link representation of a tree rooted at vert \(s\).
public boolean hasPathTo(int v) { return marked[v]; }
public Iterable<Integer> pathTo(int v) {
if(!hasPathTo(v)) return null;
Stack<Integer> path = new Stack<Integer>();
for(int x = v; x != s; x = edgeTo[x])
path.push(x);
path.push(s);
return path;
}
Proposition: After DFS, can check if vertex \(v\) is connected to \(s\) in constant time and can find \(v\)-\(s\) path (if one exists) in time proportional to its length.
Pf. edgeTo[] is parent-link representation of a tree rooted at vert \(s\).

Problem: Implement flood fill (Photoshop magic wand)


Challenge: Implement DFS without recursion
One solution (see link)
Challenge: Implement DFS without recursion
Alternative solution (space proportional to \(E+V\), vertex can appear on stack more than once)
|
Tree traversal: Many ways to explore every vertex in binary tree
|
![]() |
Graph search: Many ways to explore every vertex in a graph
dfs(G,v)dfs(G,v)sRepeat until queue is empty:
public class BreadthFirstPaths {
private boolean[] marked;
private int[] edgeTo;
private int[] distTo;
/* ... */
private void BFS(Graph G, int s) {
Queue<Integer> q = new Queue<Integer>();
q.enqueue(s); // init FIFO queue of vertices to explore
marked[s] = true;
distTo[s] = 0;
while(!q.isEmpty()) {
int v = q.dequeue();
for(int w : G.adj(v)) {
if(!marked[w]) { // found new vertex w via edge v-w
q.enqueue(w);
marked[w] = true;
edgeTo[w] = v;
distTo[w] = distTo[v] + 1;
}
}
}
}
}
Q. In which order does BFS examine vertices?
Proposition: In any connected graph \(G\), BFS computes shortest paths from \(s\) to all other vertices in time proportional to \(E+V\).


Fewest number of hops in a communication network

![]() |
![]() ![]() |



Problem: Identify connected components
|
How difficult?
|
![]() |
Problem: Is a graph bipartite?
|
How difficult?
|
![]() |
Problem: Find a cycle in a graph (if one exists).
|
How difficult?
|
![]() |
Problem: Is there a (general) cycle that uses every edge exactly once?
|
How difficult?
|
![]() |
Problem: Is there a cycle that contains every vertex exactly once?
|
How difficult?
|
![]() |
Problem: Are two graphs identical except for vertex names?
|
How difficult?
|
![]() |
Problem: Can you draw a graph in the plane with no crossing edges?
|
How difficult?
|
![]() |
BFS and DFS enables efficient solution of many (but not all) graph problems
| graph problem | BFS | DF S | time |
|---|---|---|---|
| s-t path | ✓ | ✓ | \(E+V\) |
| shortest s-t path | ✓ | \(E+V\) | |
| cycle | ✓ | ✓ | \(E+V\) |
| Euler cycle | ✓ | \(E+V\) | |
| Hamilton cycle | \(\pow(2,1.657V)\) | ||
| bipartiteness (odd cycle) | ✓ | ✓ | \(E + V\) |
| connected components | ✓ | ✓ | \(E + V\) |
| biconnected components | ✓ | \(E + V\) | |
| planarity | ✓ | \(E + V\) | |
| graph isomorphism | \(\pow(2,c\cdot\sqroot(V \log V))\) |