挿入ソート(Insertion sort) は、バブルソートと並び、アルゴリズムが単純で実装が容易なため、しばしば用いられます。
処理時間はかかりますが、バブルソートよりも高速、殆ど整列済みのデータに対しては高速という特徴を持ち、安定な内部ソートを実現します。
以下の配列 array に対する昇順ソートを行うとします。
array | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] | [9] |
---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 3 | 2 | 0 | 1 | 2 | 0 | 1 |
題意より、常に [i] の値は [i + 1] の値以下となり、最小値は arrray[0] 、最大値はarray[9] に置かれます。
まず、[0]と[1]を比較し、順番が逆であれば位置を交換します。太字は交換または挿入箇所を示し、斜体は整列済みの範囲であることを示します。
array | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] | [9] |
---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3 | 2 | 0 | 1 | 2 | 0 | 1 |
次に、整列した[0]~[1]に対して、[2]を正しい順に並ぶ位置に挿入します。挿入する際、右側のデータは右方向に一つずつ移動します。
array | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] | [9] |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 3 | 2 | 0 | 1 | 2 | 0 | 1 |
次に、整列した[0]~[2]に対して、同様の処理を行います。このあと、[3]以降の要素について、整列済みデータとの比較と適切な位置への挿入を繰り返します。
挿入位置が決まれば、それ以降比較を行う必要がないため、比較回数はバブルソートよりも少なくなり、結果「バブルソートよりも高速」となります。
ほとんど整列された配列に対しては、比較を行う必要がないため、「殆ど整列済みのデータに対しては高速」となります。
この利点を応用として、配列を細分することを考えます。このとき細分された配列のそれぞれは、細分前と比較して「殆ど整列された状態」にあります。また、整列が完了した配列を結合すると、結合された配列は「殆ど整列された状態」とみなすことができます。この考え方に基づいた、シェルソート、マージソートはより高速なソートを実現できます。
改良例として、二分挿入ソートがあります。挿入箇所の前は整列済みであるという性質を利用して、挿入箇所を二分探索する手法です。
要素数 n の倍精度実数配列 array
に対するソースを示します。ここで、配列の要素数は、配列の定義等によって既知であるとします。
数値配列に対する汎用性を考慮しており、このまま使用する場合は、引数にあたる配列のデータ型をキャストしてください。
void inssort(double array, int n) { int i, j; /*配列要素に対するカウンタ*/ double temp; /*退避用の変数*/ for (i = 1; i < n; i++) { temp = array[i]; /*これから挿入を行う値を退避する*/ /*array[i]より左側の整列済み配列に対して、右側から temp との比較を行う*/ for (j = i - 1; j >= 0 && array[j] > temp; j--) array[j + 1] = array[j]; /*挿入する値が、比較した配列要素より小さければ、その配列要素は右に1つずらす*/ /*挿入する値が比較した配列要素以上ならば、ループを抜けて、その要素の右側に退避した値を代入する(挿入)*/ array[j + 1] = temp; } } |
2008/07/25: 作成