【问题标题】:How do I write a merge sort?如何编写合并排序?
【发布时间】:2014-02-02 22:58:10
【问题描述】:

我正在尝试实现合并排序,但在运行代码时出现stack level too deep (SystemStackError) 错误。我不确定可能是什么问题。

def merge_sort(lists)
  lists if lists.count == 1

  middle  = lists[0..(lists.count / 2) - 1 ]
  left = lists[0..middle.count - 1]
  right = lists[middle.count..lists.count]

  x = merge_sort(left)
  y = merge_sort(right)
end

merge_sort [1,2,3,4,5,6,7,8]

任何帮助都会很棒!

【问题讨论】:

  • 你在lists if lists.count == 1之前忘记了return

标签: ruby mergesort


【解决方案1】:

来自wikipedia

def mergesort(list)
  return list if list.size <= 1
  mid   = list.size / 2
  left  = list[0...mid]
  right = list[mid...list.size]
  merge(mergesort(left), mergesort(right))
end

def merge(left, right)
  sorted = []
  until left.empty? || right.empty?
    if left.first <= right.first
      sorted << left.shift
    else
      sorted << right.shift
    end
  end
  sorted.concat(left).concat(right)
end

【讨论】:

  • Fwiw,OP 的实现问题不仅仅是在基本情况下缺少return 语句,任何合理的合并排序实现都会有两个功能,一个是划分,一个是重组。
【解决方案2】:

写这个

 return lists if lists.count == 1

而不是

 lists if lists.count == 1

在 Ruby 中,默认情况下总是从方法返回最后一条语句。但是如果要有条件地从除最后一行之外的任何行的中间返回,则必须显式使用 return 关键字。

【讨论】:

    【解决方案3】:

    带有 cmets 的简化版本

    def merge_sort(arr)
      # 0. Base case
      return arr if arr.length <= 1
    
      # 1. Divide
      mid = arr.length / 2
      arr0 = merge_sort(arr[0, mid])
      arr1 = merge_sort(arr[mid, arr.length])
    
      # 2. Conquer
      output = merge(arr0, arr1)
    end
    
    def merge(l, r)
      output = []
      until l.empty? || r.empty?
        output << if l.first <= r.first
                    l.shift
                  else
                    r.shift
                  end
      end
      # The order of `concat(l)` or `concat(r)` does not matters
      output.concat(l).concat(r)
    end
    

    https://www.khanacademy.org/computing/computer-science/algorithms/merge-sort/a/divide-and-conquer-algorithms

    【讨论】:

      【解决方案4】:

      这是一个很好的方法。一开始有点棘手,但请坚持下去。

      def merge_sort list
        if list.length <= 1
          list
        else
          mid = (list.length / 2).floor
          left = merge_sort(list[0..mid - 1])
          right = merge_sort(list[mid..list.length])
          merge(left, right)
        end 
      end 
      
      def merge(left, right)
        if left.empty?
          right
        elsif right.empty?
          left
        elsif left.first < right.first
          [left.first] + merge(left[1..left.length], right)
        else
          [right.first] + merge(left, right[1..right.length])
        end
      end 
      

      【讨论】:

        猜你喜欢
        • 2012-04-08
        • 1970-01-01
        • 2018-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-29
        相关资源
        最近更新 更多