Notes More applications of DFS and BFS Tyler Moore CSE 3353, SMU, Dallas, TX March 21, 2013 Reminder: HW3 due next Tues Mar 26 Notes I’m holding extra office hours from 4-5:30pm Monday, March 26 Come see me if you have questions 2 / 24 First, a correction from last time Notes Back edges can be made to a processed node Let’s take a more careful look at the definition of edge types. 3 / 24 Edge cases for DFS/BFS traversal Notes Tree edges Forward edge a a c c b b e e d d Back edge Cross edges a a c c b b e e d d 4 / 24
Edge classification Notes 1 Edge ( u , v ) is a tree edge if v was first discovered by exploring edge ( u , v ). 2 Edge ( u , v ) is a back edge if vertex u is connected to an ancestor v . 3 Edge ( u , v ) is a forward edge if vertex u is connected to a descendant v . 4 All other edges are cross edges See board for examples 5 / 24 Some observations about edge types Notes In an undirected graph, the DFS tree has only tree edges and back edges What about for a directed graph? Exercise 1: make a directed graph with a forward edge in the DFS tree Exercise 2: make a directed graph with a cross edge in the DFS tree What can you say about the edges in a BFS tree for an undirected graph? What can you say about the edges in a BFS tree for an directed graph? 6 / 24 What is the running time of DFS? Notes def r e c d f s (G, s , S=None ) : i f S i s None : S = s e t () # I n i t i a l i z e the h i s t o r y S . add ( s ) # We ’ ve v i s i t e d s for u in G[ s ] : # Explore neighbors i f u in S : continue # Already v i s i t e d : Skip r e c d f s (G, u , S) # New : Explore r e c u r s i v e l y > r e c d f s t e s t e d (G, 0) > > [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7] 7 / 24 What is the running time of DFS? Θ( V + E ) Notes Undirected Graph Depth-First Search Tree a 1 7 b b b b f c c c 2 a a a c 6 d d d 5 3 e e e f f f d 4 a c e b d f Discovered: e c a e Processed: d b f 8 / 24
Connected Components Notes A connected component of an undirected graph is a maximal set of vertices such that there is a path between every pair of vertices b d a c e g f Exercise : Explain in English how you could find all connected components of a graph using breadth-first search. 9 / 24 Code to find connected components Notes def find components (G ) : v e r t i c e s = G. keys ( ) u = v e r t i c e s [ 0 ] #p i c k s t a r t i n g v e r t e x components =[] #l i s t of components S =s e t ( ) #d i s c o v e r e d v e r t i c e s while True : cc = l i s t ( b f s (G, u ) ) #do BFS from v e r t e x S . update ( cc ) #update d i s c o v e r e d components . append ( cc ) #update component l i s t f o r v i n cc : #remove component ’ s v e r t i c e s v e r t i c e s . remove ( v ) #from s e t to check v e r t i c e s : i f not break u = v e r t i c e s [ 0 ] #p i c k the next u n d i s c o v e r e d v e r t e x return components > find components (G) > > [ [ ’ a ’ , ’ g ’ , ’ f ’ ] , [ ’ c ’ , ’ e ’ , ’ d ’ ] , [ ’ b ’ ] ] 11 / 24 Strongly connected components Notes A strongly connected component is the maximal subset of a graph with a directed path between any two vertices B g e f a b h c d i A C To find an SCC, we first need to understand how to do a topological sort 12 / 24 Application of topological sorting Notes Figure: Directed acyclic graph for clothing dependencies Figure: Topological sort of clothes 13 / 24
DFS Trees: all descendants of a node u are processed after Notes u is discovered but before u is processed Undirected Graph Depth-First Search Tree a 1 7 b b b b f c c c 2 a a a c 6 d d d 5 3 e e e f f f d 4 a c e b d f Discovered: e c a e Processed: d b f / 14 / 24 How can we tell if one node is a descendant of another? Notes Answer: with depth-first timestamps! After we create a graph in a depth-first traversal, it would be nice to be able to verify if node A is encountered before node B , etc. We add one timestamp for when a node is discovered (during preorder processing) and another timestamp for when a node is processed (during postorder processing) 15 / 24 Code for depth-first timestamps Notes def dfs (G, s , d , f , S=None , t =0): S i s None : S = s e t () # I n i t i a l i z e the h i s t o r y i f d [ s ] = t ; t += 1 # Set d i s c o v e r time S . add ( s ) # We ’ ve v i s i t e d s for u in G[ s ] : # Explore neighbors u in S : continue # Already v i s i t e d . Skip i f t = dfs (G, u , d , f , S , t ) # Recurse ; update timestamp f [ s ] = t ; t += 1 # Set f i n i s h time return t # Return timestamp pre : a pre : b pre : c pre : d pre : e − post : e − − − − − − post : d − − − − − − post : c − − − − − − post : b − − − − − pre : f − post : f − − − − − − post : a − − − − − [ ’ a ’ , ’ c ’ , ’ b ’ , ’ e ’ , ’ d ’ , ’ f ’ ] 16 / 24 Topological sorting on DAGs Notes Directed Acyclic Graph Depth-First Search Tree g 1 4 a b b b d d d f 8 2 6 5 a a a c c c e e e e c b 7 10 3 11 g g g f f f d g e a c Discovered: f d b g e c a d f b Topological sort: g a b c f e d Processed: 17 / 24
Using depth-first timestamps for topological sorting Notes > f = {} > > > d= {} > > > dfs (N, ’ a ’ ,d , f ) > > 12 > d > > { ’ a ’ : 0 , ’ c ’ : 2 , ’b ’ : 1 , ’ e ’ : 4 , ’d ’ : 3 , ’ f ’ : 9 } > f > > { ’ a ’ : 11 , ’ c ’ : 7 , ’b ’ : 8 , ’ e ’ : 5 , ’d ’ : 6 , ’ f ’ : 10 } > f = {} > > > d= {} > > > dfs (DAG, ’ g ’ ,d , f ) > > 14 > t o p s o r t = [ k for k , v in s o r t e d ( f . i t e r i t e m s () , > > key= lambda (k , v ) : v ) ] > t o p s o r t . r e v e r s e () > > > t o p s o r t > > [ ’ g ’ , ’ a ’ , ’b ’ , ’ c ’ , ’ f ’ , ’ e ’ , ’ d ’ ] 18 / 24 Topological sort using custom DFS (iterative) Notes def i t e r d f s t o p s o r t (G) : S , Q, r e s = s e t () , [ ] , [ ] # V i s i t e d − s e t and queue for u in G: #Cover e n t i r e graph Q. append (u) while Q: # Planned nodes l e f t ? v = Q. pop () # Get one i f u in S : continue S . add ( v ) # We ’ ve v i s i t e d i t now Q. extend (G[ v ] ) r e s . append (u) # Postorder process : add node when f i n i s h e d r e s . r e v e r s e () return r e s 19 / 24 Topological sort using custom DFS (recursive) Notes def d f s t o p s o r t (G) : S , r e s = s e t () , [ ] # H i s t o r y and r e s u l t def r e c u r s e (u ) : # T r a v e r s a l s u b r o u t i n e i f u in S : return # Ignore v i s i t e d nodes S . add (u) # Otherwise : Add to h i s t o r y for v in G[ u ] : r e c u r s e ( v ) # Recurse through neighbors r e s . append (u) # F i n i s h e d with u : Append i t for u in G: r e c u r s e (u) # Cover e n t i r e graph r e s . r e v e r s e () # I t ’ s a l l backward so f a r return r e s 20 / 24 Strongly connected components Notes B g e B f a b h A C Are supernodes in a DAG? c d i A C 21 / 24
Strongly connected components Notes What if we transpose all edges? B g e B f a b h A C Supernodes still in DAG c d i A C SCCs don’t change 21 / 24 Kosaraju’s algorithm for finding SCCs Notes 1 Get a topological sort of all vertices 2 Transpose the graph (reverse all edges) 3 Traverse the graph in topologically sorted order, adding an SCC each time a dead end is reached. 22 / 24 Kosaraju’s Algorithm for Finding Strongly Connected Notes Components 1. Get a topological sort of all vertices g e topsort: [a, b, e, f, g, c, d, h, i] seen: f a b h {} sccs: [] c d i 23 / 24 Kosaraju’s Algorithm for Finding Strongly Connected Notes Components 2. Reverse all edges g e topsort: [a, b, e, f, g, c, d, h, i] seen: f a b h {} sccs: [] c d i 23 / 24
Recommend
More recommend