我面临一个问题,即递归和使用循环似乎都是自然的解决方案.对于像这样的案件,是否有惯例或"首选方法"?(显然它不像下面那么简单)
Item Search(string desired, Scope scope) {
foreach(Item item in scope.items)
if(item.name == desired)
return item;
return scope.Parent ? Search(desired, scope.Parent) : null;
}
Run Code Online (Sandbox Code Playgroud)
Item Search(string desired, Scope scope) {
for(Scope cur = scope; cur != null; cur = cur.Parent)
foreach(Item item in cur.items)
if(item.name == desired)
return item;
return null;
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*lla 56
我赞成递归解决方案:
递归的实现比迭代解决方案简单得多,通常是因为它以迭代方法不能的方式利用问题的结构方面
我可以合理地确定递归的深度不会导致堆栈溢出,假设我们正在谈论以这种方式实现递归的语言
条件1似乎不是这里的情况.迭代解决方案的复杂程度大致相同,因此我坚持使用迭代路由.
RBe*_*eig 28
如果绩效很重要,那么对两者进行基准测试并在合理的基础上进 如果没有,则根据复杂性进行选择,并考虑可能的堆栈溢出.
经典着作"编程风格的元素"(由Kernighan和Plauger 撰写)有一个指南,即算法应遵循数据结构.也就是说,递归结构通常使用递归算法更清晰地处理.
Tyl*_*nry 19
递归用于表示以更容易理解的形式自然递归的算法."自然递归"算法是这样一种算法,其中答案是根据较小子问题的答案构建的,这些子问题又是根据较小的子问题的答案等构建的.例如,计算因子.
在一种不起作用的编程语言中,迭代方法几乎总是比递归方法更快,更有效,因此使用递归的原因是清晰度,而不是速度.如果递归实现最终不如迭代实现那么清晰,那么一定要避免它.
在这种特殊情况下,我会判断迭代实现更清晰.
And*_*per 13
好吧,我看到了大量的答案,甚至接受了答案,但从未看到正确的答案,并在想为什么......
\n\n长话短说 :
\n\n如果您可以通过循环生成相同的单元,请始终避免递归!
\n\n递归是如何工作的?
\n\n\xe2\x80\xa2 堆栈内存中的帧被分配给单个函数调用
\n\n\xe2\x80\xa2 框架包含对实际方法的引用
\n\n\xe2\x80\xa2 如果方法有对象,则对象将被放入堆内存中,并且 Frame 将包含对堆内存中该对象的引用。
\n\n\xe2\x80\xa2 这些步骤是为每个方法调用完成的!
\n\n风险:
\n\n\xe2\x80\xa2 当堆栈没有内存来放置新的递归方法时,StackOverFlow。
\n\n\xe2\x80\xa2 OutOfMemory 当堆没有内存来放置递归存储对象时。
\n\n循环如何工作?
\n\n\xe2\x80\xa2 之前的所有步骤,除了循环内重复执行代码将不会消耗任何进一步的数据(如果已消耗)。
\n\n风险:
\n\n\xe2\x80\xa2 当你的条件永远不会存在时,单一风险存在于 while 循环内...\n好吧,这不会导致任何崩溃或其他任何事情,如果你天真地这样做,它只是不会退出循环while(true): )
测试:
\n\n在您的软件中执行下一步:
\n\nprivate Integer someFunction(){\n\nreturn someFunction();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n你StackOverFlow很快就会得到例外,也许OutOfMemory也是
做第二件事:
\n\nwhile(true){\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\n软件只会冻结,不会发生崩溃:
\n\n最后但并非最不重要的 - for循环:
总是使用for循环,因为这样或那样的循环会迫使你给出一个断点,超过这个点循环就不会继续,当然你可能会非常生气,然后找到一种方法让循环永远不会for停止,但我建议你这样做为了内存管理和提高软件的生产力,始终使用循环而不是递归,这是当今的一个大问题。
参考:
\n\n\n如果您使用的是函数式语言(似乎不是这样),请使用递归.如果没有,那么在项目中工作的其他人可能会更好地理解循环.当然,某些任务(如递归搜索目录)比其他任务更适合递归.
此外,如果代码无法针对尾端递归进行优化,则循环更安全.
可以证明,所有尾递归算法都可以展开成一个循环,反之亦然。一般来说,递归算法的递归实现比循环实现更容易让程序员遵循,也更容易调试。同样一般来说,循环实现的实际性能会更快,因为循环中的分支/跳转通常比推送和弹出堆栈帧执行得更快。
就个人而言,对于尾递归算法,除了性能最密集的情况外,我更喜欢在所有情况下坚持使用递归实现。