【问题标题】:Removing recursion from inside of a loop从循环内部删除递归
【发布时间】:2015-07-21 06:46:41
【问题描述】:

给定的代码看起来像这样(伪代码):

f(args)
    result = simple_case
    if (base_case(args))
        return result
    new_args = args
    for each x in args list
        remove x from new_args
        if (need_to_update_result_based_on_x(result,x))         
            result = f(new_args)
    return result

我已经知道如何从函数中删除尾递归,但我不确定是否有直接的技术可以删除本身位于循环内部的递归,如上所述。

特别是,我特别想知道是否可以重写它以使其纯粹迭代?我的意思是它甚至不需要通过简单地实现它自己的堆栈来有效地模拟递归设计?如果不是,那么重写此类函数通常最经济(就存储和时间而言)的方式是什么?

【问题讨论】:

  • simple_case 是常量吗?
  • 在递归部分,您将f(new_args) 分配给result - 您确定您的意图不是以某种方式聚合结果吗?
  • 不是,但它是从 args 中的前 k 个条目派生而来的,并且 k 是常数。
  • 如果不使用额外的 O(args.length) 内存(它可能是单独的堆栈或每个 args[i] 的未使用字段),不可能以纯迭代方式重写此代码。
  • 请给出评估信息:1)需要多少字节来存储result,2)需要多少字节来存储一个参数args[i],3)列表中有多少参数@ 987654327@, 4)need_to_update_result_based_on_x(result,x)返回true的概率是多少?

标签: recursion memoization


【解决方案1】:

函数中 for 循环的每次迭代都会减少 args 列表,并且减少的列表也会传递给下一个递归调用。因此,当递归调用返回时,循环会使用它在进行递归调用时拥有的列表,但递归调用本身已经为该列表的简化版本计算出结果。

为避免重做已经完成的工作,您可以缓存先前递归调用的结果,以便将来的递归调用无需重做完整的计算。这种技术通常被称为 memoization

因此,要完全消除递归,可以预先计算基本案例结果并记住(记忆)。这些记忆可用于计算基本情况加上列表中的其他参数之一的结果,并且这些结果也被记忆(此时,基本情况结果可以被丢弃)。您可以为每个连续较大的列表大小重复计算记忆,直到获得所需参数列表的结果。

【讨论】:

  • 要扩展该答案,您还可以从后面开始计算结果(意思是,首先计算最后一个参数,然后是最后两个参数,依此类推)并缓存这些结果 - 这样你可以完全跳过递归。
  • @CptBartender:谢谢,相应地扩展了答案。
  • @CptBartender:你能详细说明我将如何重写函数来做这样的事情吗?
  • 请参阅@jxh 的更新答案 - 它很好地涵盖了这方面。
猜你喜欢
  • 2021-10-21
  • 2019-07-10
  • 1970-01-01
  • 2021-10-20
  • 1970-01-01
  • 2014-06-30
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
相关资源
最近更新 更多