![]() |
|||||||||||||||||||||
(1)シェルソートとは 単純挿入法によるソートは,単純交換法,単純選択法と同様, 計算量はO(N2)です。 一方,単純挿入法には,以下の特徴があります。 (a) ソート済み,またはそれに近いとき高速である。 (b) 挿入先が離れているとき,ずらす回数が多くなる。 最初,なるべく離れた要素をグループ化して, 大まかなソートを行い,そのグループを縮めていくことで, (a)の長所を活かし,(b)の短所を補うことができます。 この方法をシェルソートと呼びます。 まず,以下の例を単純挿入法でソートすると, 要素をずらす回数は,14回になります。 ![]() ここで,まず4つずつ離れたグループ {9,8},{2,7},{5,4},{3,7} でソートすることを考えます。すると,次のようになります。 ![]() このソートを4−ソートと呼びます。 次に2つずつ離れたグループ {8,4,9,5},{2,3,7,6} 内でソート(2−ソート)します。 ![]() 最後に,通常の単純挿入法でソートしてみます。 ![]() ずらす回数は,最初の単純な14回から6回に減っています。 [プログラム例] private void シェルソート() { int i,j,h, Tmp; for(h = Data.Length / 2 ; h > 0; h /= 2) for(i = h; i < Data.Length; i++) { Tmp=Data[i]; for(j = i - h ; j >= 0 && Data[j] > Tmp; j -= h) Data[j + h]=Data[j]; Data[j + h]=Tmp; } }
(2)増分の選択 前の例では,等増分を4,2,1と変化させましたが, 以下のように,4−ソートの2グループをあわせたものが, 2−ソートのグループになってしまっています。 ![]() しかし,各段階のソートでなるべくかき混ぜるほうが, 各段階のソート結果を反映することになりますので, 効率よくなるはずです。 このためには,増分がお互いの倍数にならないようにします。 たとえば,次のようにします。 増分=1, 4, 13, 40, 121 (1から始めて3倍して1を加える) ただし,増分が大きすぎても効果がないことが知られていますから, 最大増分量は,配列の要素数/9を超えないようにします。 このようにして改良した方法が,以下のプログラム例です。 [プログラム例] private void シェルソート改良版() { int i, j, h, Tmp; for(h = 1; h < Data.Length / 9; h = h * 3 + 1); for( ; h>0; h /= 3) for(i = h; i < Data.Length; i++) { Tmp = Data[i]; for(j = i - h ; j >= 0 && Data[j] > Tmp; j -= h) Data[j + h] = Data[j]; Data[j + h]=Tmp; } }
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 上のタイトルをクリックします |
|||||||||||||||||||||