From 8c39f11d63d9a696e7b1f0f54fa02d7927b70f0a Mon Sep 17 00:00:00 2001 From: v-log Date: Tue, 10 Apr 2018 10:41:45 +0300 Subject: [PATCH] Bottom-up mergesort implementation with tests --- RUBY/lib/2_2_merge_sort/merge_sort.rb | 118 +++++++++++------- .../tests/2_2_sort_algs/merge_sort_bu_test.rb | 10 ++ 2 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 RUBY/tests/2_2_sort_algs/merge_sort_bu_test.rb diff --git a/RUBY/lib/2_2_merge_sort/merge_sort.rb b/RUBY/lib/2_2_merge_sort/merge_sort.rb index 53c4bb6..85f252f 100644 --- a/RUBY/lib/2_2_merge_sort/merge_sort.rb +++ b/RUBY/lib/2_2_merge_sort/merge_sort.rb @@ -1,67 +1,95 @@ -def sorted?(a) - (0...a.size - 1).all? { |i| a[i] <= a[i + 1] } -end +module MergeSort + def sorted?(a) + (0...a.size - 1).all? { |i| a[i] <= a[i + 1] } + end + + def merge_sort!(a, &block) + return a if a.size <= 1 + aux = Array.new(a.size) -def merge_sort!(a, &block) - return a if a.size <= 1 - aux = Array.new(a.size) - if block_given? - merge_sort_hlpr!(a, 0, a.size - 1, aux, &block) - else - merge_sort_hlpr!(a, 0, a.size - 1, aux, &Proc.new {|x| x}) + if block_given? + merge_sort_hlpr!(a, 0, a.size - 1, aux, &block) + else + merge_sort_hlpr!(a, 0, a.size - 1, aux, &Proc.new { |x| x }) + end + a end - a -end -private + def merge_sort_bu!(a, &block) + return a if a.size <= 1 + n = a.length + aux = Array.new(n) + sz = 1 -def merge_sort_hlpr!(a, lo, hi, aux, &block) - if hi <= lo - return a + while sz < n do + 0.step(n - sz, 2 * sz) do |lo| + hi = less(lo + sz + sz - 1, n - 1) + if block_given? + merge!(a, lo, lo + sz - 1, hi, aux, &block) + else + merge!(a, lo, lo + sz - 1, hi, aux) { |x| x } + end + end + sz += sz + end + a end - mid = lo + (hi - lo)/2 - merge_sort_hlpr!(a, lo, mid, aux, &block) - merge_sort_hlpr!(a, mid + 1, hi, aux, &block) - merge!(a, lo, mid, hi, aux, &block) - a -end + private -def merge! (a, lo, mid, hi, aux, &block) - i = lo - j = mid + 1 - (lo..hi).each do |x| - aux[x] = a[x] + def less(a, b) + a < b ? a : b end - (lo..hi).each do |x| - if i > mid - a[x] = aux[j] - j += 1 - elsif j > hi - a[x] = aux[i] - i += 1 - elsif block.call(aux[j]) < block.call(aux[i]) - a[x] = aux[j] - j += 1 - else - a[x] = aux[i] - i += 1 + def merge_sort_hlpr!(a, lo, hi, aux, &block) + if hi <= lo + return a + end + + mid = lo + (hi - lo)/2 + merge_sort_hlpr!(a, lo, mid, aux, &block) + merge_sort_hlpr!(a, mid + 1, hi, aux, &block) + merge!(a, lo, mid, hi, aux, &block) + end + + def merge! (a, lo, mid, hi, aux, &block) + i = lo + j = mid + 1 + (lo..hi).each do |x| + aux[x] = a[x] + end + + (lo..hi).each do |x| + if i > mid + a[x] = aux[j] + j += 1 + elsif j > hi + a[x] = aux[i] + i += 1 + elsif block.call(aux[j]) < block.call(aux[i]) + a[x] = aux[j] + j += 1 + else + a[x] = aux[i] + i += 1 + end end end - a end +include MergeSort + a = (0..30).to_a.shuffle puts a.inspect puts sorted?(a) -merge_sort!(a) +#merge_sort!(a) +merge_sort_bu!(a) raise unless sorted?(a) puts "result:" + "\n" + a.inspect -puts sorted?(a).to_s +puts sorted?(a) puts b = [['Vasya', 1], ['Petya', 3], ['Kolya', 2]] puts b.inspect -merge_sort!(b) { |item| -item[1] } +#merge_sort!(b) { |item| -item[1] } +merge_sort_bu!(b) { |item| -item[1] } puts "result:" + "\n" + b.inspect # [["Petya", 3], ["Kolya", 2], ["Vasya", 1]] - diff --git a/RUBY/tests/2_2_sort_algs/merge_sort_bu_test.rb b/RUBY/tests/2_2_sort_algs/merge_sort_bu_test.rb new file mode 100644 index 0000000..4977dbb --- /dev/null +++ b/RUBY/tests/2_2_sort_algs/merge_sort_bu_test.rb @@ -0,0 +1,10 @@ +require_relative 'sort_test' +require_relative '../../lib/2_2_merge_sort/merge_sort' + +class MergeSortTest < Minitest::Test + include SortTestModule + + def sort!(a, &block) + merge_sort_bu!(a, &block) + end +end