More Related Content Similar to 高速なソートアルゴリズムを書こう!! (9) 高速なソートアルゴリズムを書こう!!2. 松原正和 - 自己紹介
A5:SQL Mk-2の作者
・SQL&ER図ツール
双子のパパ
・もうすぐ5歳
https://github.com/m-matsubara/sort
https://a5m2.mmatsubara.com
本人
3. Java の標準ソートは Arrays.sort() メソッド
・プリミティブ(基本)型のソートは Dual-pivot quicksort
ピボット値が2つあるクイックソート (非安定)
・オブジェクト型のソートはTimSort
Tim Petersさんの書いた非再帰マージソート (安定)
とりあえずは、比較ソートで。
基数ソートとかバケットソートと
かは今回は考えないことにします。
https://github.com/m-matsubara/sort
13. ③ 場合によっては
3-way partition Quicksortに切り替え
選んだPivot1とPivot2が等しいとき…
→ピボット値未満・ピボット値と等しい・ピボット値より大きい
の3つに分ける
→ピボット値と等しいグループは再帰不要
再帰でソート 再帰でソートソート
要らない
配列 pivot < 値値 < pivot 値 = pivot
https://github.com/m-matsubara/sort
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
24. 省メモリマージソート(2/2)
MatSort (Matsubara Sort)
• 要素数の1/4のワークメモリにした場合
※ワークメモリサイズは速度とメモリ領域のトレードオフで決定する。
※全体の計算量は O(N log N)のままとなる。
配列
① ¼の範囲ごとに
mmsSort または
MasSort等で
ソートしておく
② 後半2つマージ
③ もひとつマージ
④ 最後もマージ
https://github.com/m-matsubara/sort
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
Editor's Notes 10s
プログラミングを習い始めの頃、皆一回くらいはソートアルゴリズムを学んだことがあるはず…。
30s 40s
プリミティブとは intとかfloatとか。
とりあえず、TimSortを超えるのが目標。 40s
安定なソートはマージソートやバブルソート
安定でないソートはクイックソートやヒープソート 30s
クイックソートは最悪ケースで O(N2) になることがある。…ヒープソートを併用して回避したりする。
マージソートは速いソートの中で唯一の安定ソート。その代わり外部メモリが必要だったりする。Arrays.sortはマージソートの一種。 10s 30s 30s 50s
CPUキャッシュってなんぞや…最近アクセスしたメモリ(つまりオブジェクト)を高速にアクセスできる「キャッシュメモリ」に覚えておく。 40s
再帰の深さが2/3になるということは、メモリの転送回数も2/3になる。 30s
ソート対象と同じ大きさの外部メモリが必要。 30s
コピー処理にSIMDを使えるともっと高速化されるのだけど…。 40s 30s
ここまでがクイックソート高速化のお話。 10s 30s 30s 30s
K-way Mergesortは…誰でも一度は考える。 30s 30s 30s
state変数の取りうる値は15種類…全体で66個ものif文、4-way mergesortにすると213個ものif文
ここまでがマージソート高速化のお話 10s 30s
ワークメモリが要らない、インプレースマージソートってのもあるけどあんまり速くない。
Inplace Mergesortの例 O(N log N)のもの
WikiSort … MergeSortの倍近く…ただし、ソースに改善の余地ありと思う。
GrailSort … C++のみ … Javaに移植して試したいが…。 40s ¼の範囲ごとのソートは安定ソートなら何でもいい。ソート範囲サイズと同じワークメモリが使える。
②~④の実行コストは1/Kのワークメモリの場合、O(N・K)に比例する。つまり、Kが固定なら、O(N)ということ。
ここまでが省メモリマージソートのお話。 10s 20s
整数のキータイプと文字列のキータイプでベンチマークした。
CPUのアーキテクチャもそうだし、ダミー項目の増減でもパフォーマンスは変わる。
自分の環境はメモリが若干遅め(安物)ってところも影響はあるかも。 20s 50s 30s 20s
敷居はそんなに高くないよ。アイデア次第。
…突き詰めると離散数学とか出てくるけど… 10s