Ruby [算法讨论] 有关`迭代器' 与 `递归' 的替换.

zw963 · 2012年09月05日 · 最后由 zw963 回复于 2012年09月06日 · 4851 次阅读

直接上例子说话:

计算斐波纳契数的递归算法

def fib(n)
  return 0 if n == 0
  return 1 if n == 1
  return fib(n-2) + fib(n-1)
end

计算斐波纳契数的迭代器算法 (正是看到这个示例,深有感触)

def fib(n)
  a, b = 0, 1
  n.times do 
    a, b = b, a + b 
  end
  a
end

计算阶乘递归算法

def fac(n)
  return 1 if n == 1
  return n * fac(n-1)
end
def fac(n)
  (1..n).reduce(:*)
end

在没有学 Ruby 之前 (甚至在学了 Ruby 之后), 我仍然可能会习惯性的使用前者。

我想性能不用说了,递归的性能和迭代器那相差老远了去了!!

现在想讨论的问题是:

是不是所有的递归算法,都可以 (有一个途径) 使用迭代器进行替换?? (在 Ruby 语言下)

如果以上结论正确的话,那就是否就意味着下面的定律是成立的:

不要用递归, 他总可能成为你的项目的性能瓶颈

受 Erlang 的影响,个人比较倾向于使用递归,代码结构一般都比较清晰。不过也如你所言,在没有尾递归编译优化或者重叠子问题,递归不是一个好的选择。

http://stackoverflow.com/questions/72209/recursion-or-iteration 我喜欢这里的一句话 Loops may achieve a performance gain for your computer. Recursion may achieve a performance gain for your programmer. Choose which is more important in your situation!

http://stackoverflow.com/questions/72209/recursion-or-iteration 我喜欢这里的一句话 Loops may achieve a performance gain for your computer. Recursion may achieve a performance gain for your programmer. Choose which is more important in your situation!

http://stackoverflow.com/questions/72209/recursion-or-iteration 我喜欢这里的一句话 Loops may achieve a performance gain for your computer. Recursion may achieve a performance gain for your programmer. Choose which is more important in your situation!

http://stackoverflow.com/questions/72209/recursion-or-iteration 我喜欢这里的一句话 Loops may achieve a performance gain for your computer. Recursion may achieve a performance gain for your programmer. Choose which is more important in your situation!

我觉得这显然不成立,如果递归可以完全用迭代 (循环) 代替,那递归就不会成为一种经典算法了。这在任何语言都是一样的。不能被 ruby 优秀的语法糖给欺骗了。😊

有机械的方式将所有递归改写成循环,不过结果是在堆上分配一个栈,一些函数式语言就是这么做的,让你放心使用递归而无需担心栈溢出的问题。 某些不需要保存中间状态的递归可以改成不带栈的循环,有专门研究这个的。

做网站遇到的问题基本都有现成套路去搞... 没必要全递归或全不递归。 就算是没有循环结构的函数式语言也有仿造 foreach 和 while 的方案,怎么好理解就怎么写。

理论上(算法导论可以找到其说明),每种尾递归都可以用一个迭代过程来替换。

递归之所以经典,是因为可理解性与简洁性,即符合人类的思维,又与宇宙的递归设计层层相扣。

我以为,Ruby 里面大可以多用递归,符合它的设计哲学:For Funny.

第一个例子之所以性能差又不是递归导致的,是因为重复计算,第二个例子,用递归也没有太大性能问题。PS: 你说在没有学 Ruby 之前,你会用前一种算法,冒昧问一句你之前都是用什么语言编程的?

第一个例子之所以性能差又不是递归导致的,是因为重复计算,第二个例子,用递归也没有太大性能问题。PS: 你说在没有学 Ruby 之前,你会用前一种算法,冒昧问一句你之前都是用什么语言编程的?

第一个例子之所以性能差又不是递归导致的,是因为重复计算,第二个例子,用递归也没有太大性能问题。PS: 你说在没有学 Ruby 之前,你会用前一种算法,冒昧问一句你之前都是用什么语言编程的?

只有原始递归才能转换为 O(n) 级别的运算,但是不能只从算法效率上看,需要看应用场景和易读性。 比如 fib 来说,可以用矩阵计算达到 O(lg(n))

require 'matrix'
M = Matrix[[1,1],[1,0]]
def fib(n)
  (M**(n-1))[0,0]
end

但是在 n 较小的情况下,还不如直接递归+Memorization 来得性能好和容易理解

如果需要不用递归来提高性能的话,不如说不要用 ruby 了

赞同 #10 楼 @Alexander ,无副作用的递归算法一般会更容易加缓存的。

#3 楼 @reus

嗯。这话有道理呀。

#10 楼 @Alexander

谢谢指正,之前的确没有注意到重复调用的问题,原来我之前对于递归的误会还是蛮大的. 之前用过 Pascal.

不过,性能上还是后者好一些. #13 楼 @quakewang 👍 牛呀~ 不过,说实话我看不懂。我想搞 Rails 还了解这玩意儿的程序员,少之又少了吧. 当年,数学也算是俺绝对强项,可惜荒废了呀。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号