BFS与DFS模板总结

  • Post author:
  • Post category:其他




1.常规BFS模板

最典型的BFS场景之一为二叉树的层次遍历。如果我们不需要得到当前层数,可以采用如下模板样式。

while queue not empty
	cur = queue.pop()
	visit cur
	for node in cur.neighbors
		if node valid and not visit
			queue.push(node)



2.需要确定层数的BFS模板

有的时候我们需要获取当前遍历层数,此时需要增加level变量表示当前遍历到那一层,比如二叉树的层次遍历。如果是一个图中,亦可以表示已经遍历走了多少步。

level = 0 # 当前层数
while queue not empty
	size = queue.size  # 表示当前层的元素个数
	while (size--) # size为0表示当前层已经遍历完毕
		cur = queue.pop
		for node in cur.neighbors:
			if node valid and not visit
				queue.push(node)
	level++



3.DFS模板

def backtrack(需要搜索的集合,递归层数,状态变量1,状态变量2,...,结果集):
	if 递归终止条件:
		结果集加入当前状态
		return
	for 可以执行的分支路径:
		if 递归层数,状态变量1,状态变量2,... 符合剪枝条件:
			continue 
		对状态变量状态变量 1, 状态变量 2 的操作
		backtrack(需要搜索的集合,递归层数,状态变量1,状态变量2,...,结果集)
		对状态变量状态变量 1, 状态变量 2 的操作(即重置状态变量)
		

模板中所谓的backtrack即回溯,从上面的框架不难看出,回溯主要包括三部分:DFS即深度优先遍历,状态变量,剪枝。

当某个结点有多个路径可以走的时候,一般使用循环结构。当程序递归到底返回到原来执行的结点时,“状态”以及与“状态”相关的变量需要“重置”成第 1 次走到这个结点的状态,这个操作有个形象的名字,叫“回溯”,“回溯”有“恢复现场”的意思:意即“回到当时的场景,已经走过了一条路,尝试走下一条路”。

状态通常是一个列表结构,因为一层一层递归下去,需要在列表的末尾追加,而返回到上一层递归结构,需要“状态重置”,因此要把列表的末尾的元素移除,符合这个性质的列表结构就是“栈”(只在一头操作)。

当我们明确知道一条路走不通的时候,例如通过一些逻辑计算可以推测某一个分支不能搜索到符合题意的结果,可以在循环中 continue 掉,这一步操作叫“剪枝”。“剪枝”的意义在于让程序尽量不要执行到更深的递归结构中,而又不遗漏符合题意的解。因为搜索的时间复杂度很高,“剪枝”操作得好的话,能大大提高程序的执行效率。



版权声明:本文为bitcarmanlee原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。