Javascript 返回函数调用与在递归期间仅再次调用函数有什么区别?
我正在尝试实现DFS,但我不理解在其内部调用函数(递归)和返回函数调用(也是递归?)之间的区别Javascript 返回函数调用与在递归期间仅再次调用函数有什么区别?,javascript,algorithm,recursion,return,depth-first-search,Javascript,Algorithm,Recursion,Return,Depth First Search,我正在尝试实现DFS,但我不理解在其内部调用函数(递归)和返回函数调用(也是递归?)之间的区别 代码片段1:返回函数调用(回答错误) 在这种情况下,代码没有正确回溯 const图={ 1: [2, 3], 2: [4, 5], 3: [1], 4: [2, 6], 5: [2, 6], 6: [4, 5] } 让我们访问=[]; 常量dfs=(节点)=>{ if(已访问。包括(节点)) 返回; console.log(节点); 访问推送(节点); for(设i=0;i[ 节点, …(图形[节点
代码片段1:返回函数调用(回答错误)
在这种情况下,代码没有正确回溯
const图={
1: [2, 3],
2: [4, 5],
3: [1],
4: [2, 6],
5: [2, 6],
6: [4, 5]
}
让我们访问=[];
常量dfs=(节点)=>{
if(已访问。包括(节点))
返回;
console.log(节点);
访问推送(节点);
for(设i=0;i当您返回“函数调用”时,实际上是返回被调用函数产生的值。当您只是递归调用一个函数而不返回它时,您不会对返回值做任何事情。它们都是递归的情况,当不在循环中时,它们的工作方式类似
在本例中,由于您正在for循环中使用函数的返回值,因此一旦dfs(graph[node][i])
第一次运行,并且函数通过返回值完成执行(或者像在本例中一样刚刚完成执行)并退出堆栈调用,for循环结束,函数执行也会停止。在编程术语中,递归函数可以定义为直接或间接调用自身的例程。因此在您的示例中,这两种函数都被视为递归
但是,当考虑到递归原理是基于这样一个事实,即一个更大的问题是通过重复使用子集问题的解来解决的,那么我们将需要这些子集结果来计算大的结果。如果没有这种回报,你只会得到一个未定义的结果,这无助于你解决问题
一个非常简单的例子是阶乘,其中fact(n)=n*fact(n-1)
正如您在本例中看到的,事实(4)=4*fact(3),如果没有返回,它将是未定义的
注意:在您的示例中,不调用返回可能会起作用,因为我们没有重新使用子集的结果如果您编写避免改变外部状态的函数,而是对提供的参数进行操作,那么您会遇到更少的麻烦。下面我们用三个参数编写了dfs
t
-输入树或图形
i
-开始遍历的id
s
-访问的节点集默认为新集
函数*dfs(t,i,s=新集合)
{如果(s.has(i))返回
s、 加(i)
产量一
对于(t[i]??[]的常数v)
收益率*dfs(t、v、s)
}
常数图=
{ 1: [2, 3]
, 2: [4, 5]
, 3: [1]
, 4: [2, 6]
, 5: [2, 6]
, 6: [4, 5]
}
for(dfs的常量节点(图1))
console.log(node)
其他人已经解释了为什么return
会使您的进程短路
但我认为主要的问题是,您并没有真正使用递归函数返回任何内容,而只是依赖于函数内部的副作用(打印到控制台)。若您真的想要遍历图形,那个么编写一个返回有序节点集合的函数会更简洁。Thankyou的答案提供了一个这样的函数,使用生成器函数,以及一些有价值的建议
下面是另一种方法,它将(连接的)图形转换为数组:
const dft=(图形、节点、已访问=新集合([node])=>[
节点,
…(图形[节点]).flatMap(
(n) =>visited.has(n)?[]:dft(图,n,visited.add(n))
)),
]
常量图={1:[2,3],2:[4,5],3:[1],4:[2,6],5:[2,6],6:[4,5]}
console.log(dft(graph,1))/~>[1,2,4,6,5,3]
您能解释一下为什么一个返回DFS的正确结果而另一个不返回吗?@HarshaLimaye当您从for循环中返回时,您会提前停止循环(当您退出函数返回调用方时),在第二个示例中,您不会返回,因此,您可以在循环调用dfs()
之后继续循环,这样如果我使用return语句正确,我的“循环”只运行一次?@HarshaLimaye是的,正确。在这种情况下,您可以使用forEach()
方法forEach()
不会使用return语句中断循环。如果它对你有用的话,快告诉我。我写的是一个非生成器方法,它的工作原理类似。类似于const dfs=(t,i,s=新集合([i])=>[i,…(t[i].flatMap((n)=>s.has(n)?[]:dfs(t,n,s.add(n))))]
。你仍然应该发布它!有些初学者很难使用生成器,所以看到其他方法会很有好处:DThanks,post!有趣的是,我经常写类似于dfs的dfs
的东西,以至于有时我忘记了它确切地指的是什么^ ^ ^@Thankyou:我相信这也是一个主要用于树的术语,而不是任意(双)图。它只能访问节点的子集。(例如,尝试从6
开始的任何一种解决方案。它只会产生[6,4,2,5]
)。
function fact (n) {
if (n===0 || n===1) return 1;
else return n*fact(n-1);
}