ruby中的尾递归 - 这两个实现之间有什么区别?

时间:2011-05-23 20:38:54

标签: ruby quicksort tail-recursion

我是Ruby的新手,几天前就开始学习语言了。作为练习,我尝试实现一个简单的快速排序

class Sort
  def swap(i,j)
    @data[i], @data[j] = @data[j], @data[i]
  end

  def quicksort(lower=0, upper = @data.length - 1)
    return nil if lower >= upper
    m = lower
    i = 0
    ((lower+1)..upper).each do |i|
      swap(++m, i) if @data[i] < @data[lower]
    end

    swap(m, lower)

    quicksort1(lower, m -1)
    quicksort1(m+1, upper)
  end
end

在10000个整数上调用quicksort会给出堆栈级错误。在谷歌搜索之后,我发现在Ruby(kind of)中还不支持尾递归。但后来我找到了以下代码段(来自here

def qs(v)
  return v if v.nil? or v.length <= 1
  less, more = v[1..-1].partition { |i| i < v[0] }
  qs(less) + [v[0]] + qs(more)
end

即使有一百万个整数,运行第二个代码段也能很好地运行。然而,就我所知,最后有尾递归。那我在这里不明白了什么?

1 个答案:

答案 0 :(得分:9)

你所展示的方法都不是尾递归的(技术上,第一个是半尾递归:第二个递归调用是尾调用,但第一个不是 - 第二个方法不是尾递归的全部)。

第一个方法溢出堆栈的原因,但第二个方法不是因为一个错误(++m只应用了一元,第一个方法比第二个方法更深地递归(线性而不是对数) +运算符到m两次 - 它实际上并没有对m执行任何操作。

当给定足够大的数组时,两个版本都会溢出(即使ruby执行了TCO也会这样做),但没有错误,10000个元素就不够大了。

相关问题