DFS

DFS基于堆栈的基本结构,用回溯实现搜索,所以,不适合于解决最短路这样的问题。

DFS stops with first-found path, if there are multiple ones.

使用递归实现伪代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
visited[] // store previously visited node, for each vertex 0 .. nV-1

findPath (G, src, dest):
Input graph G, vertices src, dest

for all vertices v ∈ G do
visited[v] =- 1
end for
visited[src]=src // starting node of the path
if dfsPathCheck (G, src, dest) then // show path in dest .. src order
v=dest
while v≠src do
print v"-"
v=visited[v]
end while
print src
end if

dfsPathCheck (G, v,dest):
if v=dest then
return true // found edge from v to dest
else
for all (v, w) Eedges (G) do
if visited[w] =- 1 then
visited[w]=v
if dfsPathCheck (G, w, dest) then
return true // found path via w to dest
end if
end if
end for
end if
return false // no path from v to dest

递归调用 dfsPathCheck(G, w, dest) 的过程中,会深入到图中的下一个顶点 w,如果在这个子问题中找到了目标 dest,那么 return true 将立即结束当前层次的递归,表示已经找到了一条路径。这时,递归回溯到上一层次,继续尝试其他可能的路径。

使用栈迭代实现伪代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
hasPath(G,src,dest):
Input graph G, vertices src,dest
Output true if there is a path from src to dest in G, otherwise return false

mark all vertices in G as unvisited

push src onto new stack s
found=false
while not found and s is not empty do
pop v from s
mark v as visited
if v=dest then
found=true
else
for each (v,w) ∈ edges(G) such that w has not been visited do
push w onto s
end for
end if
end while
return found

对比某种DFS的变体(不是DFS)!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
hasPath(G,src,dest):
Input graph G, vertices src,dest
Output true if there is a path from src to dest in G, otherwise return false

mark all vertices in G as unvisited
if src=dest then
return true
end if

push src onto new stack s
found=false
while not found and s is not empty do
pop v from s
mark v as visited
for each (v,w) ∈ edges(G) such that w has not been visited
if w=dest then
return true
end if
push w onto s
end for
end while
return false

不难看出,该变体提前终结了循环,并未等到将目标元素压栈。

BFS

BFS采用队列作为基本实现结构,从起点出发“平推前进”,如果是带权图,可以直接用于解决最短路问题,使用递归有点复杂。

BFS finds a “shortest path” based on minimum #edges between src and dest.

BFS访问每个点只经过一次。

观察BFS变体(不是BFS)!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mark all vertices as unvisited
if src=dest then
return true
end if
enqueue src into a new queue Q
while Q is not empty do
dequeue v from Q and mark v as visited
for each edge (v,w) such that w has not been visited do
if w=dest then
return true
end if
enqueue w into Q
end for
end while
return false

和原版对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
visited[]

findPathBFS(G,src,dest):
Input graph G, vertices src,dest

for all vertices v ∈ G do
visited[v]=-1
end for

enqueue src into new queue q
visited[src]=src
found=false
while not found and q is not empty do
dequeue v from q
if v=dest then
found=true
else
for each (v,w) ∈ edges(G) such that visited[w]=-1 do
enqueue w into q
visited[w]=v
end for
end if
end while

if found then
display path in dest...src order
end if

这个BFS变体有点像DFS,因为他不保证每个点只遍历一次,原因在于其未记录w是否入过队列;不同于两者,在遍历到某点可达的下一个点集合中存在目标点,当即return true,然而入队操作在那之后,所以,目标点根本不会进入队列。