Ruby:堆栈级别太深(SystemStackError)实现具有反转计数的合并排序

时间:2012-03-21 20:18:21

标签: ruby mergesort

这是我的代码。

@@inversions = 0
numbers = [very big array]

def merge_sort(array)
  return array if array.size <= 1

  left = array.slice(0, (array.size / 2).round)
  right = array - left
  merge(merge_sort(left), merge_sort(right))
end

def merge(left, right)
  return right if left.empty? # crashes here with stack level too deep
  return left if right.empty?

  if left.first <= right.first
    [left.first] + merge(left[1..-1], right)
  else
    @@inversions += left.size
    [right.first] + merge(left, right[1..-1])
  end
end

你能说出它失败的原因吗? (适用于小于~15000大小的数组)

2 个答案:

答案 0 :(得分:3)

您的递归合并功能可能就是原因。对于数组中的每个元素,您在堆栈中更深一层。标准合并排序不应该比lg(N)更深。尝试重写merge是迭代的而不是递归的。

这样的东西
def merge left,right
  a = []
  while !left.empty? and !right.empty?
    if left.first < right.first
       a<<left.shift
    else 
       a<<right.shift
    end
  end
  a + left + right
end

答案 1 :(得分:0)

你跑出了堆栈室 - 显然 - 但我认为你需要知道这意味着什么所以这里有一些理论。我的基础是古老的'汇编',但这是一般问题。

在计算机体系结构中,芯片的一个区域专用于“堆栈”,通常是LIFO(后进先出)'暂存器'。数据被“推送”并“弹出”进入和离开堆栈有时会自动进行,有时也会被程序员选择。

这个堆栈有一个有限的长度(在溢出这个堆栈的* 86中覆盖了芯片的其他特殊区域(EIP),这是改变程序流控制的经典黑客技术,但无论如何......

在你的程序中,每次递归或方法调用发生时,堆栈都会加载调用代码的返回地址(因此它可以返回并继续)。这就是导致堆栈溢出的原因。