如何编写合并排序?

时间:2014-01-14 18:24:10

标签: ruby mergesort

我正在尝试实现合并排序,并且在运行代码时出现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]

任何帮助都会很棒!

5 个答案:

答案 0 :(得分:11)

写这个

 return lists if lists.count == 1

而不是

 lists if lists.count == 1

在Ruby中,默认情况下始终返回方法last语句。但是如果你想有条件地从除最后一行之外的任何行的中间返回,你必须明确地使用 return 关键字。

答案 1 :(得分:9)

来自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

答案 2 :(得分:1)

带注释的简化版

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

答案 3 :(得分:0)

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

var data = allReviews = [
  {"id": 1, "writer" : "John Joseph Doe", "review_id" : 4},
  {"id": 1, "writer" : "Daniel Smith", "review_id" : 4},
  {"id": 1, "writer" : "Thomas Edward Jones", "review_id" : 4},
  {"id": 2, "writer" : "Erin Davis", "review_id" : 5},
  {"id": 2, "writer" : "Jill Steinberg", "review_id" : 5},
  {"id": 2, "writer" : "Laurie Beth Jennings", "review_id" : 5},
  {"id": 3, "writer" : "Emma Jean Williams", "review_id" : 3},
  {"id": 3, "writer" : "Mary Joe Williams", "review_id" : 3},
  {"id": 3, "writer" : "Helen Andrews", "review_id" : 3},
  {"id": 3, "writer" : "Samantha Jones", "review_id" : 3}
];
var reviewsByBook = [];
allReviews.forEach(function(currReview) {
  var currReviewIsForNewBook = true;
  reviewsByBook.forEach(function(prevReviewsForThisBook) {
    if (currReview.id === prevReviewsForThisBook.id) {
      prevReviewsForThisBook.writer += ", " + currReview.writer;
      currReviewIsForNewBook = false;
    }
  });
  if (currReviewIsForNewBook) {
    reviewsByBook.push(currReview);
 }
});
console.log(reviewsByBook);

答案 4 :(得分:0)

试试这个:

def merge_arrays(left, right)
  sorted_array = []
  until left.empty? || right.empty?
    sorted_array << (left.first < right.first ? left.shift : right.shift)
  end
  sorted_array + left + right
end

def merge_sort(array)
  return array if array.size <= 1
  left = merge_sort array[0...(array.size / 2)]
  right = merge_sort array[(array.size / 2)...array.size]
  merge_arrays left, right
end

puts merge_sort Array.new(10) { rand(0...100) }