深度优先搜索(DFS)
深度优先搜索(DFS)是一个算法用于搜索图或树数据结构。该算法从树的根(顶部)节点开始,沿着给定的分支(路径)尽可能地前进,然后回溯,直到找到未探索过的路径,然后探索它。算法一直这样做,直到整个图被探索完毕。计算机科学中的许多问题都可以用图形来思考。例如,网络分析、路由映射、调度和查找生成树都是图问题。为了分析这些问题,图搜索算法比如深度优先搜索很有用。
在其他更复杂的算法中,深度优先搜索常被用作子程序。例如,匹配算法,Hopcroft-Karp,使用DFS作为算法的一部分来帮助查找匹配在图表中。DFS也用于树遍历算法,也称为树搜索,其中有应用旅行推销员问题和Ford-Fulkerson算法.
你是如何走出迷宫的?
深度优先搜索是许多人解决迷宫等问题的常用方法。首先,我们在迷宫中选择一条路径(为了举例,让我们根据事先制定的规则选择一条路径),然后沿着它走,直到我们遇到一个死胡同或到达迷宫的终点。如果给定的路径不起作用,我们就返回并从过去的路口选择另一条路径,并尝试那条路径。下面是DFS方法解决这个迷宫的动画。
深度优先搜索
深度优先搜索的主要策略是尽可能深入图中。深度优先搜索搜索来自最近发现的顶点的边, .只有指向未探测顶点的边才会被探测。当所有的 月球的边缘已经被探索过了,搜索就会返回,直到它到达一个未被探索的邻居。这个过程一直持续到所有从原始源顶点可以到达的顶点被发现为止。如果有任何未访问的顶点,深度优先搜索选择其中一个作为新的源,并从该顶点重复搜索。算法重复整个过程,直到发现每个顶点。该算法小心地避免重复顶点,因此每个顶点都被探索一次。DFS使用堆栈数据结构来跟踪顶点。
下面是执行深度优先搜索的基本步骤:
- 访问一个顶点 .
- 马克 参观了。
- 递归地访问所附的每个未访问的顶点 .
这个动画演示了深度优先搜索算法:
注意:这个动画没有将节点标记为“已访问”,这将更清楚地说明回溯步骤。
根据深度优先搜索访问节点的顺序,将每个节点1到12标记为以下图:
解决方案:
实现深度优先搜索
下面是递归和非递归实现DFS的伪代码和Python代码示例。该算法一般使用a堆栈为了跟踪已访问的节点,最后看到的节点是下一个要访问的节点,其余节点被存储起来以供以后访问。
伪代码[1]
1 2 3 4 5 6 7 8 9 10初始化一个空堆栈用于存储节点s,对于每个顶点u,定义u.visited为false。将根节点(第一个被访问的节点)推入S,当S不为空时:弹出S中的第一个元素u。如果u.visited = false,则:u.visited = true对于u的每个未被访问的邻居w:将w推入S,当所有节点都被访问时结束进程。
没有递归的Python实现
1 2 3 4 5 6 7 8defdepth_first_search(图):参观了,堆栈=集(),[根]而堆栈:顶点=堆栈.流行()如果顶点不在参观了:参观了.添加(顶点)堆栈.扩展(图[顶点]-参观了)返回参观了
DFS还可以使用递归实现,这大大减少了代码行数。
使用递归的Python实现
1 2 3 4 5 6 7defdepth_first_search_recursive(图,开始,参观了=没有一个):如果参观了是没有一个:参观了=集()参观了.添加(开始)为下一个在图[开始]-参观了:depth_first_search_recursive(图,下一个,参观了)返回参观了
修改算法以跟踪边而不是顶点是很常见的,因为每条边都描述了每一端的节点。这在处理完每个节点后试图重构遍历树时非常有用。对于森林或一组树,该算法可以扩展为包含一个外部循环,遍历所有树,以便处理每个节点。
实现DFS有三种不同的策略:预购,按次序的,后序.
预购DFS的工作原理是访问当前节点,然后依次向左移动,直到到达一个叶节点,在到达的过程中访问每个节点。一旦节点的左边不再有子节点,就会访问右边的子节点。这是最标准的DFS算法。
它不是在树中遍历每个节点,而是按次序的算法找到树中最左边的节点,访问该节点,然后访问该节点的父节点。然后它转到右边的子节点,并找到树中最左边的下一个节点进行访问。
一个后序策略的工作原理是访问树中最左边的叶节点,然后向上访问同一分支中的父节点,然后向下访问同一分支中第二个最左边的叶节点,以此类推,直到父节点成为分支中要访问的最后一个节点。如果目标位于树的末端,这种类型的算法会优先处理叶结点,而不是根结点。
深度优先搜索的复杂性
深度优先搜索访问图中的每个顶点一次,检查图中的每条边一次。因此,DFS复杂度为 .这假设图是表示为邻接表.
DFS vs BFS
广度优先搜索比深度优先搜索的空间效率低,因为BFS保留了整个前沿的优先级队列,而DFS在每一层保留了几个指针。
如果已知答案很可能在树的深处找到,那么DFS是比BFS更好的选择。当树的深度可以变化或需要单个答案时(例如,树中的最短路径),BFS非常适合使用。如果要遍历整个树,DFS是更好的选择。
BFS总是返回一个最优答案,但DFS并不保证这一点。
下面是一个例子,它比较了使用BFS和DFS(三种方法中的每一种)时图的搜索顺序。[2]
广度优先搜索: 1 2 3 4 5
深度优先搜索
- 预购:1 2 4 5 3
- 顺序:4 2 5 1 3
- 邮购:4 5 2 3 1
应用程序
参考文献
- 堆,D。深度优先搜索(DFS).检索,2002年12月16日,从http://www.cs.toronto.edu/~heap/270F02/node36.html
- Gupta, D。二叉树的BFS vs DFS.检索2016年7月20日,从http://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/