アルゴリズムとデータ構造
演習第 4 回
再帰

再帰(アルゴリズムC 第1巻 p.59) に関する演習です。 再帰のコツは、ループと同様に、まず最初に終了条件を考えることです。

問題1印刷用 PostScript

(1) 次のような数列がある。これらの数列の漸化式を書きなさい。

(2) 以下のような関数 rule() がある(教科書とは若干異なる)。 関数 mark() は定規に線を引く関数であり、 例えば mark( 13, 3 ) は 13 の位置に高さ 3 の線を引く。 ここで、rule( 4, 12, 3); を実行した場合、 定規にはどのように線が引かれていくかを、順番に図示しなさい。

void rule(int left, int right, int height){
  int middle = (left+right)/2;
  if( height>0 ){
    mark(middle, height);
    rule(middle, right, height-1);
    rule(left, middle, height-1);
  }
}

(1) は漸化式を作る問題です。例えば、初項 1、等差 1 の 等差級数 f(n) = n + (n-1) + ... + 2 + 1 の漸化式は このようになります。
f(n)=n+f(n-1),f(0)=0

ホーナー法は高次多項式を (ax + b) の形に展開していく方法です。 例えば、f(x) = 1x4 + 2x3 + 3x2 + 4x + 5
をこの方法で展開すると次のようになります。
ホーナー法での展開

(2) は再帰で実行される順番を考える問題 (アルゴリズムC 第1巻 p.62) です。 例えば mark(13,3) を実行すると、次のような線が 引かれることになります。
mark(13,3)

この mark() 関数の引数が、どういう順番で何になるかを考えて、 図に書いてみてください。

問題2

次の計算を行なう関数を再帰で書きなさい。

また、main() 関数でそれらの関数を呼び出し、 以下の値を計算させて表示させなさい。

実行例:
% ./a.out
10! = 3628800
2^0 + 2^1 + 2^2 + ... + 2^9 = 1023
fibonacci 20: 6765
f(2) = 57.00

関数を作る場合、問題1で考えた漸化式が参考になると思います。 例えば、このような漸化式
f(n)=n+f(n-1),f(0)=0
を関数にすると、次のようになります。

int tousa(int n){
  if( n==0 ){
    return 0;
  }else{
    return n + tousa(n-1);
  }
}

同様にして、他の関数も作ってみてください。 また、ホーナー法を用いる関数では簡単のため、 係数 an は次のようにグローバルな配列として宣言しても良い。

#define N 4
double a[N+1] = { 1, 2, 3, 4, 5 };

配列 a と展開式はこのように対応します。
展開式と配列の対応

問題3

ex04-3-skel.c は、実行すると star.ps という PostScript ファイルを生成する。 これを表示すると次のような画像になっている。
フラクタルの星
このプログラムを変更して、 このような画像 にしなさい。
フラクタルの星(アウトライン)

ex04-3-skel.c の中で、描画しているのは star 関数 (アルゴリズムC 第1巻 p.68) です。 この関数を変更してください。この関数の中で使われている line 関数は 線を引く関数で、例えば line(1,2,3,4) とした場合は、 座標 (1,2) から (3,4) までの線が引かれます。

これ、結構難しいです。 できた人はコッホ曲線にも挑戦してみてください。


Written by わかまつなおき