DFS(深度优先搜索)的递归与非递归

DFS,depth-first search,深度优先搜索。顾名思义,从一个节点出发,尽可能往下遍历,即尽可能离“家”远一点,这个思想其实就是树结构遍历中的先序遍历。

那么从上述话语中,我们可以很容易地判断出需要用到递归,其实DFS的常规构造方法也就是用到递归的,但是我们还要考虑到一个问题,那么就是如果一个图足够大,比如有上万个节点,上万条边,那么估计用递归运行DFS我们的电脑会瞬间卡死。。。因为递归的代价实在是太大了,图如果小一点还好,不是特别明显,一旦图过大,递归的劣势会被无限放大,因此这里除了用递归来构造DFS以外,我还会介绍非递归的方法,即通过使用数据结构——来代替函数调用,虽说栈的出现会导致占用过多的内存空间,但是,时代变了!区区一个栈再大能够有多大呢?再宝贵能有时间宝贵吗?所以在大型的图深度遍历中,使用栈的DFS绝对要比使用递归的DFS的效率要高!

递归算法转化为非递归算法的优点

  1. 节省内存空间
  2. 提高执行效率

一些特殊情况

首先我们需要考虑到一些特殊情况:

  • 某些图存在环路,因此我们需要避免因为环路导致的死循环,即重复遍历相同的节点。
    • 解决方案就是,添加一个标志位mark,未遍历的节点mark为0
  • 某些图并不是所有的节点都连接在一起,即从一个节点出发可能无法遍历所有的节点。
    • 解决方案就是,在一次遍历结束时,检查标志数组mark[],通过查看其所有的mark是否为0,来判断是否遍历完所有的节点。

解决完这些特殊情况之后,那么接下来就进入到了正式环节:

常规版本——递归DFS

先上伪代码

因为伪代码没有其他语言的语法限制,能够有助于我们更好地将注意力放在算法上,所以我们先用伪代码来讲述一下主要思想:

algorithm DFS(G)
//实现给定图G的广度优先搜索
//输入:图G=<V, E>,其中V为G中所有的节点集合,E为G中所有的边集合
//输出:图G的节点,按照DFS遍历访问到的先后顺序
count <- 0
for 每个属于V的v do
	mark[v] <- 0  //将每个节点的标志位都赋初值为0,表示未被访问
for 每个属于V的v do
	if mark[v] = 0
		dfsVisit(v)
		
dfsVisit(v)
count <- count + 1
visit(v)
mark[v] <- count
for 每个与v相邻的节点w do
	if mark[w] = 0
		dfsVisit(w)

由以上代码便实现了DFS,接下来只需要使用某一种特定的高级语言来实现即可。

在实现之前,我们先来探讨一下其中的一些细节:

1.以上代码是否实现了遍历所有节点的要求呢?

首先在DFS()中,我们在调用dfsVisit()函数之前,是用了一个循环遍历所有的节点,然后若一个节点未被遍历,则会调用dfsVisit()函数,随后将与其相连接的节点全部遍历完,因此能够实现遍历所有的节点。

for 每个属于V的
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花无凋零之时

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值