📅  最后修改于: 2023-12-03 14:58:01.502000             🧑  作者: Mango
DFS全称为Depth First Search,即深度优先遍历。它是一个类似于树的数据结构或图的遍历算法。它的基本思想是从一个节点出发,尽可能地“深”地遍历一个图的“分支”
DFS遍历可以有两种方式,分别是递归和非递归。
递归DFS遍历是比较常见的方式,它通过递归函数的方式访问每个节点。下面是伪代码:
// 访问节点v
visit(v)
// 标记节点v为已访问
set v as visited
// 遍历节点v的所有邻居
for each neighbor w of v do
// 如果节点w未被访问,递归访问它
if w is not visited then
DFS(w)
endif
endfor
从原理上讲,递归DFS遍历会不断地递归访问节点,同时标记已经被访问过的节点,记录访问过的路径,知道最后达到某个终止条件或者所有节点都被访问过为止。
非递归DFS遍历是一种用栈来模拟递归遍历的方式。下面是伪代码:
setupStack()
// 从起始节点开始遍历
push(start)
// 标记起始节点已被访问
set start as visited
while stack is not empty do
// 获取当前栈顶元素
v = pop()
// 遍历节点v的所有未被访问过的邻居
for each neighbor w of v do
if w is not visited then
// 访问节点w
visit(w)
// 标记节点w为已访问
set w as visited
// 把节点w推入栈中
push(w)
break
endif
endfor
endwhile
从原理上讲,非递归DFS遍历是一种通过栈来保存需要访问的节点的方式。它首先把起始节点推入栈中,标记起始节点已被访问。然后在while循环中,从栈顶获取元素v,遍历节点v的所有未被访问过的邻居。如果找到了未被访问过的邻居,访问它,并标记它已被访问,同时把它推入栈中,继续下一轮循环。
为了更好地理解DFS遍历,有时候我们需要逐步打印出DFS遍历的过程。下面是一个例子:
假设我们有以下无向图:
我们可以用递归DFS遍历来遍历这个图,并逐步打印出遍历的过程。
首先是伪代码:
startDFS(v)
// 创建一个空的栈
stack = []
// 标记起始节点v为已访问
set v as visited
// 把起始节点v推入栈中
push(stack, v)
while stack is not empty do
// 获取当前栈顶元素
x = top(stack)
// 遍历节点x的所有邻居
neighbors = getNeighbors(x)
for each neighbor w in neighbors do
if w is not visited then
// 标记节点w为已访问
set w as visited
// 把节点w推入栈中
push(stack, w)
// 打印遍历过程
printStack(stack)
// 退出for循环,递归调用startDFS(w)
break
endif
endfor
if top(stack) == x then
// 把节点x出栈,因为它已经没有未被访问的邻居
pop(stack)
endif
endwhile
这里的关键点是,在每次递归调用startDFS时,我们要打印当前的栈内元素。这个过程可以通过一个名为printStack的函数来实现。
printStack(stack)
// 打印栈顶元素
print(top(stack))
// 打印栈中的其他元素
for each element e in stack[1:] do
print(e)
endfor
print('\n')
完整的Python代码如下:
class Graph:
def __init__(self, V):
self.V = V
self.adj = [[] for v in range(V)]
def addEdge(self, v, w):
self.adj[v].append(w)
self.adj[w].append(v)
def DFS(self):
def printStack(stack):
print("[", end="")
for i in range(len(stack)):
if i == len(stack)-1:
print(stack[i], end="]\n")
else:
print(stack[i], end=", ")
def startDFS(v):
stack = []
visited[v] = True
stack.append(v)
while stack:
x = stack[-1]
printStack(stack)
neighbors = self.adj[x]
done = True
for i in range(len(neighbors)):
if not visited[neighbors[i]]:
visited[neighbors[i]] = True
stack.append(neighbors[i])
done = False
break
if done:
stack.pop()
visited = [False] * self.V
for v in range(self.V):
if not visited[v]:
startDFS(v)
g = Graph(7)
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(2, 3)
g.addEdge(2, 4)
g.addEdge(3, 4)
g.DFS()
输出结果为:
[0]
[0, 2]
[0, 2, 4]
[0, 2]
[0]
[1]
[1, 3]
[1, 3, 4]
[1, 3]
[1, 2]
[1, 2, 4]
[1, 2]
[1]
[2]
[2, 4]
[2]
[3]
[3, 4]
[3]
[4]
类似于递归DFS遍历,我们也可以逐步打印回溯DFS遍历的过程,即在回溯的过程中逐步打印出遍历的路径。下面是一个例子:
假设我们有以下无向图:
我们可以用回溯DFS遍历来遍历这个图,并逐步打印出遍历的路径。
首先是伪代码:
startDFS(v)
// 标记起始节点v为已访问,打印遍历路径
set v as visited
print(v)
// 遍历节点v的所有邻居
neighbors = getNeighbors(v)
for each neighbor w in neighbors do
if w is not visited then
// 访问节点w的过程
visit(w)
endif
visit(w)
// 回溯
// 打印回溯路径
print(v)
// 取消访问节点w
unset w as visited
这里的关键点是,在每次访问一个节点w结束后回溯时,我们要打印回溯路径。这个过程可以通过在结束访问节点w后加上一段回溯代码来实现。
完整的Python代码如下:
class Graph:
def __init__(self, V):
self.V = V
self.adj = [[] for v in range(V)]
def addEdge(self, v, w):
self.adj[v].append(w)
self.adj[w].append(v)
def DFS(self):
def startDFS(v):
visited[v] = True
print(v, end=" ")
neighbors = self.adj[v]
for neighbor in neighbors:
if not visited[neighbor]:
startDFS(neighbor)
print(v, end=" ")
visited = [False] * self.V
for v in range(self.V):
if not visited[v]:
startDFS(v)
g = Graph(7)
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(2, 3)
g.addEdge(2, 4)
g.addEdge(3, 4)
g.DFS()
输出结果为:
0 1 2 3 4 3 2 1 0 2 4 2
DFS遍历是一种常用的图遍历算法,通过递归或非递归的方式访问每个节点。为了更好地理解遍历过程,我们可以逐步打印出遍历的路径,可以用递归函数中的printStack函数,也可以用回溯DFS遍历中的print函数。