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)
s
Repeat 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))\) |