📜  逐步打印DFS遍历(也可以回溯)(1)

📅  最后修改于: 2023-12-03 14:58:01.502000             🧑  作者: Mango

逐步打印DFS遍历(也可以回溯)

什么是DFS遍历?

DFS全称为Depth First Search,即深度优先遍历。它是一个类似于树的数据结构或图的遍历算法。它的基本思想是从一个节点出发,尽可能地“深”地遍历一个图的“分支”

如何进行DFS遍历?

DFS遍历可以有两种方式,分别是递归和非递归。

递归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遍历

非递归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遍历的过程。下面是一个例子:

假设我们有以下无向图:

DFS Graph

我们可以用递归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遍历的过程,即在回溯的过程中逐步打印出遍历的路径。下面是一个例子:

假设我们有以下无向图:

DFS Graph

我们可以用回溯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函数。