深度优先搜索的介绍
深度优先搜索(Depth First Search,缩写为DFS)是一种用于遍历或搜索树或图的算法。它从一个开始顶点(或根顶点)开始遍历图或树,沿着一条路径直到没有更多的未访问节点为止,然后回溯到之前的顶点,继续寻找下一个可以访问的顶点。
DFS算法可以用递归或堆栈等方式实现。它的基本思想是深度优先遍历每个结点,访问未访问过的子结点。在遍历过程中,标记已经访问过的结点,以避免重复访问。
DFS的伪代码:
DFS(start):
visited[start] = true
for each neighbor of start:
if neighbor is not visited:
DFS(neighbor)
其中,start
为起始节点,visited
为已访问的节点集合。我们先将起始节点标记为已访问,然后遍历该节点的所有邻居,如果邻居节点未被访问过,则递归访问该节点,标记为已访问。
具体实现方式可以有多种,比如可以使用递归方式实现,也可以使用堆栈等数据结构实现。无论哪种方式,算法都具有类似的基本思想:深度优先搜索遍历每个结点,尽可能深入地搜索每个结点的所有子结点,只有在到达末端后才回溯到上一个结点。
DFS算法在Python中的具体实现:
from typing import List
def dfs(graph: List[List[int]], start: int, visited: List[bool]):
# 标记当前节点为已访问
visited[start] = True
print(start, end=' ')
# 遍历当前节点的邻居节点
for neighbor in graph[start]:
# 如果邻居节点未被访问过,则递归访问它
if not visited[neighbor]:
dfs(graph, neighbor, visited)
# 例子:使用邻接表实现的无向图
n = 6
graph = [[] for _ in range(n)]
graph[0] = [1, 2]
graph[1] = [0, 3, 4]
graph[2] = [0, 4]
graph[3] = [1, 5]
graph[4] = [1, 2, 5]
graph[5] = [3, 4]
# 从节点0开始进行DFS
visited = [False] * n
dfs(graph=graph, start=0, visited=visited)
在实现中,我们使用邻接表(graph
)来表示无向图的数据结构。其中,graph[i]
表示节点i的所有邻居节点,即跟节点i直接相连的其他节点。
在dfs
函数中,我们先将起始节点标记为已访问,并输出当前节点的编号。接着,遍历当前节点的所有邻居节点,如果邻居节点没有被访问过,则递归访问它。这样,我们就可以按照深度优先的方式遍历整张图。最后,我们输出遍历过程中经过的所有节点编号。
以上的实现方式是递归方法,DFS也可以用迭代方法中的堆栈实现。
通过使用堆栈来实现
在迭代方式下,DFS可以通过使用堆栈来实现,主要思路是:
-
将起始节点加入到堆栈
-
如果堆栈非空,那么弹出栈顶元素
-
如果当前弹出的节点没有被访问过,那么把该节点加入到已访问节点中,并将其邻接节点压入堆栈中(这是为了接下来继续访问)
-
重复步骤2
用堆栈实现DFS的Python代码:
def dfs_iterative(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
stack.append(neighbor)
return visited
在上述代码中,我们使用一个集合来存储已访问的节点,使用一个堆栈保存当前待访问的节点。若堆栈非空,那么弹出栈顶元素,判断该节点是否已经被访问。若未被访问,则将该节点标记为已访问,并把它的邻接节点压入堆栈中,等待后续访问。重复进行上述步骤,直到堆栈为空,此时遍历完成。最后,我们返回已经访问的节点集合。
二叉树上的深度优先搜索
对于二叉树上的深度优先搜索(DFS),通常有三种不同的遍历方式:
- 前序遍历(Preorder Traversal)
- 中序遍历(Inorder Traversal)
- 后序遍历(Postorder Traversal)
下面分别介绍这三种遍历方式的具体实现方式:
1. 前序遍历
在前序遍历中,首先访问根节点,然后递归地遍历左子树和右子树。下面是前序遍历的Python代码:
def preorder(root):
if not root:
return
print(root.val)
preorder(root.left)
preorder(root.right)
2. 中序遍历
在中序遍历中,首先递归地遍历左子树,然后访问根节点,最后递归遍历右子树。下面是中序遍历的Python代码:
def inorder(root):
if not root:
return
inorder(root.left)
print(root.val)
inorder(root.right)
3. 后序遍历
在后序遍历中,首先递归地遍历左子树和右子树,然后访问根节点。下面是后序遍历的Python代码:
def postorder(root):
if not root:
return
postorder(root.left)
postorder(root.right)
print(root.val)
需要注意的是,在实现二叉树的深度优先搜索算法时,我们需要考虑如何处理空节点,以及如何标记已经被访问的节点。另外,我们还需要在代码中考虑如何传递参数和处理返回值,以便正确地实现二叉树的深度优先搜索算法。
总结
深度优先搜索(DFS)是一种用于遍历图和树的常用算法,其核心思想是从某个起始节点开始,尽可能深地遍历图或树,直到无法继续往下遍历为止,然后再回溯到上一个结点继续遍历。
DFS算法的实现可以采用递归和非递归(使用堆栈)两种方式。对于图的DFS,我们需要使用一个辅助集合来记录已经访问过的节点,在遍历时,可以采用递归方式实现,也可以使用非递归方式,使用栈来保存当前待访问的节点。
对于二叉树的DFS遍历,有三种不同的遍历方式,分别是前序遍历,中序遍历和后序遍历。在二叉树DFS遍历中,需要注意处理空节点和已访问节点的情况,还需要考虑参数传递和返回值的问题。