# sort.rb
class Array
def insertion
(1..self.count).each do |i|
(i..0).each do |j|
first = j - 1
second = j
if self[second] > self[first]
swap(second, first)
end
end
end
self
end
def mergesort
return self if self.size <= 1
mid = self.size / 2
left = self[0, mid]
right = self[mid, self.size-mid]
merge_array(left.mergesort, right.mergesort)
end
# helpers
def merge_array(left, right)
sorted = []
until left.empty? or right.empty?
if left.first <= right.first
sorted << left.shift
else
sorted << right.shift
end
end
sorted.concat(left).concat(right)
end
def swap(previous, current)
copy = self[previous]
self[previous] = self[current]
self[current] = copy
end
end
我的rspec文件:
require './sort'
unsorted = 5000.downto(1).to_a.shuffle
describe Array, "#insertion" do
it "sorts using insertion sort" do
time = Time.now
unsorted.insertion.should eq(unsorted.sort)
puts "insertion"
puts Time.now - time
end
end
describe Array, "#merge" do
it "sorts using merge sort" do
time = Time.now
unsorted.mergesort.should eq(unsorted.sort)
puts "merge"
puts Time.now - time
end
end
我们知道插入排序应该比合并排序慢,因为插入排序的运行时平均为O(n ^ 2),而合并排序为O(n * log(n))。但是,当我运行上面的测试代码时,merge比插入慢10倍。
insertion 0.001294 seconds .merge 0.017322 seconds
我的猜测是我使用了一些计算成本较高的方法,例如shift
和concat
,但相差10倍太过分了。
如何改进合并排序?
答案 0 :(得分:8)
这里有很多东西:
(i..0).each
什么都不做,因为范围不能以相反的顺序排列(你的规范没有通过)。请改用downto
。self[a], self[b] = self[b], self[a]
简化交换方法。first
,second
,previous
,next
都令人困惑。他们的名字暗示他们是元素,但实际上他们是索引,我会重命名为index1
(可能是first_index
,但这可能会变得冗长。)count
和size
之间切换?这令人困惑,让它看起来像你复制并粘贴了其他人的代码(事实上,其中一个函数改变了数组而另一个函数没有,一般来说,合并排序看起来像是由知道的人编写的他们正在做什么,“插入”排序没有。)dup
数组然后根据开始和结束索引对其进行排序。bmbm
试图最小化这些差异。unsorted.insertion.should eq(unsorted.sort)
内运行测试,所以你不仅要计算你的排序,你还要计算Ruby的unsorted.sort
以及RSpec断言。最好将排序包装在计时代码中,然后输出结果。答案 1 :(得分:4)
思路: