有两种实现 DFS
的方法。
dfs递归模版
第一种方法是进行递归:
boolean DFS(Node cur, Node target, Set<Node> visited) {
return true if cur is target;
for (next : each neighbor of cur) {
if (next is not in visited) {
add next to visted;
return true if DFS(next, target, visited) == true;
}
}
return false;
}
12345678910
当我们递归地实现 DFS
时,似乎不需要使用任何栈。但实际上,我们使用的是由系统提供的隐式栈,也称为调用栈(Call Stack)。
dfs显式栈模板
递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS
,或使用 显式栈 实现 DFS
。
boolean DFS(int root, int target) {
Set<Node> visited;
Stack<Node> s;
add root to s;
while (s is not empty) {
Node cur = the top element in s;
return true if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in visited) {
add next to s;
add next to visited;
}
}
remove cur from s;
}
return false;
}
dfs显式栈的问题
当在遍历过程中需要传递一些额外的信息时,会比较麻烦。
比如返回一条深度优先搜索的路径(从根开始直到某个结点):
-
如果用递归实现,可以每次通过递归函数的参数来传递一些额外的信息,比如list。在递归调用后,可以再调用list.remove()将list的状态回溯。这样在任意深度的地方都可以很方便得到一个属于该层状态的list,比如深度优先搜索的路径。
-
如果用显示栈实现,那么会面临问题:
如何在栈中保存状态相关的变量?
一种思路是可以通过对象包裹后传递给栈,每次从栈中读取相关的信息。但是这样明显带来了额外的对象创建开销,对于比较小的变量尚可接受,对于比较大的对象、或者参数比较多的情况就会显得比较麻烦。