Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

高速なソートアルゴリズムを書こう!!

1,249 views

Published on

この資料は JJUG CCC 2017 Fall で発表した資料です。
以下の内容を扱います。
 ・クイックソートを高速化したアルゴリズム
 ・マージソートを高速化したアルゴリズム
 ・マージソートを省メモリ化したアルゴリズム

Published in: Technology
  • Be the first to comment

  • Be the first to like this

高速なソートアルゴリズムを書こう!!

  1. 1. 高速なソートアルゴリズムを 書こう!! 最速のソートアルゴリズムを目指して JJUG CCC 2017 Fall #ccc_m8 松原 正和 https://github.com/m-matsubara/sort
  2. 2. 松原正和 - 自己紹介 A5:SQL Mk-2の作者 ・SQL&ER図ツール 双子のパパ ・もうすぐ5歳 https://github.com/m-matsubara/sort https://a5m2.mmatsubara.com 本人
  3. 3. Java の標準ソートは Arrays.sort() メソッド ・プリミティブ(基本)型のソートは Dual-pivot quicksort ピボット値が2つあるクイックソート (非安定) ・オブジェクト型のソートはTimSort Tim Petersさんの書いた非再帰マージソート (安定) とりあえずは、比較ソートで。 基数ソートとかバケットソートと かは今回は考えないことにします。 https://github.com/m-matsubara/sort
  4. 4. 安定(Stable)ソートとは…おさらい 安定(Stable)ソートとは、ソートキーが同じ要素が複数あった場合、 元配列の出現順序が保たれるソートのこと。 安定なソート 非安定なソート 同じ身長同じ身長 同じ身長同じ身長 ソート前 ソート後 https://github.com/m-matsubara/sort
  5. 5. 速いソート・遅いソート ソートアルゴリズムの速い・遅いを語るときにビッグ・オー表記を用 いる。 遅いソート … O(N2) 要素数が10倍になると実行時間は100倍くらいになる。 アルゴリズムの例:バブルソート、選択ソート、挿入ソート 速いソート … O(N log N) log…ロガリズム(logarithm)…対数 要素数が10倍になっても実行時間は100倍までならない (10件から100件で20倍、10万件から100万件で12倍くらい) アルゴリズムの例:クイックソート、ヒープソート、マージソート N はソートの 要素数 https://github.com/m-matsubara/sort
  6. 6. 1.クイックソートを高速化するお話 https://github.com/m-matsubara/sort
  7. 7. クイックソートのおさらい(1/2) • 身長順に並べる ①ピボット値の選択 ②ピボット値以下を左に、ピボット値以上を右に集める 配列 ピボット!! 小さいサブリスト 配列 大きいサブリスト https://github.com/m-matsubara/sort
  8. 8. クイックソートのおさらい(2/2) ③小さいサブリスト・大きいサブリストそれぞれで再度ピボット値 を決め、さらに小さいサブリスト・大きいサブリストを作っていく …これを繰り返す。 配列 こっちも繰り返す! https://github.com/m-matsubara/sort
  9. 9. Dual-pivot Quicksortをベースに 安定ソート化!! mmsSort (matsubara masakazu stable Sort) ① ピボット値を2つにする ② マージソートのように外部メモリを使うことで安定ソート化 ③ 場合によっては3-way partition Quicksortに切り替え ④ CPUキャッシュを有効活用 https://github.com/m-matsubara/sort
  10. 10. ① ピボット値を2つに 再帰の深さが約2/3になる。CPUキャッシュも効果的に利用できる。 配列 ※ピボット値の選び方 1) 配列中から8個候補を選ぶ 2) 候補をソート 3) 3番目と6番目の要素を ピボット値として選ぶ pivot1 比較回数が減るわ けではない。 https://github.com/m-matsubara/sort pivot2
  11. 11. 配列の先頭からピボット1・ピボット2と比較してパーティション 操作する。 配列 ② マージソートのように外部メモリを 使うことで安定ソート化(1/2) ワーク メモリ pivot1 < 値 < pivot2 pivot2 ≦ 値 (作業領域に後ろから詰めていく)(作業領域に前から詰めていく) 値 ≦ pivot1 配列と同じサイズの 外部メモリが必要 https://github.com/m-matsubara/sort
  12. 12. ワークメモリから元の配列に書き戻す。 配列 ワーク メモリ ② マージソートのように外部メモリを 使うことで安定ソート化(2/2) コピー 反転コピー pivot2 ≦ 値値 ≦ pivot1 pivot1 < 値 < pivot2 pivot1 < 値 < pivot2 pivot2 ≦ 値 https://github.com/m-matsubara/sort
  13. 13. ③ 場合によっては 3-way partition Quicksortに切り替え 選んだPivot1とPivot2が等しいとき… →ピボット値未満・ピボット値と等しい・ピボット値より大きい の3つに分ける →ピボット値と等しいグループは再帰不要 再帰でソート 再帰でソートソート 要らない 配列 pivot < 値値 < pivot 値 = pivot https://github.com/m-matsubara/sort
  14. 14. ④ CPUキャッシュを有効活用 →先頭から分割操作したとき、後ろ側のサブリストから再帰すると ちょっと速い ①最初に 再帰ソート ②次に 再帰ソート ③最後に 再帰ソート 分割操作では配列の先頭から値を詰めていく。 再帰の処理は後ろのサブリストから処理する。 配列 pivot2 ≦ 値値 ≦ pivot1 pivot1 < 値 < pivot2 https://github.com/m-matsubara/sort
  15. 15. 2.マージソートを高速化するお話 https://github.com/m-matsubara/sort
  16. 16. マージソートのおさらい(1/2) • 身長順に並べる ①配列を半分ずつに分割し、各々ソート(マージソート)しておく。 ②配列の前半をワークメモリに移動する。 配列 配列 ワーク メモリ 何か騙され た気持ちに なる。 配列の半分のワークメモリが必要。 https://github.com/m-matsubara/sort
  17. 17. マージソートのおさらい(2/2) ③マージを行う。 配列 ワーク メモリ https://github.com/m-matsubara/sort
  18. 18. 3-way Mergesortの少し変わった実装(1/2) 一般的なオンメモリマージソートは2分割する実装が多いけど、3 分割とかすれば速くならない? …まじめに書くと意外と面倒、ヒープやトーナメントツリーを用い て実装される。 トーナメントツリーの場合 5 3 6 3 どのサブリスト(の先頭) から値を取り出すか管理 しなければならない。 https://github.com/m-matsubara/sort
  19. 19. 3-way Mergesortの少し変わった実装(2/2) MasSort (Masakazu Sort) ①1個の整数でデータの状態を管理 ②大量のif文で状態遷移を管理 ※3分割版と4分割版を作ったが3分割版の方が速かった。ここで は3分割版を基本として説明をする。 実はC++だと 4分割版のほうが速い…。 https://github.com/m-matsubara/sort
  20. 20. ①1個の整数でデータの状態を管理 int state で各サブリストの先頭値の大小順を表現 state = 123となる 2 3 6① ② ③ state = 312となる 8 9 6① ② ③ https://github.com/m-matsubara/sort
  21. 21. ②大量のif文で状態遷移を管理 if (state < 0x200) { // state = 0x123 or 0x132 array[idx] = workArray[pos1++]; if (pos1 >= p1to) break; if (state == 0x123) { if (comparator.compare(workArray[pos1], workArray[pos2]) <= 0) ; // モード変更なし else if (comparator.compare(workArray[pos1], array[pos3]) <= 0) state = 0x213; else state = 0x231; } else { // state = 0x132 各stateの取りうる値(15種類) ごとに処理をハードコード https://github.com/m-matsubara/sort
  22. 22. 3.省メモリなマージソート https://github.com/m-matsubara/sort
  23. 23. 省メモリマージソート(1/2) • 一般的なマージソートは同じ大きさの2つのサブリストに分割す るけど、あえてバランスを崩してみる。 配列 ワーク メモリ ワークメモリ小さい!!。 https://github.com/m-matsubara/sort
  24. 24. 省メモリマージソート(2/2) MatSort (Matsubara Sort) • 要素数の1/4のワークメモリにした場合 ※ワークメモリサイズは速度とメモリ領域のトレードオフで決定する。 ※全体の計算量は O(N log N)のままとなる。 配列 ① ¼の範囲ごとに mmsSort または MasSort等で ソートしておく ② 後半2つマージ ③ もひとつマージ ④ 最後もマージ https://github.com/m-matsubara/sort
  25. 25. 4.ベンチマーク https://github.com/m-matsubara/sort
  26. 26. ベンチマーク • ソート対象のオブジェクトは以下のような感じ class SortItem { public int key; public String keyStr; public int orginalOrder; public int filler1; … public int filler13; } • Java version 1.8.0_40 で実行 • Intel Core-i7 3770K で実行 • 10回繰り返した平均値で比較 整数のソートキー 文字列のソートキー ソート前の配列上での位置 (安定ソートできているかチェック用) 13個のダミー項目 https://github.com/m-matsubara/sort
  27. 27. ※比較回数はArrays.sortが一番少なくなる ※ソート済みや重複値が多い場合、Arrays.sortが一番速くなる …こともある。 ベンチマーク (乱数・整数キー・重複なし) アルゴリズム 10,000,000 mmsSort (dual pivot stable Sort) 3.471 MatSort(1/5) 3.819 MasSort 3.849 Quick Sort (Median of 3) 4.006 Arrays.sort 4.580 実行時間 要素数1000万個で Arrays.sort()より 25%ほど速い。 単位(秒) https://github.com/m-matsubara/sort
  28. 28. ベンチマーク総括(1/2) mmsSortの特徴 • 乱数配列でArrays.sort()より20~30%ほど速い • 作業領域は対象配列と同じサイズ必要 MasSortの特徴 • 乱数配列でArrays.sort()より10%ほど速い • 作業領域は対象配列の2/3ほど必要 MatSortの特徴 • MergeSortの作業領域サイズを対象配列サイズの数分の1から 100分の1ほどに減らせる。 • 苦手データが少なめ(ソート済みが遅い部類に入るくらい) https://github.com/m-matsubara/sort Dual-pivot Quicksort ベース 3-way Mergesort ベース 省メモリマージソート
  29. 29. ベンチマーク総括(2/2) Arrays.sort()の特徴 • ほとんどの条件で比較回数は最小になる。 • ソート済みや重複値が多い場合、急激に速くなる。 • 重複の少ない乱数配列は実際のところそれほど速くない (MergeSortより遅いくらい) QuickSortの特徴 • メジャーなソートアルゴリズムでは最速とされる…がJavaだとそ こまで速くないことも。 • 比較回数多め(乱数配列の場合、Arrays.sort()の1.5倍くらい) • 苦手なデータがある(最悪、O(N2)のパフォーマンス。HeapSortを 併用して克服!!) https://github.com/m-matsubara/sort
  30. 30. 速いソートを書いて目指すところ • Javaの将来のバージョンの標準ソートに取り込まれたい。 • Javaじゃなくても何かの言語で採用してくれないかなあ…。 • 皆さんにも速いソートにチャレンジしてみてほしい。 https://github.com/m-matsubara/sort
  31. 31. Copyright © 2017 松原正和 ご清聴ありがとうございました。 https://github.com/m-matsubara/sort

×