$30 off During Our Annual Pro Sale. View Details »
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
速いクイックソート: Pattern-defeating quicksort
Search
WATANABE Yuki
August 24, 2022
Programming
0
390
速いクイックソート: Pattern-defeating quicksort
社内勉強会から。Pattern-defeating quicksort アルゴリズムの大まかな説明。
WATANABE Yuki
August 24, 2022
Tweet
Share
More Decks by WATANABE Yuki
See All by WATANABE Yuki
C++ はなぜあんなにも複雑なのか
magicant
0
84
鉄道シミュレーターで自動運転を実装した話
magicant
0
300
ドキュメント、書けてますか?
magicant
0
120
Other Decks in Programming
See All in Programming
Socio-Technical Evolution: Growing an Architecture and Its Organization for Fast Flow
cer
PRO
0
130
Microservices Platforms: When Team Topologies Meets Microservices Patterns
cer
PRO
1
720
AWS CDKの推しポイントN選
akihisaikeda
1
220
モビリティSaaSにおけるデータ利活用の発展
nealle
1
670
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
230
dotfiles 式年遷宮 令和最新版
masawada
1
270
AIエージェントでのJava開発がはかどるMCPをAIを使って開発してみた / java mcp for jjug
kishida
4
830
大体よく分かるscala.collection.immutable.HashMap ~ Compressed Hash-Array Mapped Prefix-tree (CHAMP) ~
matsu_chara
1
190
Web エンジニアが JavaScript で AI Agent を作る / JSConf JP 2025 sponsor session
izumin5210
4
2.1k
Level up your Gemini CLI - D&D Style!
palladius
1
140
CSC305 Lecture 17
javiergs
PRO
0
200
JEP 496 と JEP 497 から学ぶ耐量子計算機暗号入門 / Learning Post-Quantum Crypto Basics from JEP 496 & 497
mackey0225
2
510
Featured
See All Featured
How STYLIGHT went responsive
nonsquared
100
5.9k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
68k
How GitHub (no longer) Works
holman
316
140k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
360
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.8k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.8k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
2.9k
Statistics for Hackers
jakevdp
799
230k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
34
2.3k
Fireside Chat
paigeccino
41
3.7k
Transcript
速いクイックソート 渡邊裕貴 / 2022-08-24
Pattern-defeating quicksort • Orson Peters という人が 2015 年ごろに発明した不安定ソートアルゴリズム • クイックソートを速くするいろいろな工夫の集大成みたいな感じ
• オリジナルのコードは C++ で書かれている • Rust の標準ライブラリーで採用された • 最近 Go の標準ライブラリーでも採用された
1分でわかる普通のクイックソート 5 4 1 6 7 3 2 9 8
配列の中から一つ軸を選ぶ (pivot) 2 4 1 3 5 7 6 9 8 軸未満→軸→軸以上 の順になるように入れ替える 以下、前後それぞれ繰り返し 2 4 1 3 5 7 6 9 8 1 2 4 3 5 6 7 9 8
クイックソートの計算量 全ての分割が二等分になる場合が最も効率的で、O(n log n) 4 3 7 6 1 5
2 2 3 1 4 6 5 7 1 2 3 4 5 6 7 n log n
クイックソートは遅い時もある (1) 常に配列の先頭を軸にする場合、配列が元からソート済みだと分割が偏る 1 2 3 4 5 6 7
n 1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 n O(n2)
軸の選び方の工夫 • 配列の先頭 • 配列の真ん中 • 三つ選んで中央値を取る ◦ 3 回の比較でできる
• John Tukey’s ninther ◦ 「三つ選んで中央値を取る」を 3 回やって中央値を取る ◦ 12 回の比較でできる 簡単 分割が偏りにくい
クイックソートは遅い時もある (2) 同じ値がたくさんある場合、分割が偏る 1 1 1 1 1 1 1
n 1 1 1 1 1 1 1 1 1 1 1 1 1 1 n 1 1 1 1 1 1 1 どれを選んでも軸は 1 O(n2)
軸に等しい値の振り分けを工夫する 1 1 2 1 1 1 1 1 1
2 1 1 1 1 新しい軸が前回の軸と等しいなら 同じ値がたくさんある公算が高い 軸に等しい値→軸より大きい値 の順に入れ替える 軸に等しい値どうしはもうソートしなくていい O(n2) が O(n) になった 1 1 1 1 1 1 2
クイックソートは遅い時もある (3) それでも分割が偏る可能性はゼロではない • とても運が悪かった場合 • 分割が偏るように仕組まれている場合
軸の候補をシャッフルする 分割が偏っていた場合 (分割比が 1:7 未満の場合) は 次の軸の選び方 (John Tukey’s ninther
で使う値) を変える • オリジナル版: ◦ 配列の端っこや真ん中だけじゃなくて四等分した位置から選ぶ • Rust/Go 版: ◦ 四等分した位置だけじゃなくてランダムに選ぶ ▪ 簡易的な乱数を使う
最後の手段: ヒープソート 偏った分割が log n 回発生したら、諦めてヒープソートに移行する ヒープソートとは: • 二分木と等価な構造を配列上に再現するソート手法 •
クイックソートより 2 倍くらい遅い • 最悪計算量 O(n log n) が保証されている
部分挿入ソートによる高速化 • 以下の条件が全て満たされたとき、配列全体がソート済みの可能性が高そう ◦ 前回の分割比が 1:7 より悪くなかった ◦ 前回の分割時、軸の前後で入れ替わった要素がなかった ◦
John Tukey’s ninther で軸を選ぶとき候補となる九つの値がソート済みだった • この場合は挿入ソートを試す ◦ ただし一定ループ回数で終わらなければ諦める (O(n))
配列の分割 (軸前後の値の入れ替え) の遅さ 典型的コード while (left < right && array[left]
< pivot) left++; while (left < right && array[right] >= pivot) right--; if (left < right) { tmp = array[left]; array[left] = array[right]; array[right] = tmp; } 分岐予測の外れやすい分岐 1 回の入れ替えで 3 回の代入
BlockQuicksort による高速化 1. 配列の先頭 128 個と末尾 128 個を一気に軸と比較して 入れ替えるべき値の位置を一時配列にまとめる ◦
ループ回数を固定したことで分岐予測が当たるようになる ◦ ループアンローリングも可能に 2. 一次配列に入った位置の値を一気に入れ替える ◦ 2n 個の値を 2n+1 回の代入で入れ替える tmp
まとめ Pattern-defeating quicksort にはソートを速くするいろんな工夫が詰まっている • 中央値に近い値を軸にする: John Tukey’s ninther •
軸に等しい値を効率よく集める • 軸の候補をシャッフルする • 再帰回数が O(log n) を超えそうならヒープソート • 既にソート済みっぽいなら挿入ソート • 値の入れ替えを速くする: BlockQuicksort