Data Structures and Algorithms
Depth-First Search
executive summary
A depth-first traversal is akin to navigating a maze.
We pursue neighbors of neighbors of neighbors for as long as we can make new discoveries, backtrack when we are stuck, and stop when we are truly stuck (i.e, nothing new to discover and nowhere to backtrack).
link to companion notes · Jeff Erickson Book Chapter · visualgo
In these slides we cover a stack-based implementation of DFS.
Try them all
Explore one thoroughly
What do you do when you have many different options?
Navigating Graphs
Navigating Graphs
Try them all
Explore one thoroughly
What do you do when you have many different options?
Phase 0.
Identify a
starting point \(s\).
Phase 0.
Identify a
starting point \(s\).
Phase 1.
Go to some friend of \(s\).
Phase 1.
Go to some friend of \(s\).
Phase 0.
Identify a
starting point \(s\).
Phase k.
Go to some friend of* friend of friend of friend of ... \(s\).
\(\cdots\)
What if the current person you are talking to has no new friends to introduce you to?
*whom you have
not met yet!
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
\(s\)
\(x\)
\(y\)
\(w\)
\(z\)
Implementation?
[Backtrack, rinse and repeat.]
Phase 1.
Go to some friend of \(s\).
Phase 0.
Identify a
starting point \(s\).
Phase k.
Go to some friend of* friend of friend of friend of ... \(s\).
\(\cdots\)
*whom you have
not met yet!
Maintain Visit Status
visited[s] = 1
//where s is the starting point
visited[u] = 0
//for all other vertices u
find_unvisited_neighbor(v):
if v has an unvisited neighbor:
return w
else:
return -1
A Helper Function
current = s
while(true):
x = find_unvisited_neighbor(current)
if(x > -1):
visited[current] = 1 current = x
?!?
else:
current = s
while(true):
x = find_unvisited_neighbor(current)
visited[current] = 1
current = x
?!?
if(x > -1):
initalize stack T
visited[s] = 1; push(T,s)
while(T is nonempty):
current = peek(T)
visited[x] = 1
push(T,x)
pop(T)
else:
1
2
1
2
1
3
2
1
3
4
2
1
3
1
5
1
1
5
6
1
1
5
6
7
1
1
5
6
1
1
5
8
1
1
5
1
1
1
1
9
1
1
9
10
1
1
9
1
1
x = find_unvisited_neighbor(current)
if(x > -1):
initalize stack T
visited[s] = 1; push(T,s)
while(T is nonempty):
current = peek(T)
visited[x] = 1
pop(T)
else:
push(T,x)
; inc clock; pre[x] = clock
; inc clock; post[v] = clock
; clock = 1
v=
; pre[s] = clock
Source: Algorithms, Jeff Erickson
new if v is not on the stack yet
active if it is on the stack
finished if it is removed from the stack
new if v is not on the stack yet, that is, if:
clock < pre[v]
active if it is on the stack, that is, if:
pre[v] \(\leq\) clock < post[v]
finished if it is removed from the stack, that is, if:
post[v] \(\leq\) clock
edge: u to v; status of v when DFS(u) is called.
(4) cross edges
already finished
(3) back edges
already active
(2) forward edges
new; DFS(v) not called by DFS(u)
(1) tree edges
new; DFS(v) called by DFS(u)
Source: Algorithms, Jeff Erickson
Fix an arbitrary depth-first traversal of any directed graph G.
The following statements are equivalent for all vertices u and v of G.
(a) u is an ancestor of v in the depth-first forest.
(b) u.pre \(\leq\) v.pre < v.post \(\leq\) u.post.
(c) Just after DFS(v) is called, u is active.
(d) Just before DFS(u) is called, there is a path from u to v in which every vertex (including u and v) is new.
TBA
Recursive implementation
Parent-pointer based implementation
More properties of pre/post values
DSA · Depth-First Search
By Neeldhara Misra
DSA · Depth-First Search
- 378