Menu
Coddy logo textTech

挿入ソート

最終更新

挿入ソートは、ソート済み配列を1要素ずつ構築します。次の未ソート要素(「キー」)を取り出し、ソート済み領域内でそれより大きいすべての要素を1つ右へずらし、キーをその空いた場所に置きます。これはまさに、多くの人が手札のカードを並べる方法と同じです。上の再生ボタンを押して各キーが挿入される様子を見るか、ずらす操作を1つずつ進めてみてください。

挿入ソートは小さい入力やほぼ整列済みの入力では非常に高速で、データがすでにソート済みの場合は O(n) で動作します。そのため、多くのハイブリッドソートは小さな部分配列に対して挿入ソートに切り替えます。

時間計算量と空間計算量

ケース計算量備考
最良の場合O(n)すでにソート済み
平均の場合O(n²)ランダムな順序
最悪の場合O(n²)逆順にソート済み
空間O(1)インプレース
安定はい等しい要素は相対的な順序を保つ

ステップごとの説明

ステップ何が起こるか
1最初の要素をサイズ1のソート済み領域として扱う。
2次の要素をキーとして取り出す。
3ソート済み領域でキーより大きい各要素を1つ右へずらす。
4開いた空きにキーを挿入する。
5すべての要素が挿入されるまで繰り返す。

具体例

[5, 2, 4, 1] をソートする場合:

パス配列操作
開始[5, 2, 4, 1]5 はサイズ1の初期ソート済み領域。
1[2, 5, 4, 1]キー 25 を右へずらし、2 を先頭に挿入。
2[2, 4, 5, 1]キー 45 を右へずらし、2 は小さいので停止、4 を挿入。
3[1, 2, 4, 5]キー 1542 を右へずらし、1 を先頭に挿入。
完了[1, 2, 4, 5]すべての要素が挿入され、配列はソート済み。

挿入ソートを使うべき場面

使うべき場合避けるべき場合
配列が小さい場合(おおよそ n < 20)。配列が大きくランダムな順序の場合。
データがすでにほぼソート済みで、最良の場合 O(n) が得られる場合。保証された最悪の場合 O(n log n) が必要な場合。
O(1) の追加空間で安定かつインプレースなソートが必要な場合。多くのずらし操作を行うため、要素の移動コストが高い場合。
データが逐次到着し、オンラインでソート済みを保つ必要がある場合。入力が逆順にソートされており、最悪の場合 O(n²) になる場合。

Insertion Sortのコード

Python, JavaScript, Java, C++, Cによるクリーンで実行可能なInsertion Sortの実装です。言語を選んでコードをコピーするか、Coddyプレイグラウンドに読み込んだ状態で開けます。

PythonでのInsertion Sortのコード

Python
1def insertion_sort(a):2    for i in range(1, len(a)):3        key = a[i]4        j = i - 15        # Shift larger elements one slot to the right6        while j >= 0 and a[j] > key:7            a[j + 1] = a[j]8            j -= 19        a[j + 1] = key10    return a11
12
13nums = [7, 3, 9, 1, 5, 8, 2]14print("Before:", nums)15insertion_sort(nums)16print("After: ", nums)
このコードをPythonプレイグラウンドで実行

挿入ソートのよくある質問

挿入ソートの時間計算量はどれくらいですか?
挿入ソートは平均および最悪の場合で O(n²) ですが、すでにソート済みまたはほぼソート済みの配列では O(n) です。追加空間は O(1) を使います。
挿入ソートは安定ですか?
はい。挿入ソートはキーより厳密に大きい要素だけをずらすため、等しい要素が互いを追い越すことはなく、相対的な順序が保たれます。
挿入ソートはいつ使うべきですか?
小さな配列や、すでにほぼソート済みのデータに使いましょう。オーバーヘッドが小さく最良の場合が適応的であるため、Timsort のようなハイブリッドアルゴリズムは小さなランに対して挿入ソートを使います。
挿入ソートとバブルソートの違いは何ですか?
どちらも O(n²) の比較ソートですが、挿入ソートはキーのための空きを作るために要素をずらすのに対し、バブルソートは順序の逆な隣接ペアを繰り返し交換します。挿入ソートは通常、書き込み回数が少なく、実際には特にほぼソート済みのデータで最良の場合 O(n) に達するため、性能が優れています。
なぜ挿入ソートは小さな配列でマージソートより速いのですか?
挿入ソートは定数倍のオーバーヘッドが非常に小さく、再帰や追加のメモリ確保がないため、漸近計算量が悪いにもかかわらず、小さな入力では O(n log n) のソートを上回ります。まさにこの理由で、Timsort や introsort のようなハイブリッドソートは小さな部分配列に対して挿入ソートに切り替えます。
挿入ソートは連結リストと配列のどちらで性能が良いですか?
挿入ソートは通常、要素のずらしが主なコストとなる配列向けに書かれます。連結リストではノードを所定の位置につなぎ替えることでずらしを回避できますが、高速なランダムアクセスを失うため、挿入位置を見つけるのに要素ごとに線形時間がかかり、全体のコストは O(n²) のままです。
Coddy programming languages illustration

Coddy でアルゴリズムをマスターしよう

始める