【问题标题】:Two recursive called no finish (Towers of Hanoi)两个递归称为没有完成(河内塔)
【发布时间】:2016-10-27 05:01:24
【问题描述】:

我在河内塔问题的 haskell 中编写了这个函数。该函数给出了从源棒到目标棒的步数,只有一根替代棒。

numStepsHanoi :: Integer -> Integer
numStepsHanoi 0 = 0
numStepsHanoi n = numStepsHanoi (n-1) + numStepsHanoi (n-1) + 1

这个功能可以正常工作...直到n,光盘的数量,变得太高。 GHCi 没有完成。我知道这个问题的复杂性,我知道它不能运行得更快。

例如,如果我用n = 64 调用它,我可以等待 20 分钟而没有输出(它没有完成)。即使n = 20,也需要大约2秒。

使用另一种实现(如下),时间大大减少。

numStepsHanoi :: Integer -> Integer
numStepsHanoi 0 = 0
numStepsHanoi n = 2 * numStepsHanoi (n-1) - 1

现在,使用n = 64,我可以立即得到结果。明明这只有一次递归调用,但是效果这么大吗?

这可能是 GHCi 优化的问题吗?

【问题讨论】:

  • GHCi 中不会进行任何优化,除此之外,GHC 编译器不会优化 x + x2 * x 之类的东西。后者比前者快得多的原因是您对第一个解决方案(指数)与第二个解决方案(线性)的复杂性有误。
  • @user2407038 我知道指数复杂度,但我认为 GHCi 将 x + x 转换为 2 * x。非常感谢!
  • 自动记忆(动态编程)在这里也有帮助,但用户仍然需要明确要求。 GHC 不会以这种方式优化事物。

标签: haskell recursion towers-of-hanoi


【解决方案1】:

我怀疑这实际上功能复杂性。您的第一个版本对每次调用进行 2 次递归调用,复杂度为 O(2^n)。对于 n=64,您总共拨打了 2^65 - 1 次电话。这大约是 37 * 10^18 次调用,因此在当前计算能力的情况下,您不会在此生命周期中看到结果。以每微秒一次调用计算,这仍然远远超过 1000 万年。

第二个例程每次迭代只调用一次;它是 O(n)

要查看效果,请尝试将您的第一个函数计时在 n = 19、20、21、22。这应该足以显示每个添加的光盘的 2 倍时间差。

【讨论】:

    【解决方案2】:

    如果您想保证应用它,标准建议似乎是自己进行公共子表达式优化。见https://wiki.haskell.org/GHC/FAQ#Does_GHC_do_common_subexpression_elimination.3F

    numStepsHanoi :: Integer -> Integer
    numStepsHanoi 0 = 0
    numStepsHanoi n = let steps = numStepsHanoi (n-1)
                      in steps + steps + 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 2013-08-28
      • 1970-01-01
      • 1970-01-01
      • 2017-02-04
      • 2016-01-27
      • 1970-01-01
      相关资源
      最近更新 更多