1 データのブロック分割 2 各ブロックごとの処理(並べ換え) 3 ブロックの統合であり、クイックソートでは特に1のデータの分割にアルゴリズムのよさの秘密が隠されている。例を用いてクイックソートのアルゴリズムを解説しよう。
48 65 10 36 83 5 21 72ステップ01
48 65 10 36 83 5 21 72
ステップ02
21 65 10 36 83 5 48 72
さらに、ステップ02を続けると、5と65が入れ替わる。
21 5 10 36 83 65 48 72
以下、同様な操作を繰り返し、注目している点が交差するまで行なう。すると
21 5 10 36 83 65 48 72
が得られる。これは、基準値とした位置(左から4番目)を境に、左右ブロックに分割したことになる。左側には4番目のデータ(36)よりも小さいデータ、右側には大きいデータとなる。
ステップ1ー1
左側のブロックに対して、ステップ01、02を行なう。
21 5 10 5 | 21 10よって、5と21,10とに分割できる。
ステップ1ー1ー1
さらに、左側についてステップ01、02を行なう。この場合、5だけなのでなにもしない。
ステップ1ー1ー2
右側の21,10についてステップ01、02を行なう。
上記ステップ1ー1ー1、1ー1ー2により、
5 10 21
が得られる。
ステップ1ー2
83,65,48,72について同様にステップ01、02を行なう。よって、
5 10 21 36 48 65 72 83
が得られる。
基準点としたデータが、左、右いずれかのブロックに含まれる時と含まれない時がある。その詳細についてはプログラム6−4を見ていただきたい。ここでは、アルゴリズムの大体の考え方を理解できればよいと考えている。
クイックソートのプログラムは以下のようである。
1: void QuickSort( int data[], int upper, int lower ) {
2: int mid, tmp, i, j;
3:
4: i = upper;
5: j = lower;
6: mid = data[(lower+upper)/2];
7: do {
8: while( data[i] < mid ) i++;
9: while( mid < data[j] ) j--;
10: if( i <= j ) {
11: tmp = data[i];
12: data[i] = data[j];
13: data[j] = tmp;
14: i++;
15: j--;
16: }
17: } while( i <= j );
18: if ( upper < j ) QuickSort(data, upper, j);
19: if ( i < lower ) QuickSort(data, i, lower);
20: }
Quicksortメソッドは、プログラム内部でさらに自分自身を呼んでいる。つまり再帰的なアルゴリズムとなっている。先に示した例のデータを用いて実行の様子を表現すると、下記のような構造となっている。
( 48 65 10 36 83 5 21 72 )
|
|QuickSort(1,8)
−−−−− +−−−−−−−
| | |
( 21 5 10 ) ( 36 ) ( 83 65 48 72 )
| |
QuickSort(1,3)| |QuickSort(5,8)
−−− +−− −−+−−−−
| | | |
( 5 ) ( 21 10 ) ( 48 ) ( 65 ) ( 83 72 )
| |
QuickSort(2,3)| |QuickSort(7,8)
−−+−− −−+−−
| | | |
( 10 ) ( 21 ) ( 72 ) ( 83 )
よって分割したブロックを統合すると、
5 10 21 36 48 65 72 83となる。
クイックソートの計算時間量を評価してみよう。今回は、プログラム中の11〜13の実行回数をカウントすることで、オーダーを求めることにする。
1段目 QuickSort(1,n)では、入れ替えの起こる確率を1/2とすると約n/2回
実行される。
2段目 QuickSort(1,n/2)、QuickSort(n/2,n)では、入れ替えの起こる確率を1/2と
するとそれぞれ約n/4回実行される。二つの回数を合わせると、約n/2回
の実行となる。
3段目 4つの関数QuickSort(1,n/4)、QuickSort(n/4,n/2)、QuickSort(n/2,3n/4)、
QuickSort(3n/4,n)が実行されそれぞれ約n/8回の実行となる。これらを合
わせると約n/2回の実行となる。
4段目 同様に考えると8回のQuickSort関数を実行し、それぞれ約n/16回実行。
合わせると約n/2回の実行回数となる。
以上から、各段階では約n/2回の入れ替えが起こることがわかる。