データ構造

整列アルゴリズム比較

7種類が同じ入力を同時に整列します。1回の更新で比較や移動を1ステップ進めるため、早く終わるほど集計したステップ数が少ないことを示します。実際のCPU実行時間の比較ではありません。入力によって順位は変わります。

同じ配列で7種類の整列アルゴリズムを比較するシミュレーター

入力

ほぼ整列済みなら挿入ソートとバブルソートが有利ですが、逆順では処理が増えます。マージソートとヒープソートは入力順序の影響が小さめです。表のアルゴリズム名から詳細な実験へ進めます。

計算量の一覧

アルゴリズム最良平均最悪追加領域安定性
バブルO(n)O(n²)O(n²)O(1)はい
選択O(n²)O(n²)O(n²)O(1)いいえ
挿入O(n)O(n²)O(n²)O(1)はい
クイックO(n log n)O(n log n)O(n²)O(log n)いいえ
マージO(n log n)O(n log n)O(n log n)O(n)はい
ヒープO(n log n)O(n log n)O(n log n)O(1)いいえ
計数O(n + k)O(n + k)O(n + k)O(n + k)はい

kは計数ソートの値域です。安定ソートは同じ値の元の順序を保ちます。名前で整列した後に点数で整列するなど、複数の基準を順に適用するときに役立ちます。

どのアルゴリズムを使うか

通常は言語の組み込みソート

Pythonのsort()は安定で、最悪時間計算量はO(n log n)です。一般的な整列には、十分に検証された組み込み実装を使いましょう。

最悪でもO(n log n)が必要な場合

安定性が必要で追加メモリを使えるならマージソート、配列の追加領域を一定に抑えたいならヒープソートが候補です。

ほぼ整列済み・小さな入力

挿入ソートが得意な条件です。多くの汎用ソートでも小区間の処理に使われます。

狭い値域に大量の整数

計数ソートは値同士を比較せずO(n + k)で処理します。頻度だけが必要なら保存領域も減らせます。

演習:ソートキーを選ぶ

多くの問題ではソートの自作よりキーの選択が重要です。タプルのキーは順に比較され、数値に負号を付けるとその項目を降順にできます。

a.sort()                                   # 安定・リストを直接更新
b = sorted(a, reverse=True)                # 降順の新しいリスト
people.sort(key=lambda p: (-p[1], p[0]))   # 点数は降順、名前は昇順

おおまかな目安では、二乗時間のアルゴリズムは数千要素なら使える場合がありますが、10万要素ほどでは高コストです。限界は言語・機器・処理内容に依存するため、固定の時間目安ではなく計測で判断してください。