【アルゴリズム】【Ruby】ソートのいろいろ ~むちゃ遅いクイックソート
計算量って知ってる? バブルソートって遅いよねっていうのは、 エクレアってデザートよねってくらいに常識かな。。ほんまに。
っていう師匠からの小言に対処すべく、
アルゴリズムを分かろう:その2、スタートです。
詳細はこちら
クイックソートとは
ピボットとして一つ選びそれをPとする。
http://ja.wikipedia.org/wiki/%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88
左から順に値を調べ、P以上のものを見つけたらその位置をiとする。
右から順に値を調べ、P以下のものを見つけたらその位置をjとする。
iがjより左にあるのならばその二つの位置を入れ替え、2に戻る。ただし、次の2での探索はiの一つ右、次の3での探索はjの一つ左から行う。
2に戻らなかった場合、iの左側を境界に分割を行って2つの領域に分け、そのそれぞれに対して再帰的に1からの手順を行う。要素数が1以下の領域ができた場合、その領域は確定とする。
よし。実装してみよう
いけてないコード
実装してみたものの、ありえないくらい処理が遅い。
コードも複雑で、いけてない感ぷんぷん。
a = (0..10).to_a a = a.sample(a.length) p a start_time = Time.now def q_sort(a, pipot=nil) return a if a.size == 1 if pipot == nil then pipot = a[a.size/2.ceil] end i = 0 while i < a.size if a[i] >= pipot then j = a.size-1 while j >= 0 if a[j] <= pipot then if i < j then a[i], a[j] = a[j], a[i] if i +1 == j then a[0...i] = q_sort(a[0...i]) a[i...a.size] = q_sort(a[i...a.size]) else q_sort(a[i+1 ... j-1], pipot) end else a[0...i] = q_sort(a[0...i]) a[i...a.size] = q_sort(a[i...a.size]) end end j -= 1 end end i += 1 end a end q_sort(a) end_time = Time.now p a p ("timeee " + (end_time - start_time).to_s + "s" )
■実行結果
[0, 10, 8, 1, 3, 9, 2, 4, 5, 6, 7] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] "timeee 38.522204s"
やっば。まじやっば。。
10個のソートに38秒って一体。。。
アルゴリズムって作った人の知性を如実に反映するね・・・
まあでも頑張ったので、師匠にコードを送ってみた。
ごめんなさい、このこーどを読む気がおきません。。。 てか、38秒って遅すぎる
38秒が遅いって、そりゃ私でも分かるわ!
コードがイケてないのは私が1番知ってるわ!
って、師匠に怒るのは間違いです。
自分の知能の至らなさが本質なのです。
Wikiの答え
wiki のサンプルを見てRubyで実装してみる
a = (0..10).to_a a = a.sample(a.length) p a start_time = Time.now def q_sort(a, left, right) return a if left >= right pivot = a[((left + right).to_f/2.to_f).ceil] i = left j = right while true i += 1 while a[i] < pivot j -= 1 while a[j] > pivot break if (i >= j) a[i], a[j] = a[j], a[i] i += 1 j -= 1 end q_sort(a, left, i-1) q_sort(a, i, right) a end q_sort(a,0,a.size - 1) end_time = Time.now p a p ("timeee " + (end_time - start_time).to_s + "s" )
■実行結果
[0, 5, 9, 2, 10, 1, 3, 4, 7, 8, 6] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] "timeee 0.0s"
やばい!
38秒⇒0秒に!
何がいけてなかったのか
自分のコードのどこがいけてなかったのか考察してみる
while文がいけてない
while i < a.size if a[i] >= pipot then
これ、一文で書ける。ネストが浅くなる。
while a[i] < pipot
while文は使いなれてない。ちゃんと慣れよう。。
メモリを使いまくってた
def q_sort(a, pipot=nil) ・・・ q_sort(a[i...a.size]) q_sort(a[i+1 ... j-1], pipot)
とか書いてた。
これって、配列を部分的に取り出すたび、
新しい配列を作成しているので、恐ろしくイケテない処理になってる。
クイックソート終わり。。
の前に
公式ガイド:制御構造をちゃんと理解する。