回溯尾递归算法可以转换为迭代吗?

Posted

技术标签:

【中文标题】回溯尾递归算法可以转换为迭代吗?【英文标题】:Can a backtracking tail recursive algorithm be converted to iteration? 【发布时间】:2012-11-26 18:08:21 【问题描述】:

让我们来看看骑士巡回赛的问题。那可以转换为迭代吗?让我困惑的是回溯部分。如何在循环中回溯?当我从递归到迭代时,我是否必须使用堆栈数据结构来实现回溯?


我在这里以更好的方式问了这个问题:Can someone describe through code a practical example of backtracking with iteration instead of recursion?

【问题讨论】:

【参考方案1】:

不,不可能。

所有递归算法都可以实现迭代,通过使用显式 LIFO 数据结构“模拟”递归。但这不会改变 算法 本身,即算法保持递归,而不是迭代。

同时,回溯是递归的固有属性。如果你有回溯,你就有递归。您可能知道,允许直接真正转换为迭代的一类算法是尾递归算法。但是回溯的存在立即意味着您的递归不是尾递归。

您可以做的是尝试发明一种不需要回溯的算法。当然,这将是一个完全不同的算法,而不是将原始递归算法转换为迭代形式。

【讨论】:

很少有人聪明到知道这些东西。在那一小群人中,很少有人会用简单的语言来表达。你是其中之一。谢谢!我可以说使用迭代+堆栈数据结构的回溯也是不可能的,换句话说,BACKTRACKING => RECURSION. 以下答案是否显示了尾递归和迭代版本的回溯算法? ***.com/questions/20514267/…【参考方案2】:

所有递归算法都可以转换为迭代算法,反之亦然。这是 Church-Turing 论文的直接结果。

它可能并不总是很明显(或微不足道),但任何算法都可以表示为递归或迭代过程;对于一般情况,这个问题已经回答了before。

至于如何,有几种技术可以应用于从一种风格到另一种风格,例如看看this 的答案,或者阅读更详细的讨论this 文章解释了如何使用堆栈来消除递归。

【讨论】:

“Church-Turing 论文的直接结果”是任何递归算法都允许迭代实现。它绝不声称任何递归算法都可以转换为迭代算法。而且,正确答案是否定的,一般是不可能的。了解算法与其实现之间的区别是这里的关键时刻。没有它,它只会变成一个无用的学术声明。【参考方案3】:

基本上,每个递归都可以实现为循环+堆栈,因为它基本上是在机器(硬件)级别上实现的——只是一堆分支和一个用于存储返回地址和参数的堆栈。

有一个在条件不满足时重复的循环,而不是递归调用 - 只需将下一次迭代(可能是最后一个状态)的参数推送到堆栈,然后返回到循环的起点.


编辑:(因为很明显你在谈论尾递归回溯,而不是简单的递归):

来自wikipedia:In computer science, a tail call is a subroutine call that happens inside another procedure as its final action。据我所知,具有多个递归调用的函数 - 根据定义不是尾递归,并且由于回溯算法确实有不止一个调用,因此它们不是“尾递归”。

还要注意 - 只有循环和恒定空间的程序可以转换为在多项式时间内运行的第二个程序 P'(因为最多有 2^CONST 状态,基本上是 CONST',并且验证每一个都是在多项式时间内完成的 - 所以总共是 CONST'*p(n) 时间,这仍然是多项式),所以 除非 P=NP,否则这是不可能的,因为它可以让我们解决 @987654323 @ 在多项式时间内通过将回溯解决方案转换为基于循环的多项式解决方案。 (而且我相信从HP 进一步减少是可行的,以表明无论如何都不可能)。

【讨论】:

我对 HOW 更感兴趣。 @chrisapotek:循环的第二部分回答了它是如何完成的 - 确切的细节取决于实现 - 但这是一般指导方针 - 只需将要搜索的下一个状态推送到堆栈, (在骑士之旅问题中,从每一步插入所有可能的新步骤进行搜索,并返回到循环的起点) @chrisapotek:我想我首先误解了你的真实意图。编辑是否更好地回答了您的问题?

以上是关于回溯尾递归算法可以转换为迭代吗?的主要内容,如果未能解决你的问题,请参考以下文章

递归如何转换为非递归

所有的迭代算法都可以递归表达吗?

递归转换为迭代的一种通用方式

有人可以帮助解释这个回溯算法中的递归吗?

聊聊算法——回溯算法

聊聊算法——回溯算法