Graph Traversal H ow can w e explore every intersection system atically in this m ap?
Feb 11, 2016
Graph Traversal
How can we explore every intersection systematically in this map?
Recall that with a rooted tree, we have preorder, inorder, and postorder traversal to visit all the nodes. Now we want to do the similar thing. We want some ways to visit every vertex and edge systematically. traversal of a graph: a systematic procedure for exploring a graph by examining all of its vertices and edges. The first algorithm is called depth-first search.
Depth-First Search Consider an undirected graph G. In this approach, we start with a vertex s. We mark this vertex as visited. And the vertex s is now the current vertex.
svisited
Now we arbitrarily select an edge (s, u) and visit vertex u. We mark the vertex u as visited and now our current vertex is u.
s
visited
uvisited
Again, we arbitrarily select an edge (u, v) and visit the vertex v. If vertex v has already been marked as visited, we go back to the vertex u and select another edge incident on u such as (u, w).
s
visited
vvisited
wvisited
u
We repeat the process and eventually get to a dead-end, i.e., a current vertex u such that all the edges incident on u lead to visited vertices. In this case, we backtrack along the edge that brought us to u, going back to a previously visited vertex v. Then we make vertex v current and repeat the process for other edges (such as (v, w)) incident on vertex v.
s
visitedv
backtrack
u
w
dead-end
visited
If the vertex v becomes a dead-end, we backtrack further to the vertex z that broght us to v. We repeat this until we backtrack to where we started, the vertex s. Now the traversal is completed.
svisited
v
backtrack
u
w
dead-end
visited
z
If the vertex v becomes a dead-end, we backtrack further to the vertex z that broght us to v. We repeat this until we backtrack to where we started, the vertex s. Now the traversal is completed.
svisited
v
backtrack
u
w
dead-end
visited
z
If the vertex v becomes a dead-end, we backtrack further to the vertex z that broght us to v. We repeat this until we backtrack to where we started, the vertex s. Now the traversal is completed.
svisited
v
backtrack
u
w
dead-end
visited
z
If the vertex v becomes a dead-end, we backtrack further to the vertex z that broght us to v. We repeat this until we backtrack to where we started, the vertex s. Now the traversal is completed.
svisited
v
backtrack
u
w
dead-end
visited
z
If the vertex v becomes a dead-end, we backtrack further to the vertex z that broght us to v. We repeat this until we backtrack to where we started, the vertex s. Now the traversal is completed.
svisited
v
backtrack
u
w
dead-end
visited
z
Example discovery edges: tree edges: The edges used to discover new vertices. back edges: The edges lead to visited vertices.
s
s
s
s
Notice that the discovery edges form a spanning tree of the connected component of the starting vertex s. Recall that a spanning tree is a spanning subgraph that is a tree.
A spanning subgraph is a subgraph that contains all the vertices of the graph.
s
Algorithm DFS(G, v): Input: A graph G and a vertex v of G
Output: A labeling of the edges as discovery/back edges
loop for every edge e incident on v if edge e is unexplored assign the opposite vertex to w if vertex w is unexplored label e as discovery edge call DFS(G, w) else label e as a back edge
Extension to the Position Abstract Data Type To mark the explored vertices, we need to add the following methods to the position ADT:
has(a): Tests whether the position has attribute a get(a): Returns the value of attribute a
set(a, x): Sets to x the value of attribute a destroy(a): Removes attribute a and its associated value
A Generic DFS Implementation in Java We declare a class that can be extended to accomplish various tasks. public abstract class DFS { protected InspectableGraph G; protected Object visitResult; // unmark all positions public Object execute( InspectableGraph g, Vertex start, Object info ) { G = g; for( PositionIterator pos = G.positions(); pos.hasNext(); )
unVisit( pos.nextPosition()); return null;
}
protected Object dfsTraversal( Vertex v ) { initResult(); if( !isDone())
startVisit( v ); if( !isDone())
visit( v ); for( EdgeIterator inEdges = G.incidentEdges( v ); inEdges.hasNext(); ) { Edge nextEdge = inEdges.nextEdge();
if( !isVisited( nextEdge )) { visit( nextEdge ); Vertex w = G.opposite( v, nextEdge ); if( !isVisited( w )) { traversDiscovery( nextEdge, v ); if( isDone()) break;
visitResult = dfsTraversal( w ); if( isDone()) break; } else { traverseBack( nextEdge, v ); if( isDone()) break;
} } } }
if( !isDone()) finishVisit( v );
return result(); } // Auxiliary methods for specializing a generic DFS protected void initResult() {} // initializes result // Called when we first visit v protected void startVisit( Vertex v ) {} // Called when we finish with v protected void finishVisit( Vertex v ) {} // Discovery edge protected void traverseDiscovery( Edge e, Vertex from ) {} // Back edge protected void traverseBack( Edit e, Vertex from ) {} // is DFS done early? (namely, not being back to vertex s) protected boolean isDone() { return false; } // The result of the DFS protected Object result() { return new Object(); }
// Attribute and its two values for the // visit status of positions protected static Object STATUS = new Object(); protected static Object VISITED = new Object(); protected static Object UNVISITED = new Object(); // Mark a position as visited protected void visit( Position p ) {
p.set( STATUS, VISITED ); } // Mark a position as unvisited protected void unVisit( Position p ) { p.set( STATUS, UNVISITED ); } // Test if a position has been visited protected boolean isVisited( Position p ) { return( p.get( STATUS ) == VISITED ); }
}// End of class DFS
Here is a class that uses DFS to determine whether the graph is connected. public class ConnectivityDFS extends DFS { protected int reached; public Object execute( Graph g, Vertex start, Object info ) { init( g ); int n = 0; Iterator V = G.vertices(); while( V.hasNext()) { V.next(); n++; } reached = 0; dfsTraversal( start ); return new Boolean( reached == n ); protected void startVisit( Vertex v ) { reached++; } }
Example reached = 5 n = 7 Therefore, the graph is not connected.
s
Another application of the class DFS is to find a path from a given vertex to another. public class FindPathDFS extends DFS { protected List path protected boolean done; protected Vertex target; public Object execute( Graph g, Vertex start, Object info ) { init( g ); path = new NodeList(); done = false; target = ( Vertex )info; // info object stores target dfsTraversal( start ); return path.elements(); } protected void startVisit( Vertex v ) { path.insertLast( v ); if( v == target ) done = true; }
protected void finishVisit( Vertex v ) { path.remove( path.last()); // remove v from path if( !path.isEmpty()) // if v is not the start vertex // remove discovery edge into v from path path.remove( path.last()); } protected void traversDiscovery( Edge e, Vertex from ) { path.insertLast( e ); } protected boolean isDone() { return done }; }
Example start
target
The last application of the class DFS is to find a cycle in the connected component of a given vertex v. public class FindCycleDFS extends DFS { protected List Cycle; protected boolean done; protected Vertex cycleStart; public Object execute( Graph g, Vertex start, Object info ) { init( g ); cycle = new NodeList(); done = false; dfsTraversal( start ); // remove the vertices and edges from start to cycleStart if( !cycle.isEmpty() && start != cycleStart ) { Iterator pos = cycle.positions(); while( pos.hasNext()) {
Position p = ( Position )pos.next(); // remove vertex from cycle
cycle.remove( p ); p = ( Position )pos.next(); // remove edge from cycle Edge e = ( Edge )p.element();
c y c l e . r e m o v e ( p ) ; V e r t e x [ ] e n d v = g . e n d V e r t i c e s ( e ) ; c y c l e . r e m o v e ( p ) ; V e r t e x [ ] e n d v = g . e n d V e r t i c e s ( e ) ; i f ( ( e n d v [ 0 ] = = c y c l e S t a r t ) | |
( e n d v [ 1 ] = = c y c l e S t a r t ) ) b r e a k ; } } r e t u r n c y c l e . e l e m e n t s ( ) ; }
s t a r t
r e m o v e
s t a r t
c y c l e
c y c l e S t a r t
protected void startVisit( Vertex v ) { cycle.insertLast( v ); } protected void finishVisit( Vertex v ) { cycle.remove( cycle.last()); if(!cycle.isEmpty()) cycle.remove( cycle.last()); } protected void traverseDiscovery( Edge e, Vertex from ) { cycle.insertLast( e ); } protected void traverseBack( Edge e, Vertex from ) { cycle.insertLast( e ); cycleStart = G.opposite( from, e ); cycle.insertLast( cycleStart ); done = true; } protected boolean isDone() { return done; } } // end of class FindCycleDFS
Breadth-First Search This is another way to traverse a graph. In this approach, we try to visit all the vertices adjacent to the vertices belonging to a level.
Like DFS, we start from vertex s (level 0). Then we visit all the vertices adjacent to s and place these vertices into level 1.
slevel 0
level 1
Then we visit all the vertices adjacent to vertices at level 1 and place them into level 2 and so on.
When every vertex has been visited, the BFS traversal terminates.
slevel 0
level 1level 2
Algorithm BFS(s): initialize container 0L to contain vertex s assign 0 to variable i loop until container iL is empty create an empty container 1iL loop for every vertex v in iL loop for every edge e incident on v if edge e is unexplored assign the opposite vertex to w if vertex w is unexplored label e as a discovery edge insert w into 1iL else label e as a cross edge increment i
Example
s0
s0 1
discovery edges: The edges lead to new vertices cross edges: The edges lead to visited vertices There are no back edges because none will lead to one of its ancestors.
s0
21
s0 31
2
s0 31
2
4
Like DFS, the discovery edges form a spanning tree of the connected component of the starting vertex s. Notice that the shortest path (in terms of the number of edges) from the vertex s to any vertex in level i is i.
s0 31
2
4
5
Data Structure Exercises 21.1