イントロ
ソートは、1997年にDavid Musserによって考案された
ソートアルゴリズムで、
クイックソートとヒープ
ソートという2つの異なる
アルゴリズムを組み合わせることで、それぞれの長所を活かし、短所を補完する設計になっています。
アルゴリズムの概要
イントロ
ソートは、まず
クイックソートを適用します。
クイックソートは平均的には非常に高速な
ソートアルゴリズムですが、特定の入力データに対しては著しく性能が低下する可能性があります。そこでイントロ
ソートでは、
クイックソートの
再帰呼び出しの深さが、
ソート対象の要素数の対数を超えると、
アルゴリズムをヒープ
ソートに切り替えます。ヒープ
ソートは最悪の場合でもO(n log n)の時間計算量を保証する安定した
アルゴリズムですが、一般的には
クイックソートより遅い傾向があります。
イントロ
ソートはこのように、最初は高速な
クイックソートで
ソートを進め、
クイックソートが苦手とするケースに遭遇した場合には、ヒープ
ソートに切り替えることで、最悪の場合でも効率的な
ソート処理を実現しています。
クイックソートの課題とイントロソートの解決策
クイックソートの性能は、ピボット(分割の基準となる値)の選び方に大きく左右されます。例えば、データ列の先頭や最後尾をピボットとして選ぶ場合、入力データが既に
ソートされているような状況では、分割が偏ってしまい、最悪の場合にはO(n²)の時間計算量になってしまいます。
この問題を解決するために、データ列の中央の要素をピボットに選ぶ方法や、先頭、最後尾、中央の3つの要素の中央値をピボットに選ぶ「median-of-3 pivot」などの手法が用いられます。しかし、これらの方法でも、入力データを意図的に操作することで
クイックソートの性能を低下させることが可能です。特に、ユーザーからの入力データを
ソート処理する場合には、悪意のある入力によって
DoS攻撃(サービス拒否攻撃)を引き起こすリスクがあります。
イントロ
ソートは、このような
クイックソートの潜在的な問題を回避しつつ、平均的なケースでは
クイックソートと同等の高速性を維持することを目指して設計されました。
性能と実用
Musserの実験では、最悪ケースで
クイックソートが非常に遅くなるようなデータに対しても、イントロ
ソートは
クイックソートの1/200程度の実行時間で
ソートを完了できたと報告されています。さらに、
キャッシュメモリを考慮した最適化として、
ソートの最終段階で挿入
ソートを行うことも検討されました。これは、データがほぼ
ソート済みの状態では挿入
ソートが非常に効率的であるという特性を利用したものです。
イントロ
ソートの効率の良さから、SGIのC++標準テンプレートライブラリ(STL)では、イントロ
ソートの考え方に基づいた不安定
ソートの実装が採用されています。この実装では、ヒープ
ソートへの切り替えタイミングを引数で指定でき、さらに最終段階で挿入
ソートを用いることも可能です。
擬似コード
擬似コードでイントロ
ソートを表現すると以下のようになります。ここで、partitionは
クイックソートの分割処理、heapsortはヒープ
ソートの処理をそれぞれ行う関数とします。
function introsort(array, depthLimit)
if length(array) <= 1 then
return
if depthLimit == 0 then
heapsort(array)
return
pivot = partition(array) //
クイックソートの分割
introsort(array[0..pivot-1], depthLimit - 1)
introsort(array[pivot+1..length(array)-1], depthLimit - 1)
end function
function sort(array)
maxDepth = 2
log2(length(array))
introsort(array, maxDepth)
end function
まとめ
イントロソートは、クイックソートとヒープソートの良い点を組み合わせた、実用的なソートアルゴリズムです。クイックソートの高速性を維持しつつ、最悪の場合でもO(n log n)の時間計算量を保証するため、さまざまな状況で安定した性能を発揮します。その実装には、キャッシュメモリの効果を考慮した最適化や、挿入ソートとの組み合わせなど、さらに性能を向上させるための工夫が凝らされています。
関連情報
イントロセレクト: イントロ
ソートの考え方を応用した選択
アルゴリズムで、クイックセレクトの最悪計算時間を改善します。
*
外部リンク: Ralph Undenによるイントロ
ソートの解説とJavaによる実装例が提供されています。
イントロ
ソートは、
ソートアルゴリズムの選択肢として、その優れた性能と安定性から、広く採用されています。