ここでは、自分自身を呼び出すことを関数の再帰呼出しという。
int型配列に格納されたN個のデータ(a[0]〜a[N−1])を昇順に整列する。整列の手順は以下のとおりである。
@与えられたデータ列の中央附近のデータa[2/N]を選ぶ。この値をsとする。
Asを基準とし、s以下のデータは左側に、s以上のデータは右側になるようにデータ列を分割する。分割の手順は以下に示す。
1)左端のデータをa[i](i=0)、右端のデータをa[j](j=N−1)とする。
2)a[i]から右へ向かって基準値s以上のデータを探す。
3)a[j]から左へ向かって基準値s以下のデータを探す。
4)i,jの値により以下の処理を行う。
ア)i<jの時a[i]とa[j]とを交換し、2)から繰り返す。
イ)i=jの時a[0]〜a[i−1]はすべてs以下、a[j+1]〜a[N−1]はすべてs以上となっており、データ列は2つに分割された。
ウ)i>jの時a[0]〜a[j]はすべてs以下、a[i]〜a[N−1]はすべてs以上となっており、データ列は2つに分割される。
B分割された左側のデータを同様に分割する。
C分割された右側のデータを同様に分割する。
D要素数が2つ以下になるまで分割を繰り返す。要素数が2つのときは、昇順になるようにデータを入れ替える。
関数名はsort()、渡される仮引数は、
pa:データが格納された配列のポインタ
n:データの個数
[プログラムの作成]
/*-----------------------------------------------
クイックソート
-------------------------------------------------*/
vold sort(int *pa,int n)
/*pa:データ列(配列)へのポインタ*/
/*n:データの個数*/
{
int s; /*基準値*/
int i,j; /*添字*/
if(n<=2){ /*要素数2以上*/
if(n==2)
if(*pa>*(pa+1))swap(pa,pa+1); /*昇順にする*/
return;
}
else{
s=*(pa+n/2); /*基準値の選択*/
i=-1; /*右から*/
j=n; /*左から*/
while(i<j){
while(*(pa+(++i))<s);
while(*(pa+(--i))>s);
if (i<j)swap(pa+i,pa+j);
}
if(i==j){
sort(pa,i); /*左側*/
sort(pa+i+1,n-i-1); /*右側*/
}
else{
sort(pa,i); /*左側*/
sort(pa+i,n-i); /*右側*/
}
}
}
/*-----------------------------------------------
データの交換
-------------------------------------------------*/
vold swap(int *pa,int *pb)
{
int t;
ta=*pa;
*pa=*pb;
*pb=t;
}
解説
【関数の再帰呼出し】 数学の漸化式のようにもとめた値を使って次の値を求めるときや、この例題のように同じ処理を範囲を変えて行いたい時、関数の再帰呼出しを用いると、直観的でスマートなプログラムを書くことができる。
再帰呼出しが行われると、渡された引数や関数内で定義されたオブジェクトなどは、新たな領域が確保され、呼出し側とはまったく切りはなされる。
【再帰からの脱出】 再帰呼出しでは、関数から自分自身を呼び出すため、再帰を脱出する条件が必ず必要である。そうしないと、永久に自分自身を呼び続けてしまう。再帰呼出しでは、一般に関数の形は以下のようになる。
Kansuu()
{
if(脱出条件){
脱出処理;
return;
}
else{
:
:
kansuu() ←再帰呼出し
:
}
}
練習問題へ選択メニューに戻る