CMPSC250 Lecture 19: Undirected Graphs

CMPSC250
Lecture 19: Undirected Graphs
Prof. John Wenskovitch
04/02/2015
Last Time
• Data Compression
– Compress reduces, expansion expands
– Compression must be reversible, or at least a very
close approximation
– Compression must be computationally efficient
• Huffman Compression
– Prefix-free, variable length character codes
– Build a trie from the bottom up
04/02/2015
Undirected Graphs
2
Basic Graph Terminology
•
•
•
•
•
•
•
•
Graph
Vertex
Edge
Self-loop edge
Parallel edge
Degree
Subgraph
Undirected/Directed
04/02/2015
Undirected Graphs
•
•
•
•
•
•
•
Path
Simple path
Connected/Disconnected
Cyclic/Acyclic
Tree
Sparse/Dense graph
Bipartite graph
3
Book Graph Input
04/02/2015
Undirected Graphs
4
Storing a Graph
• Needs to be both space-efficient
for storage and time-efficient for
searching.
• Option #1: Adjacency matrix
– (fails #1)
• Option #2: Array/list of edges
– (fails #2)
• Option #3: Array of adjacency lists
– (OK)
04/02/2015
Undirected Graphs
5
Exploring a Graph
• Option #1: Depth-First Search
– Think of it as exploring a maze:
• Take any unmarked passage (edge), unrolling a string behind
you
• Mark all intersections (vertices) and passages (edges) when
you visit them
• Retrace steps using the string when you visit a marked
intersection (vertex)
• Retrace steps when no unvisited options remain at an
intersection encountered when retracing steps
04/02/2015
Undirected Graphs
6
Depth-First Search
public DepthFirstSearch(Graph G, int s) {
marked = new boolean[G.V()];
dfs(G, s);
} //DepthFirstSearch (constructor)
private void dfs(Graph G, int v) {
marked[v] = true;
count++;
for (int w : G.adj(v)) {
if (!marked(w)) {
dfs(G, w);
} //if
} //for
} //dfs
public boolean marked(int w) {
return marked[w];
} //marked
04/02/2015
Undirected Graphs
7
Depth-First Search – Visual
04/02/2015
Undirected Graphs
8
Depth-First Search – Analysis
• Theorem: DFS marks all the vertices connected to a given
source in time proportional to the sum of their degrees.
• Proof:
– Every marked vertex is connected to the source, since the
algorithm finds vertices only by following edges.
– Suppose that some unmarked vertex w is connected to s.
– Since s is marked, any path from s to w must have at least one
edge from the set of marked vertices to the set of unmarked
vertices, say v-x.
– But, the algorithm would have discovered x after marking v, so
no such edge can exist.
– The time bound follows because marking ensures that each
vertex is visited once. ∎
04/02/2015
Undirected Graphs
9
Finding Paths
• An extension of DFS is determining whether or
not a path exists between any pair of nodes.
• Add an edgeTo[] array to store the path
generated, saving the edge v-w that takes us
to each vertex w for the first time by setting
edgeTo[w] = v.
• The result is a tree rooted at the source.
04/02/2015
Undirected Graphs
10
Finding Paths
public void dfs(Graph G, int v) {
...
if (!marked(w)) {
edgeTo[w] = v;
...
} //dfs
public Iterable<Integer> pathTo(int v) {
if (!hasPathTo(v)) {
return null;
} //if
Stack<Integer> path = new Stack<Integer>();
for (int x = v; x != s; x = edgeTo[x]) {
path.push(x);
} //for
path.push(s);
return path;
} //pathTo
04/02/2015
Undirected Graphs
11
Finding Paths – Visual
04/02/2015
Undirected Graphs
12
Finding Paths – Analysis
• Theorem: DFS allows us to provide clients
with a path from a given source to any marked
vertex in time proportional to its length.
• Proof: Extension of the DFS Proof.
– By induction on the number of vertices visited, it
follows that the edgeTo[] array represents a tree
rooted at the source.
– The pathTo() method builds that path in time
proportional to its length. ∎
04/02/2015
Undirected Graphs
13
Breadth-First Search
• DFS – When we’re at a node, explore all paths
from that node recursively.
• BFS – When we’re at a node, explore one step
in each path from that node iteratively.
• Usage: Rather than identify whether or not a
path exists, we will find the shortest path (if it
exists).
04/02/2015
Undirected Graphs
14
Breadth-First Search
(main calls bfs(G,s))
private void bfs(Graph G, int s) {
Queue<Integer> queue = new Queue<Integer>();
marked[s] = true;
queue.enqueue(s);
while (!(queue.isEmpty()) {
int v = queue.dequeue();
for (int w : G.adj(V)) {
if (!marked(w)) {
edgeTo[w] = v;
// save last edge on path
marked[w] = true;
// mark it because path known
queue.enqueue(w);
// add it to the queue
} //if
} //for
} //while
} //bfs
04/02/2015
Undirected Graphs
15
Breadth-First Search – Visual
04/02/2015
Undirected Graphs
16
Breadth-First Search – Analysis
• Theorem: For any vertex v reachable from s, BFS
computes a shortest path from s to v.
• Proof:
– By induction, it is trivial to prove that the queue always
consists of zero or more vertices of distance 𝑘 from the
source, followed by zero or more vertices of distance 𝑘 + 1
from the source, for some integer 𝑘 starting with 𝑘 = 0.
– This property implies that vertices enter and leave the
queue in order of their distance from s.
– When a vertex v enters the queue, no shorter path to v
will be found before it comes off the queue, and no path
to v that is discovered after it comes off the queue can be
shorter than v’s tree path length.∎
04/02/2015
Undirected Graphs
17
Breadth-First Search – Analysis
• Theorem: BFS takes time proportional to 𝑉 + 𝐸
in the worst case.
• Proof:
– BFS marks all vertices connected to s in time
proportional to the sum of their degrees (like DFS did).
– If the graph is connected, this sum equals the sum of
the degrees of all the vertices, or 2𝐸.
– Initializing the marked[] and edgeTo[] arrays takes
time proportional to 𝑉.
– 2𝐸 + 2𝑉 grows at rate O(𝐸 + 𝑉).∎
04/02/2015
Undirected Graphs
18
DFS vs BFS Visual (First 250 Nodes)
04/02/2015
Undirected Graphs
19
Any Questions?
04/02/2015
Undirected Graphs
20