0% found this document useful (0 votes)
29 views

Graph Traversal DFS

Depth-first search (DFS) is an algorithm for exploring a graph by going deeper whenever possible. It uses a stack to remember which vertices still need to be explored further. DFS colors vertices white, gray, and black to track the exploration process. It also records discovery and finish times for each vertex. DFS runs in O(V+E) time and explores the entire graph systematically without being given a starting vertex. The Parenthesis Theorem describes the relationships between vertex discovery and finish times in the DFS tree.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

Graph Traversal DFS

Depth-first search (DFS) is an algorithm for exploring a graph by going deeper whenever possible. It uses a stack to remember which vertices still need to be explored further. DFS colors vertices white, gray, and black to track the exploration process. It also records discovery and finish times for each vertex. DFS runs in O(V+E) time and explores the entire graph systematically without being given a starting vertex. The Parenthesis Theorem describes the relationships between vertex discovery and finish times in the DFS tree.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 56

Depth-first search: Idea

• A way to “explore” a graph. Useful in several


algorithms.
• We saw the breadth-first search (BFS) algorithm.
• The algorithm explored outward in all directions
uniformly.
• We will now see depth-first search (DFS), an
algorithm that explores out in one direction, backing
up when necessary.
• Graph G=(V,E) directed or undirected
• Goal: Systematically explore every vertex and every
edge
• Idea: Search deeper whenever possible
Depth-first search: Key components
• Maintains several fields for each vertex.
• We’ll use a color:
WHITE never seen
GRAY discovered but not finished
BLACK finished

• DFS also timestamps each vertex with two


timestamps
• d[v] : records when v is first discovered and grayed
• f[v]: records when v is finished and blackened
• Since there is only one discovery event and finishing
event for each vertex we have 1<=d[v] <f[v]<=2|V|
• [v] : predecessor of v = u, such that v was
discovered during the scan of u’s adjacency list.
Cont.
• Input: G = (V, E), directed or undirected. No source
vertex given!
• Output:
– 2 timestamps on each vertex.
• d[v] = discovery time
• f [v] = finishing time black)
– [v] : predecessor of v
Depth-first search: Algorithm
DFS(G) DFS-Visit(u)
1. for each vertex u  V[G]
1. color[u]  GRAY  White
2. do color[u]  white vertex u has been discovered
3. [u]  NIL 2. time  time + 1
4. time  0
3. d[u]  time
5. for each vertex u  V[G]
4. for each v  Adj[u]
6. do if color[u] = white
5. do if color[v] = WHITE
7. then DFS-Visit(u)
6. then [v]  u
7. DFS-Visit(v)
8. color[u]  BLACK 
Blacken u; it is finished.
9. f[u]  time  time + 1
Depth-first search: Analysis
• Initialization loop and main loop in DFS :(V) time,
excluding time to execute DFS-Visit.
• DFS-Visit is called once for each white vertex vV
when it’s painted gray the first time.
• For loop in DFS-Visit is executed |Adj[v]| times. The
total cost of executing DFS-Visit is vV|Adj[v]| =
(E).
• Total running time of DFS is (V+E).
Depth-first search: Example

x y z

s t

w v u
Depth-first search: Example

x y z
1

s t

w v u
Depth-first search: Example

x y z
1

s t

w v u
Depth-first search: Example

x y z
1

s t

w v u
Depth-first search: Example

x y z
1

s t

w v u
Depth-first search: Example

x y z
1

s t

3 4

w v u
Depth-first search: Example

x y z
1

s t

3 4 5

w v u
Depth-first search: Example

x y z
1

s t

3 4 5 6

w v u
Depth-first search: Example

x y z
1

s t

2 7

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8

s t

2 7

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8

s t

2 7

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8

s t

2 7 9

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8

s t

2 7 9

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 8 11

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 12 8 11

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6 14

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6 14

w v u
Depth-first search: Example

x y z
1 12 8 11 13

s t

2 7 9 10

3 4 5 6 14 15

w v u
Depth-first search: Example

x y z
1 12 8 11 13 16

s t

2 7 9 10

3 4 5 6 14 15

w v u
Depth-first search: DFT and DFF
By keeping track of parents, we want to construct a forest resulting
from the DFS traversal.
x y z
1 12 8 11 13 16

