[-------------------------v1-----------------------]
[-------v2------] [-------------v6-------------]
[----v3---] [----------v5----------]
[-v4-] [------v7------]
[---v8---]
[-v9-]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Tree edges: (v1,v2), (v2,v3), (v1,v6), (v6,v5), (v5,v7), (v7,v8), (v8,v9)
Back edges: (v5,v6), (v9,v8)
Cross edges: (v8,v4), (v9,v3), (v5,v4)
There are no forward edges.
Two possible vertices are \(v_2\) and \(v_9\). The tree for \(v_2\) would only have the root of \(v_2\), \(v_3\) as its child, and v4 as its grandchild. The tree for \(v_9\) would have \(v_9\) as the root with 2 children being \(v_3\) and \(v_8\), and then one more grandchild, \(v_4\), attached to \(v_3\). We see that both the trees have the \(v_3\) and \(v_4\) vertices, but they each have other vertices in their tree.
Add a clock and two vertex attributes:
DFS(v, clock):
mark v
clock <- clock + 1; v.pre <- clock
for each edge vw
if w is unmarked
w.parent <- v
clock <- DFS(w, clock)
clock <- clock + 1; v.post <- clock
return clock
v.pre
is the clock value when the vertex v
is first discovered and marked.
v.post
is the clock value when we are done exploring v
.
Suppose we run DFS
on a graph \(G\).
v.pre
.v.post
.If \(G\) is a tree, these notions are the same as preorder/postorder traversals.
For any two vertices u
and v
, exactly one of the following must hold:
[u.pre..u.post]
and [v.pre..v.post]
do not overlap.
[u.pre..u.post]
is contained in [v.pre..v.post]
.
u
is a descendant of v
in a depth-first tree.[v.pre..v.post]
is contained in [u.pre..u.post]
.
v
is a descendant of u
in a depth-first tree.Notice: .pre
and .post
must be nested like parentheses:
Every edge uv
in the graph is one of the following.
uv
is in a/the depth-first tree.
DFS(u)
calls DFS(v)
directly, so u = v.parent
.v
is a descendant of u
, but not its child.
u.pre
\(<\) v.pre
\(<\) v.post
\(<\) u.post
uv
goes backwards up a depth-first tree.
v.pre
\(<\) u.pre
\(<\) u.post
\(<\) v.post
uv
connects different branches in the depth-first forest.
v.post
\(<\) u.pre
u
\(\rightarrow\) v
from u
to v
.
[u.pre..u.post]
is contained in [v.pre..v.post]
, then u
is a descendant of v
in a depth-first tree.
u.post
\(<\) v.post
.uv
is a back edge.v
to u
.uv
is part of a cycle.So we can determine if a graph contains a cycle:
DoesGraphHaveACycle(G)
for each edge uv in G:
if u.post < v.post return "Graph has a cycle"
return "Graph has no cycles"
DFS(v, clock):
mark v
clock <- clock + 1; v.pre <- clock
for each edge vw
if w is unmarked
w.parent <- v
clock <- DFS(w, clock)
clock <- clock + 1; v.post <- clock
return clock
// wrapper: // Modified DFS:
IsAcyclic(G): IsAcyclicDFS(v):
for all vertices v v.status <- Active
v.status <- New for each edge vw
for all vertices v if w.status = Active
if v.status = New return False
if IsAcyclicDFS(v) = False else if w.status = New
return False if IsAcyclicDFS(w) = False
return True return False
v.status <- Finished
return True
A directed graph without cycles is called a directed acyclic graph (DAG).
Suppose \(G\) is a DAG.
.post
. (Reverse postordering)See Figure 6.8.
TopologicalSort(G):
Call DFSAll(G) to compute finishing times v.post for all v in G
Return vertices in order of decreasing finishing times
DFS(v, clock):
mark v
clock <- clock + 1; v.pre <- clock
for each edge vw
if w is unmarked
w.parent <- v
clock <- DFS(w, clock)
clock <- clock + 1; v.post <- clock
return clock
DFSAll(G):
clock <- 0
for all vertices v
unmark v
for all vertices v
if v is unmarked
clock <- DFS(v, clock)
TopologicalSort(G):
Call DFSAll(G) to compute finishing times v.post for all v in G
Return vertices in order of decreasing finishing times
Facts:
Table #1 | Table #2 | Table #3 | Table #4 | Table #5 | Table #6 | Table #7 |
---|---|---|---|---|---|---|
Andrew | John | Logan | Jordan | Bri | Levi | Jack |
Drake | Josiah | Ethan | Kristen | Blake | Talia | Trevor |
Grace | Isaac | Claire | Nathan | Kevin | Graham | James |
DFS
, assume that the for-loops consider the vertices in numerical order. Include the starting and finishing times for each vertex.How many sources and sinks are there in this DAG?
Now suppose DFSAll
considers vertex 6 first, and then vertex 1. Repeat question 1, and note any differences.
What relation does this DAG model? Are there other topological orderings for this DAG?