Algorithm 是否存在只有递归解决方案的问题?

Algorithm 是否存在只有递归解决方案的问题?,algorithm,recursion,Algorithm,Recursion,可能的重复项: 是否有一个问题只有一个递归解,也就是说,一个问题有一个递归解,但还没有找到迭代解,或者更好的是,它被证明是不存在的(显然,这不是尾部递归)?所有非np完全问题都可以通过顺序、决策和迭代来解决。递归不应该是必需的,尽管它通常会大大简化问题 将函数调用替换为将参数推到堆栈上,然后返回并弹出堆栈,这样就消除了递归 编辑:响应“使用堆栈不会减少空间成本” 如果递归算法可以在常量空间中运行,那么它可以以尾部递归的方式编写。如果它是以尾部递归格式编写的,那么任何合适的编译器都可以折叠堆

可能的重复项:



是否有一个问题只有一个递归解,也就是说,一个问题有一个递归解,但还没有找到迭代解,或者更好的是,它被证明是不存在的(显然,这不是尾部递归)?

所有非np完全问题都可以通过顺序、决策和迭代来解决。递归不应该是必需的,尽管它通常会大大简化问题

将函数调用替换为将参数推到堆栈上,然后返回并弹出堆栈,这样就消除了递归

编辑:响应“使用堆栈不会减少空间成本”

如果递归算法可以在常量空间中运行,那么它可以以尾部递归的方式编写。如果它是以尾部递归格式编写的,那么任何合适的编译器都可以折叠堆栈。然而,这意味着“convert function calls to explicit stack push”方法也需要常量空间。以阶乘为例

阶乘:

def fact_rec(n):
    ' Textbook Factorial function '
    if n < 2:  return 1
    else:      return n * f(n-1)


def f(n, product=1):
    ' Tail-recursive factorial function '
    if n < 2: return product
    else:     return f(n-1, product*n)

def f(n):
    ' explicit stack -- otherwise same as tail-recursive function '
    stack, product = [n], 1
    while len(stack):
        n = stack.pop()
        if n < 2: pass 
        else:
            stack.append(n-1)
            product *= n
    return product
def事实记录(n):
“阶乘函数”
如果n<2:返回1
其他:返回n*f(n-1)
def f(n,产品=1):
“尾部递归阶乘函数”
如果n<2:返回产品
其他:返回f(n-1,产品*n)
def f(n):
'显式堆栈--否则与尾部递归函数相同'
堆栈,乘积=[n],1
而len(堆栈):
n=stack.pop()
如果n<2:通过
其他:
stack.append(n-1)
乘积*=n
退货
由于stack.pop()在循环中跟随stack.append(),因此堆栈中的项不会超过一个,因此它满足了常量空间要求。如果您设想使用temp变量而不是1长度堆栈,它将成为标准的迭代阶乘算法


当然,有些递归函数不能用尾部递归格式编写。您仍然可以使用某种堆栈转换为迭代格式,但如果有任何关于空间复杂度的保证,我会感到惊讶。

这取决于解决问题需要多少行代码


列出C:\上的所有文件,使用递归,然后不使用。当然,您可以用两种方法来实现,但有一种方法更易于理解和调试。

否。递归只不过是一个堆栈,您可以通过显式实现堆栈来实现相同的结果

这可能不是一个特别令人满意的答案,但你必须问一个更具体的问题才能得到更好的答案。例如,理论表明,在计算级别上,如果使用while循环与仅使用(传统的)For循环,则可以解决的问题的范围有很大的不同


我把“传统”放在这里,因为它们实际上意味着循环迭代一定次数,而(…;…;…)循环的C风格是伪装的循环。

在编程中,递归实际上是迭代的一种特殊情况,即使用调用堆栈作为存储状态的特殊手段。您可以将任何递归方法重写为迭代方法。它可能更复杂,也可能不那么优雅,但它是等效的

在数学中,有些问题需要递归技术才能找到答案-一些例子是求根()、计算素数、图形优化等。然而,即使在这里,也只是一个如何区分术语“迭代”和“递归”的问题

编辑:正如其他人所指出的,存在许多定义为递归的函数,例如。然而,这并不意味着它们不能使用迭代构造进行计算——只要你有一个图灵完整的运算集和无限的内存。

没有递归就无法表达

编辑:如中所述,这是不正确的。

您可以定义一个没有递归的函数(对吗?),因此语言不需要递归。

作为对的响应,这是一个非常简单的将调用堆栈转换为实际堆栈的问题。这也显示了迭代版本的一个优点

在我的平台(Python3.1rc2/Vista32)上,迭代版本计算ack(3,7)=1021 fine,而递归版本堆栈溢出。注意:它在不同的机器上的python 2.6.2/Vista64上没有stackoverflow,因此它似乎相当依赖于平台

(社区wiki,因为这实际上是对另一个答案的注释[如果只有注释支持代码格式…)


这取决于你所说的递归。每个递归函数都可以通过实现堆栈转换为非递归函数..是;这里有详细的描述:@Marc gravel:太棒了@Marc Gravell:太棒了,我们可以在K&R中的递归索引中找到同样的东西。(索引引用了一堆页面和索引页面…)我认为这更多的是“迭代比递归糟糕的地方是否存在任何问题”,而不是“是否存在绝对需要递归的问题”这不是递归消除。当用非递归函数替换递归函数时,应该使用有限的内存,而不是理论上无限的堆栈。“保证使用有限的内存”不是非递归函数的定义。这可能是一个理想的属性,但不是一个定义要求。带有内存泄漏的迭代算法可能会使用无限量的内存,但没有人会认为单独使用它会使算法递归。@jia3ep:这是递归消除。事实上,通过将负载从操作系统的调用堆栈(在许多体系结构中,调用堆栈的空间有限)移动到堆中,并避免函数的开销,它在某些情况下已经有了明显的好处
def ack(m,n):
  s = [m]
  while len(s):
     m = s.pop()
     if m == 0:
        n += 1 
     elif n == 0:
        s.append(m-1)
        n = 1
     else:
        s.append(m-1)
        s.append(m)
        n -= 1
  return n