s t

2 7 9 10

3 4 5 6 14 15

w v u y
z
1 12 8 11 13 16
x t
s
2 7 9 10

3 4 5 6 14 15

w v u
Theorem: When DFS(s) is called on a node s, no recursive
calls will be made on nodes not reachable from s.
Proof: By contradiction; assume a recursive call is made on at
least one node not reachable from s.
There must be a first node v visited this way; v can't be s, since s
is trivially reachable from itself.
Thus DFS(v) must have been recursively invoked by DFS(u) for
some node u ≠ v, which in turn called DFS(v).
This means edge (u, v) must exist. Now, we consider two cases:
– Case 1: u is reachable from s. But then v is reachable from s,
because we can take the path from s to u and follow edge (u,
v).
– Case 2: u is not reachable from s. But then v was not the first
node not reachable from s to have DFS called on it.
In either case, we reach a contradiction, so our assumption was
wrong. Thus DFS(s) never makes recursive calls on nodes not
reachable from s.
Parenthesis Theorem
In DFS of graph, for all u, v, exactly one of the following holds:
1. Interval (d[u], f [u]) or ( d[v],f [v]) are disjoint and neither u nor v is a descendant of
the other.
2. Interval (d[u], f [u]) is contained within interval ( d[v],f [v]) and u is a descendant of
v.
3. Interval ( d[v],f [v]) is contained within interval (d[u], f [u] and v is a descendant of u.

Proof: Consider d[u] < d[v]. Two subcases - d[v] < f [ u] or not.
The first subcase d[v] < f [u]: so v was discovered while u was still gray,
implies v is a descendant of u. Also v was discovered more recently than u, as
all of its outgoing
edges are explored and is finished, before the search returns to and finishes
u. Hence, interval ( d[v],f [v] is entirely contained within the interval (d[u], f
[u]).
Other subcase, f[u] < d[v], and d[u] < f [u].
So, d[u] < f [u] < d[v] < f [v]; interval (d[u], f [u],) or ( d[v],f [v]) are disjoint.
Because the intervals are disjoint, neither vertex was discovered while the
other
was gray, and so neither vertex is a descendant of the other.
The case in which : d[v] < d[u] is similar.
Example (Parenthesis Theorem)
y z s t
3/6 2/9 1/10 11/16
B F C B

4/5 C 7/8 C 12/13 C 14/15


x w v u

(s (z (y (x x) y) (w w) z) s) (t (v v) (u u) t)
Classification of Edges
• Consider edge (u,v) in directed graph G = (V,E) w.r.t.
DFS forest

• Tree edge: in the depth-first forest. Found by exploring


(u, v). v is a child of u.
• Back edge: (u, v), where u is a descendant of v (in the
depth-first tree). It is from descendent to ancestor.
• Forward edge: (u, v), where v is a descendant of u, but
not a tree edge.
• Cross edge: any other edge. Can go between vertices in
same depth-first tree or in different depth-first trees.
Theorem: In DFS of an undirected graph, we get only tree
and back edges. No forward or cross edges.
1/8 2/7 9/12
in DFS forest
tree
b a e
not in DFS
forest
forward tree tree
back cross

d c f
tree back
4/5 3/6 10/11

35
Theorem: A graph G (directed or not) contains a cycle
if and only if a DFS of G yields a back edge.
• Assume G contains a cycle. Let v be the first vertex
reached on the cycle by a DFS of G. All the vertices
reachable from v will be explored from v, including the
vertex u that is just “before” v in the cycle. Since v is
an ancestor of u, the edge (u,v) will be a back edge.
• Say the DFS results in a back edge from u to v.
Clearly, u→v ( “there is a path from u to v”, or “v is
reachable from u”). And since v is an ancestor of u (by
def of back edge), v→u . So v and u must be part of a
cycle.
Back Edge Detection

• How can we detect back edges with DFS? For


undirected graphs, see if we’ve visited the vertex
before, i.e. color ≠ WHITE.
• For directed graphs: we color a vertex GRAY
while its adjacent vertices are being explored. If
we re-visit the vertex while it is still GRAY, we
have a back edge.
• We blacken a vertex when its adjacency list has
been examined completely. So any edges to a
BLACK vertex cannot be back edges.
Topological Sort
• In college, before taking a particular course, students usually
must take all applicable prerequisite courses.
• For example, before taking the Programming II course, students
must take the Programming I course.
• However, certain courses can be taken independently of each
other.
• The courses within a department can be represented as a directed
graph.
• A directed edge from, say, vertex u to vertex v means that the
course represented by the vertex u is a prerequisite of the course
represented by the vertex v.
• It would be helpful for students to know, before starting a major,
the sequence in which they can take courses so that before
taking a particular course they take all its prerequisite courses.
• This section describes an algorithm that can be used to output
the vertices of a directed graph in such a sequence.
Example
• Problem: Find
322
an order in 143
321
which all these
courses can be
taken 142
326

370
• Example: 142 341

143 378 370


321 341 322
326 421 401 378
421
401
Topological sort
• Topological sort (of directed acyclic graph): It
is linear ordering of all the vertices such that if
(u,v) is a directed edge, then u appears before
v in the ordering.
– We assume that the graph has no cycles.

• Ordering is not necessarily unique!


Topological sort: Example
A B F C D E

Valid order
C
A

D E Not Valid order

A B E C D F
Topological sort : Algorithm 1
• Step 1: Identify vertices that have no incoming
edges
– The “In-degree” of these vertices is zero.
B

C
A

D E
Topological sort : Algorithm 1
• Step 1: Identify vertices that have no incoming
edges
– If no such edges, graph has cycles (cyclic graph).
B

C
A
Example of a cyclic
graph: No vertex of
In-degree 0

D
Topological sort : Algorithm 1
• Step 2: Delete this vertex of in-degree 0 and all
its outgoing edges from the graph. Place it in
the output.
B

C
A

D E
Topological sort : Algorithm 1
• Repeat Step1 and Step 2 until graph is empty.

C
A

D E
Topological sort : Algorithm 1
• Repeat Step1 and Step 2 until graph is empty.

C
A B

D E
Topological sort : Algorithm 1
• Repeat Step1 and Step 2 until graph is empty.

C
A B F

D E
Topological sort : Algorithm 1
• Repeat Step1 and Step 2 until graph is empty.

A B F C D E
Summary of Topological Sort
Algorithm B

• Store each vertex’s In- C


degree (# of incoming A
edges) in an array. F
• While there are vertices
remaining: D E

– Find a vertex with In-


degree zero and output it
– Reduce In-degree of all
vertices adjacent to it by
1
– Mark this vertex(in-
In-
degree = -1) Degree
array
Topological Sort Algorithm 1:
Analysis
• For input graph G(V,E), Run time =??
• Break down into total time required to:
– Initialize In-degree array: O(|E|)
– Find vertex with In-degree 0:
• |V| vertices, each takes O(|V|) to search In-degree array. Total
time = O(|V|2)
– Reduce In-degree of all vertices adjacent to a vertex:
O(|E|)
– Output and mark vertex: O(|V|)
– Total time =O(|V|2+ |E|) Quadratic time!
Topological sort
• Can we do better than quadratic time?

• Problem:
– Need a faster way to find vertices with in-degree 0
instead of searching through entire in-degree array
Topological sort: Improvement
• Key Idea: Initialize and maintain a queue (or
stack) of vertices with In-degree 0
Queue A F

C
A
F

In-Degree
D E array
Topological sort: Improvement
After each vertex is output, when updating In-degree
array, enqueue any vertex whose In-degree has become
zero. F B
Queue

Dequeue Enqueue

Output A
B

C
A
F
In-Degree
D E array
Topological Sort Algorithm 1:
Analysis
• For input graph G(V,E), Run time =??
• Break down into total time required to:
– Initialize In-degree array: O(|E|)
– Initialize Queue with In-degree 0 vertices: O(|V|)
– Dequeue and output vertex:
• |V| vertices, each takes only O(1) to dequeue and output.
• So total time = O(|V|)
– Reduce In-degree of all vertices adjacent to a vertex
and Enqueue any In-Degree 0 vertices: O(|E|)
– Total time =O(|V| + |E|) Linear running time!
Topological sort: Algorithm 2
• The algorithm
– Run DFS(G)
– When a vertex is finished, output it
– Vertices are output in the reverse topologically
sorted order
• Runs in O(V+E) time – a linear time
algorithm

You might also like