LoginSignup
2
0

More than 5 years have passed since last update.

Rubyでソートアルゴリズム

Posted at

0.概要

ソートについて色々と調べた上で、クイックソートとヒープソートを実装した。

1.クイックソート

ピボットを基準として、値の大小で2つに分割していく方法。
O(n log n)で計算でき、他のソートと比べると高速なソート法。
ただし、データの並びやデータの数によって計算量が変化する。最悪計算量はO(n**2)となる。

実装は以下の通り。

quick_sort.rb
class Array
  def quick_sort
    return self if size <= 1
    pivot = choice_pivot
    smallers, biggers = partition { |item| item < pivot }
    push(pivot)
    smallers.quick_sort.concat([pivot]).concat(biggers.quick_sort)
  end

  def choice_pivot
    self[0] >= self[1] ? delete_at(0) : delete_at(1)
  end
end

ピボットの選択によって計算量が変わるらしく、今回は2つの数値からより大きいものをピボットにした。

2.ヒープソート

ヒープという木構造を構築すると、必ず根が最大の値になる。
これを利用してソートしていくのがヒープソート。
あまり実装例を見かけないので、チャレンジという意味も込めて試してみた。

実装は以下の通り。

heap_sort.rb
class Array
  def build_heap(arr)
    parent = (arr.length - 1) / 2
    node_cnt = parent

    until node_cnt < 0
      l_child = 2 * parent + 1
      r_child = l_child + 1

      if arr[r_child] && arr[r_child] >= arr[l_child] && arr[r_child] > arr[parent]
          arr.swap!(r_child, parent)
          parent = r_child
      elsif arr[l_child] && arr[l_child] > arr[parent]
          arr.swap!(l_child, parent)
          parent = l_child
      else
        node_cnt -= 1
        parent = node_cnt
      end
    end
    arr
  end

  def swap!(a, b)
    self[a], self[b] = self[b], self[a]
  end

  def heap_sort
    arr = self.dup
    res = []
    until arr.empty?
      heap = build_heap(arr)
      heap.swap!(-1, 0)
      res.unshift(heap.delete_at(-1))
    end
    res
  end
end

3.実行速度について

実行速度を測りたいという意図もあり、以下のテストコードを書いた。

quick_sort_test.rb
class QuickSortTest < Minitest::Test
  def setup
    num = 10000
    @arr = []
    num.times { @arr << rand(num)  }
  end

  def test_quick_sort
    assert_equal @arr.quick_sort, @arr.sort
    run_time = Benchmark.realtime { @arr.quick_sort }
    p run_time
  end
end
heap_sort_test.rb
class HeapSortTest < Minitest::Test
  def setup
    num = 10000
    @arr = []
    num.times { @arr << rand(num)  }
  end

  def test_quick_sort
    assert_equal @arr.heap_sort, @arr.sort
    run_time = Benchmark.realtime { @arr.heap_sort }
    p run_time
  end
end

結果は以下の通り。

クイックソート 0.029008000157773495
ヒープソート 4.9474329999648035

圧倒的にクイックソートのほうが速い...
ヒープソートも書き方を変えたらもっと速くなるのだろうか。

4.終わりに

アルゴリズムはほぼ未学習の状態だったので、よい勉強になった。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0