经典(基于递归)深度优先搜索比基于堆栈的DFS更高效的内存吗?

时间:2013-12-10 14:07:52

标签: algorithm search recursion depth-first-search

我正在查看@AndreyT对this问题的回答,我对经典DFS与基于堆栈的DFS的内存效率有疑问。参数是通过简单的堆栈到队列替换不能从BFS创建经典的回溯DFS。在通过堆栈到队列替换执行BFS到DFS时,会丢失传统DFS的空间效率。不是搜索算法专家(虽然我正在阅读它)我会假设这只是“真实的”并且随之而去。

然而,我的问题实际上是关于整体内存效率。虽然递归解决方案确实具有一定的代码效率(我可以通过几行递归搜索代码完成更多工作)和优雅,但它没有内存(可能性能)“点击”因为它是递归?

每次进入函数时,它都会将本地数据推送到堆栈,函数的返回地址以及编译器认为在返回时保持状态所需的其他内容等等。这可以快速加起来。它还必须为每个递归进行函数调用,这也会消耗一些操作(可能是次要的......或者它可能会破坏分支的可预测性,迫使管道冲洗......这里不是专家......随意帮腔)。

我想我现在想坚持简单的递归,而不是像这个问题的答案那样进入“替代形式”,如尾递归。至少现在。

1 个答案:

答案 0 :(得分:1)

虽然通过显式管理堆栈,可能比编译器做得更好,但奖励通常不值得额外工作。这些天编译器比很多人想象的要聪明得多。它们也不像其他人有时想的那么好 - 你把坏事带走了。

也就是说,大多数编译器都可以检测并删除尾递归。有些可以将简单的递归函数转换为迭代解决方案,而一些非常好的编译器可以确定可以重用局部变量。

递归解决方案通常会导致代码更小,这意味着代码更有可能适合CPU缓存。需要显式托管堆栈的非递归解决方案可能导致代码更大,缓存未命中,并且性能低于“慢速”递归解决方案。

最后,许多解决方案最直观地以递归方式实现,而这些解决方案往往简短易懂。将递归解决方案转换为涉及显式管理堆栈的迭代解决方案会导致更多行代码,这些代码通常模糊,易碎且难以证明是正确的。

我发现一个易于编码和理解的递归解决方案通常足够快,并且不会使用太多内存。在极少数情况下,分析显示我的递归实现是瓶颈(通常它是一个比较函数或类似于递归函数调用的东西),我会考虑一个非递归的解决方案。我不经常通过改变来获得显着的收益。