
分割統治法を使ったソートの王道”クイックソート”
以前の記事で、分割統治法を用いたアルゴリズムとして、常に安定した \(O(n \log n \) の性能を誇る「マージソート」を紹介しました。
- 一つ前の記事 “分割統治法を純粋に遂行”マージソート
マージソートの仕組みを徹底解説!アニメーションで学ぶ「分割統治」ソート・併合ソート【ソートアルゴリズム入門】#6
「マージソート」は「分割統治法」に基づく高速なソートです。O(N^2)の単純ソートとは異なり、O(N log N)の計算量を実現します。データを半分に「分割」し、ソートしながら賢く「結合(マージ)」する仕組みを図解します。
- “分割統治法”について理解する
分割統治法とは?高速なソートアルゴリズム【ソートアルゴリズム入門】#5
「分割統治法」とは? 難しい問題を「小さく分けて、後で合体する」ことで高速に解くアルゴリズム戦略です。O(N^2)の壁を破るO(N log N)の鍵となる、マージソートやクイックソートの基本思想を図解します。
マージソートは「分割は単純、結合は賢く」という戦略でしたね。
今回は、同じ「分割統治法」を使いながら、逆のアプローチをとるアルゴリズム、「クイックソート(Quick Sort)」を解説します。
クイックソートは、その名の通り非常に高速で、多くのプログラミング言語で標準ソートとして採用されている「ソートの王様」とも呼ばれるアルゴリズムです。
クイックソートの実行例 アニメーション

クイックソートの実行例 アニメーション
1. クイックソート(Quick Sort)とは?
クイックソートも「分割統治法」に基づいています。しかし、マージソートとは対照的に、「分割の段階で賢く並べ替え、結合を不要にする」アルゴリズムです。
- マージソート:
- 分割: とにかく半分に分ける。(作業は単純)
- 結合: ソート済みの2つを賢くマージする。(作業が重い)
- クイックソート:
- 分割: ある「基準値」を決め、それより小さい/大きいで分ける。(作業が重い)
- 結合: 分割が終わればソートも終わっているので、作業は不要。
この「分割」のステップがクイックソートの核であり、「パーティション(Partition)」操作と呼ばれます。
2. クイックソートの分割統治方法
例として、マージソートと同様のトランプの配列 [9, 6, Q, 3, 2, 1, J, 8, 7, 5, 10. 4] を並び替える例でアルゴリズムを紹介します。
(1) 分割 (Divide) と 統治 (Conquer)
クイックソートでは「分割」と「統治(再帰呼び出し)」が密接に関連しています。
ステップ1: グループ全体 [9, 6, Q, 1, 2, 3, J, 10, 8, 7, 5, 4]
- ピボット(基準値)の選択:まず、グループ内から「ピボット」となる基準値を1つ選びます。選び方はいろいろありますが、ここでは単純に一番右の「4」をピボットに選びます。
[9, 6, Q, 1, 2, 3, J, 10, 8, 7, 5,4](ピボット) - パーティション(分割)操作:ピボット以外の要素(左端から)を順に見ていき、「ピボット”4″以下のグループ」と「ピボット”4″より大きいグループ」に振り分けます。(※実際の実装はもう少し複雑ですが、ここでは概念的な動きを示します)
9\(\to\) 大きいグループへ6\(\to\) 大きいグループへQ\(\to\) 大きいグループへ1\(\to\) 小さいグループへ2\(\to\) 小さいグループへ3\(\to\) 小さいグループへ- …
これを最後まで行うと、配列が以下のように並び替えられます。
[1, 2, 3] (小さいグループ) \(\to\) 4 \(\to\) [9, 6, Q, J, 10, 8, 7, 5] (大きいグループ)
ピボットだった「4」を2つのグループの間に置きます。この時点で、「4」は最終的な正しい位置に確定しました。

ステップ2: 2つのグループを、それぞれ「統治」する
次に、分割してできた2つのグループ(小さいグループと大きいグループ)に対して、まったく同じこと(クイックソート)を再帰的に行います。
- 左グループ
[1, 2, 3]の処理:- ピボットに「3」を選ぶ。
- パーティション操作 \(\to\)
[1, 2](小さい) \(\to\)3\(\to\)[](大きい: なし)
- 右グループ
[9, 6, Q, J, 10, 8, 7, 5]の処理:- ピボットに「5」を選ぶ。
- パーティション操作 \(\to\)
[](小さい: なし) \(\to\)5\(\to\)[9, 6, Q, J, 10, 8, 7]
ステップ3: さらに再帰…
これを、分割したグループの要素が1つ(または0個)になるまで繰り返します。
(2) 結合 (Combine)
マージソートの「結合」は、2つのソート済みリストを比較しながらマージする重い処理でした。
クイックソートの「結合」はどうでしょう?
ステップ1の時点で、[小さいグループ] \(\to\) ピボット \(\to\) [大きいグループ] という並びが確定しています。
それぞれのグループを再帰的にソートし終えたら、それらをただ並べるだけです。特別な結合操作は一切不要です。これがクイックソートが高速な理由の一つです。
3. クイックソートの動きを見てみよう!
クイックソートで並び替えを試せます。ステップ実行ボタンを押して、並び替えを進めてみてください。
色が濃い部分が今処理をしているグループ(パーティション対象)で、ピボットに使用している要素を赤色にしています。
4. クイックソートの疑似コード (ソートの手順)
クイックソートは、再帰関数1つで表現できます。(パーティション操作を関数内に含める方法)
// L: ソートしたいリスト
// low, high: ソート対象の「範囲」を示すインデックス
algorithm QuickSort(L, low, high) is
// (1) 再帰の停止条件: 範囲がない、または1つだけなら終了
if low >= high then
return
end
// (2) 分割 (Partition)
// pivot_index ← Partition(L, low, high)
// (Partition操作の結果、ピボットが最終的な位置 (pivot_index) に移動する)
// --- Partition操作の簡易な例 (ピボットを L[high] とする) ---
pivot ← L[high]
i ← low // 「小さいグループ」の右端
// j: 未処理グループの先頭 (low から high-1 まで)
for j from low to high-1 do
if L[j] <= pivot then
swap(L[i], L[j]) // L[j]を「小さいグループ」の末尾に追加
i ← i + 1
end
end
// 最後にピボットを「小さい」と「大きい」の間に移動
swap(L[i], L[high])
pivot_index ← i
// --- Partition操作ここまで ---
// (3) 統治 (Conquer)
// ピボットの「左側」を再帰的にソート
QuickSort(L, low, pivot_index - 1)
// ピボットの「右側」を再帰的にソート
QuickSort(L, high, pivot_index + 1)
end5. まとめ
- クイックソートは、「分割統治法」の代表的なアルゴリズム。
- 「ピボット」を選び、「パーティション」操作で分割する。(分割が賢い)
- 分割が終わった時点でソートが完了するため、結合操作は不要。
- 多くの場合(平均的に)非常に高速で\(O[n \log n]\) の計算量となる。
- (弱点1)ピボットの選び方が最悪(例: 毎回最小値を選ぶ)だと、分割が偏り、計算量が \(O[n^2]\) に悪化する。
- (弱点2)同じ値の順序が入れ替わる可能性があり、「不安定ソート」である。
次の記事
次回は”ピープ”という木構造を利用してソートするピープソートの前知識として、ヒープとは何かについて紹介します。その次に本題であるピープソートに仕組みについて紹介しようと思います。
ヒープソート前座 ヒープとは?【ソートアルゴリズム入門】#10
ヒープとは?ヒープである条件について紹介。ヒープがわかればヒープシートがわかる。
11 記事
ソートアルゴリズム
ソートアルゴリズムについて、単純ソート、分割統治法などの比較するソート、基数ソートなどの比較しないソートまでその仕組みを...
ここまで読んでいただきありがとうございます。
では、次の記事で。 lumenHero