Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
速いクイックソート: Pattern-defeating quicksort
Search
WATANABE Yuki
August 24, 2022
Programming
480
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
速いクイックソート: Pattern-defeating quicksort
社内勉強会から。Pattern-defeating quicksort アルゴリズムの大まかな説明。
WATANABE Yuki
August 24, 2022
More Decks by WATANABE Yuki
See All by WATANABE Yuki
C++ はなぜあんなにも複雑なのか
magicant
0
100
鉄道シミュレーターで自動運転を実装した話
magicant
0
390
ドキュメント、書けてますか?
magicant
0
130
Other Decks in Programming
See All in Programming
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
180
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
6.6k
Event is what happens
moro
2
770
ChromeでローカルLLM
ryu1013
0
140
現場と育てるRailsモデリング 〜Spreadsheetから始めたモデル設計〜
siroemk
2
590
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
1.1k
カツオ、ご期待ください
suneo3476
0
190
パスワード再設定メールのURLについて知っておこう
uyuki234
0
160
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.9k
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
880
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
640
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Featured
See All Featured
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.9k
Skip the Path - Find Your Career Trail
mkilby
1
260
My Coaching Mixtape
mlcsv
0
360
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
460
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
It's Worth the Effort
3n
188
29k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
22k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
570
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
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