プログラミング言語 C
C は 関数を 再帰的 (recursion) に 使用することができる。つまり 関数は (その内部で) 関数自身を 直接 または 間接に 呼び出してもよい。
数字を 文字列に 変換する関数 print_d() を 考えてみよう。
数字の場合、逆順生成という 性質をもつ。すなわち 低い桁の数字が 高い桁の数字より 先に得られる。
(そのため 出力時には) 逆順に プリントさせなければならない。
この問題には 2つの解がある。一つは 生成した順に 配列に格納し (do-while文を使って) 逆順に プリントする方法である。
もう一つの方法が 再帰を使う 解法で、逆順生成に 対処するため、関数内部で 関数自身を 呼び出すようにする。
- /* print_d.c */
- #include
- /* 数字 n を 10進法で プリントする */
- void print_d(int n)
- {
- if (n < 0) {
- putchar('-');
- n = -n;
- }
- /* 数字 n が 負の場合 はじめに 正の整数に 変換しておく */
- if (n / 10)
- print_d(n / 10);
- /* 数字が 2桁以上のとき 再帰関数を 呼び出す */
- /* このとき int型の 除算なので 小数点以下が 切捨てとなる */
- putchar(n % 10 + '0');
- /* 高い桁から 順に プリント */
- }
関数が 自分自身を 再帰的に呼び出すと、それぞれの 呼び出しごとに すべての 自動変数が 一新され、以前とは まったく 独立した セットになる。
例えば print_d(123) では 最初の print_d() では n = 123 である。
第2レベルの print_d() では '12' が 渡り、つぎに そのうちの '1' が 第3レベルの print_d() に 渡る。
第3レベルの print_d() は '1' を プリントしてから 第2レベルに 戻る。第2レベルのprint_d() で '2' が プリントされ、最初のレベルへと 戻る。そして '3' が プリントされ (この関数は) 終了となるわけである。
再帰を使った もう一つの よい例が quicksort すなわち C.A.R.Hoare が 1962年に 考えだした ソートアルゴリズムである。
ある配列が 与えられたとき、 まず 1つの要素 (下のコードでは int n) を 選んだら、その要素より 小さいパートと、等しいか より大きいパートとの 2つの サブセットに 分割する。
次に 同じプロセスを 再帰的に 2つの サブセットに 適用していく。
そして サブセットが 2より 少ない 要素を もつようになれば このソートは 必要なくなり 再帰は 終了する。
- /* q_sort.c */
- void q_sort(int v[], int left, int right)
- {
- int i, last;
- void swap (int v[], int i, int j);
- if (left >= right)
- return;
- /* 配列が 2 より 少ない 要素に なったときは */
- /* 以下の プログラムは 実行されない */
- swap (v, left, (left + right) / 2);
- last = left;
- /* 分割要素を サブセットの始め = v[0] に 移動させる */
- for (i = left + 1; i <= right; i++) /* 分割 */
- if (v[i] < v[left])
- swap (v, ++last, i);
- /* for文は ここまで */
- swap (v, left, last); /* 分割要素を 回復 */
- q_sort(v, left, last - 1);
- q_sort(v, last + 1, right);
- /* 再帰関数を 使い 左右それぞれの サブセットを ソートしていく */
- }
- /* swap.c */
- /* スワップ関数 */
- void swap (int v[], int i, int j)
- {
- int tmp;
- tmp = v[i];
- v[i] = v[j];
- v[j] = tmp;
- }
再帰を使う場合、処理中の値の スタックを 保持しなければならない。そのため メモリの 節約には ならないし また 速度も (使用しないときと 比べ) 速いとはいえない。
しかし 再帰を使った プログラムでは (コード自体が) より コンパクトになり、使わない プログラムに 比べて ずっと 書きやすく また 理解するのが 容易と なることが 多い。