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
© Copyright 2024