1 CSCI 104 Graph & Tree Search and Traversals Algorithms Mark Redekopp David Kempe Sandra Batista
2 RECURSIVE TREE TRAVERSALS
3 Guiding Recursive Principle f(n) f(n-1) 1 0 1 2 3 4 • A useful principle when trying to 50 51 52 53 54 develop recursive solutions is that the recursive code should handle 2 only 1 element, which might be: f(head) f(head->next) 1. An element in an array 0x148 2. A node a linked list 0x148 0x1c0 0x380 0x0 3 9 7 0x1c0 0x380 3. A node in a tree NULL val next val next val next 4. One choice in a sequence of choices • Then use recursion to handle the 3 f(n) remaining elements • And finally combine the solution(s) to the recursive call(s) with the one f(right) f(left) element being handled
4 Recursive Tree Traversals • A traversal iterates over all nodes of the tree – Usually using a depth-first, recursive approach // Node definition struct TNode { • Three general traversal orderings int val; TNode *left, *right; – Pre-order [Process root then visit subtrees] }; – In-order [Visit left subtree, process root, visit right subtree] – Post-order [Visit left subtree, visit right subtree, process root] Preorder(TNode* t) Inorder(TNode* t) { if t == NULL return { if t == NULL return 60 process(t) // print val. Inorder(t->left) Preorder(t->left) process(t) // print val. Preorder(t->right) Inorder(t->right) 20 80 } } 10 20 25 30 50 60 80 60 20 10 30 25 50 80 10 30 Postorder(TNode* t) { if t == NULL return Postorder(t->left) 25 50 Postorder(t->right) process(t) // print val. } 10 25 50 30 20 80 60
5 Example 1: Count Nodes • Write a recursive function to count how many nodes are in the binary tree – Only process 1 node at a time – Determine pre-, in-, or post-order based on whose answers you need to compute the result for your node – For in- or post-order traversals, determine how to use/combine results from recursion on children // Node definition struct Tnode { int val; TNode *left, *right; }; f(n) int count(TNode* root) { if( root == NULL ) _______________; else { f(right) f(left) } }
6 Example 2: Prefix Sums • Write a recursive function to have each node store the sum of the values on the path from the root to each node. – Only process 1 node at a time – Determine pre-, in-, or post-order based on whose answers you need to compute the result for your node void prefixH(TNode* root, int psum) void prefix(TNode* root) { prefixH(root, 0); } f(n) void prefixH(TNode* root, int psum) { 4 if( root == NULL ) ________________; 4 else { f(right) f(left) 3 8 7 12 5 7 12 14 } }
7 GENERAL GRAPH TRAVERSALS
8 BREADTH-FIRST SEARCH
9 Breadth-First Search • Given a graph with vertices, V, and edges, E, and a starting vertex that h b we'll call u 0 c • BFS starts at u (‘a’ in the diagram to the a d left) and fans-out along the edges to g nearest neighbors, then to their e neighbors and so on f • Goal: Find shortest paths (a.k.a. Depth 0: a minimum number of hops or depth) from the start vertex to every other vertex
10 Breadth-First Search • Given a graph with vertices, V, and edges, E, and a starting vertex, u h b • BFS starts at u (‘a’ in the diagram to the 0 c 1 a left) and fans-out along the edges to d nearest neighbors, then to their g neighbors and so on 1 e • Goal: Find shortest paths (a.k.a. f minimum number of hops or depth) Depth 0: a from the start vertex to every other Depth 1: c,e vertex
11 Breadth-First Search • Given a graph with vertices, V, and 2 edges, E, and a starting vertex, u h b • BFS starts at u (‘a’ in the diagram to the 0 c 1 a left) and fans-out along the edges to 2 2 d nearest neighbors, then to their g neighbors and so on 1 2 e • Goal: Find shortest paths (a.k.a. f minimum number of hops or depth) Depth 0: a from the start vertex to every other Depth 1: c,e vertex Depth 2: b,d,f,g
12 Breadth-First Search • Given a graph with vertices, V, and 3 2 edges, E, and a starting vertex, u h b • BFS starts at u (‘a’ in the diagram to the 0 c 1 a left) and fans-out along the edges to 2 2 d nearest neighbors, then to their g neighbors and so on 1 2 e • Goal: Find shortest paths (a.k.a. f minimum number of hops or depth) Depth 0: a from the start vertex to every other Depth 1: c,e vertex Depth 2: b,d,f,g Depth 3: h
13 Developing the Algorithm • Key idea: Must explore all nearer neighbors before exploring further- h b away neighbors 0 c 1 • From ‘a’ we find ‘e’ and ‘c’ a d – If we explore 'e' next and find 'f' who g should we choose to explore from next: 1 2 e 'c' or 'f'? f • Must explore all vertices at depth i before any vertices at depth i+1 Depth 0: a Depth 1: c,e – Essentially, the first vertices we find Depth 2: b,d,f,g should be the first ones we explore from Depth 3: h – What data structure may help us?
14 Developing the Algorithm • Exploring all vertices in the order they are found implies we will explore all vertices at shallower depth before greater depth – Keep a first-in / first-out queue (FIFO) of neighbors found • Put newly found vertices in the back and pull out a vertex from the front to explore next • We don’t want to put a vertex in the queue more than once… – ‘mark’ a vertex the first time we encounter it – only allow unmarked vertices to be put in the queue • May also keep a ‘predecessor’ structure that indicates how each vertex got discovered (i.e. which vertex caused this one to be found) – Allows us to find a shortest-path back to the start vertex
15 Breadth-First Search Algorithm: nil,inf nil,inf h b BFS(G,u) nil,inf nil,0 c 1 for each vertex v 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue nil,inf nil,inf d 4 Q.enqueue(u), d[u]=0 g 5 while Q is not empty 6 v = Q.front(); Q.dequeue() nil,inf nil,inf e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) 10 pred[w] = v, d[w] = d[v] + 1 Q: a
16 Breadth-First Search Algorithm: nil,inf nil,inf h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue nil,inf nil,inf d 4 Q.enqueue(u), d[u]=0 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() nil,inf e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 a Q: e c
17 Breadth-First Search Algorithm: nil,inf nil,inf h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue nil,inf nil,inf d 4 Q.enqueue(u), d[u]=0 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 e Q: c c f
18 Breadth-First Search Algorithm: nil,inf c,2 h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue c,2 d 4 Q.enqueue(u), d[u]=0 c,2 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 c Q: c f b d g
19 Breadth-First Search Algorithm: nil,inf c,2 h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue c,2 d 4 Q.enqueue(u), d[u]=0 c,2 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 f Q: c b d g
20 Breadth-First Search Algorithm: b,3 c,2 h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue c,2 d 4 Q.enqueue(u), d[u]=0 c,2 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 b Q: c d g h
21 Breadth-First Search Algorithm: b,3 c,2 h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue c,2 d 4 Q.enqueue(u), d[u]=0 c,2 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 d Q: g c h
22 Breadth-First Search Algorithm: b,3 c,2 h b BFS(G,u) nil,0 c 1 for each vertex v a,1 2 pred[v] = nil, d[v] = inf. a 3 Q = new Queue c,2 d 4 Q.enqueue(u), d[u]=0 c,2 g 5 while Q is not empty a,1 6 v = Q.front(); Q.dequeue() e,2 e 7 foreach neighbor, w, of v: f 8 if pred[w] == nil // w not found 9 Q.enqueue(w) v = 10 pred[w] = v, d[w] = d[v] + 1 g Q: h c
Recommend
More recommend