Home >> Columns >> Algorithms on Integer


Javaでの整数を使ったアルゴリズム


H−1.整数を使ったアルゴリズム

☆ユークリッドの互助法

2つの整数の変数になんらかの値(1以上の正の数)が代入されているとします。この2つの整数の最大公約数を求めるアプリケーションプログラムを作りなさい。クラス名は、CommonDivisorとします。求め方は、繰返しを使って求めていきます。更に2つ変数を用意し、一方には大きい方の数を、もう一方には小さい方の数を代入します。繰返しの中で、大きい方の数と小さい方の数が等しい、あるいは、大きい方の数が小さい方の数で割りきれれば(剰余が0になる)、小さい方の数が最大公約数ですから、繰返しを脱出します。そうでなければ、大きい方の数を小さい方の数で割った余り(剰余)を求めます。今度は、大きい方の数を、元の小さい方の数を代入し、小さい方の数には、この剰余を値を代入して、もう一度繰返しを行ないます。このアルゴリズムは、ユークリッドの互除法として知られています。ユークリッドは、古代アレクサンドリアの数学者です。(大きい方の数、小さい方の数)の組合せで記述しますと、例えば(64, 28)の2つの数の場合は、以下のようにして求まります。

		(64, 28)→(28, 8)→(8, 4)→4が最大公約数
		
最大公約数を求めるやり方です。古代ギリシャのユークリッドが考えました。2つの正の整数の最大公約数は、大きい方の数から小さい方の数で割りきれればその小さい方の数が最大公約数であるというものです。割りきれなければ、2つの数の差と小さい方の数で同じ事を繰り返します。

	int  gcd(  int   a,   int   b  )  { 
		while  ( true )  {
			if ( a > b )  {
				if  (  a %  b == 0 ) { return b; }  else { a = a - b; }
			} else  {
				if ( b %  a == 0 ) { return a; } else { b = b - a; }
			}
		}
	}
		
あるいは、2つの数の差を取る替わりに、大きい数と小さい数の余りを取るというやり方もあります。この方が早く解に辿り着けます。再帰を使って記述してみました。

	int  gcd(  int   a,   int   b  )  { 
		if ( a > b ) { return   ( a%b == 0 ) ? b :  gcd(  b,  a %  b ); }
		else { return (b%a == 0 ) ? a : gcd( a, b %  a ); }
	}
		

☆課題H-2 ユークリッドの互除法

再帰呼出しを利用しないで、余りを求めながら、最大公約数を求めるメソッドを作りなさい。 2つの変数を宣言し、整数値を代入しておきます。繰返しに突入する前に、更に2つ変数を宣言します。if式などを用いて、この2つの変数に大きい方の数と小さい方の数を代入しておきます。繰返しの中では、if文を使って条件をテストし、2つの変数が等しいか、小さい方の数で割りきれれば、break文で脱出します。そうでなければ、別の変数に小さい方の数を代入しておいて、大きい方の数を示す変数に小さい方の数を、小さい方の数を示す変数に剰余を代入します。

☆課題H-2 ユークリッドの互除法の仕上げ

2つの整数をコンソールから入力してもらい、最大公約数を求めて表示するプログラムを作成しなさい。 クラス名は、GreatestCommonDiviserとします。引き算で行なう方法と、剰余で行なう方法について、 途中で求まる2つの数をコンソールに表示して、どのように収束して求まっていくのかの過程についても 表示するようにしなさい。

☆課題H-3 最小公倍数を求める

最小公倍数を求めるプログラムを、最大公約数を求めるメソッドを利用して作りなさい。

☆エラトステネスの篩い(ふるい)

3から100までの数について素数であるかどうか判定し、素数だけを表示するアプリケーションプログラムを作りなさい。素数というのは、1とその数以外で、割り切れる数がない数のことです。1と2は素数です。クラス名は、PrimeCheckerとします。繰返しをネストさせ、外側の繰返しでは、3から100までループ変数を動かしていきます。内側の繰返しでは、2から外側のループ変数の値未満まで、内側の繰返しのループ変数を動かしていきます。もし、内側の繰返しのループ変数で外側のループ変数が割り切れれば、素数でありませんので、内側の繰返しを脱出します。脱出したときに、内側のループ変数の値が外側のループ変数の値よりも小さければ、素数ではないことがわかります。このアルゴリズムの改良版は、同じく古代アレクサンドリアの数学者のエラトステネスによって考え出されています。

☆実習H-1 エラトステネスの篩を求めるメソッドを作って利用する

ヒント: 内側の繰返しのループ変数は、予め繰返しに入る前に宣言して、2を代入しておきます。

☆課題H-4 ピタゴラス数を求める

3の二乗+4の二乗=5の二乗でした。このような関係にある3つの数を、 1〜100までの間で求めなさい。

☆チャールズ・バベッジの階差機関

19世紀のイギリスにおいて、チャールズ・バベッジは、歯車を使って階差機関を試作しました。方程式の結果を記した数列は、階差を取っていくと、次数の高い方程式も、すべて足し算で計算できます。たとえば、xの2乗について考えてみましょう。1から順に初めて、計算結果を求めていき、その階差を取ると次のようになります。
x:   0  1  2  3   4   5   6   7   8   9
x2:  0  1  4  9  16  25  36  49  64  81
     \/ \/ \/ \/  \/  \/  \/  \/  \/
第1階差: 1   3  5  7   9   11  13  15  17
      \/ \/ \/  \/  \/  \/  \/  \/ 
第2階差:  2   2   2   2   2   2   2   2

☆課題H-3 階差を使って二次方程式の答えを表示するプログラム

これを利用し、任意のpx2 + qx + rという二次方程式について、掛け算を使わないで、計算するプログラムを作りなさい。整数で行ないなさい。pとq、およびrには、適当な整数の定数を代入しておきます。xを1から10ぐらいまで変化させ、そのときに、その二次方程式に適用したときの計算結果を出すようにfor文で作ります。もちろん、第1階差の初項と第2階差を求めるとき以外は、掛け算を使わないで、足し算だけで求めていきます。クラス名は、Differentialにします。なお、チャールズ・バベッジは、階差機関を発展させていろいろな方程式を求めることができる解析機関を歯車で試作しようとしました。これは、現在のコンピュータの元祖の一つになっています。

ヒント:px2 + qx + rの第1階差は、p*(2 *x+1)+q(すなわちp*(x+x+1)+q)になります。第2階差は、2p(すなわちp+p)になります。x=0のときの、最初の計算結果、第1階差、第2階差を求めておき、それを求められる数にxが達するまで足し合わせていきます。すなわち以下のように計算結果には、第1階差を足し込みますし、第1階差には第2階差を足し込みます。ここで、Javaの自己参照代入分から1つ前と新しい値は、1つの変数で表わせることを思い出しましょう。

答え = 1つ前の答え + 第1階差
第1階差 = 1つ前の第1階差 + 第2階差

☆その他の計算

中心のx, y座標を指定して、円の半径を指定して、その円に外接(頂点が演習のどこかに接する)、正n角形を 描画するようなメソッドdrawPolygon( int x, int y, int radius, int n )を定義して、startメソッドから呼び出して 使ってみなさい。

今月のカレンダーをダイアログに表示するプログラムを作成しなさい。 タートル・グラフィックスのgetYear( )、getMonth( )などを利用しなさい。 DisplayCalendarとします。まずは、簡単にその月が日曜日始まりで、31日あるものとして始めます。 その月が何日あるかは、小の月、大の月の条件を考えて下さい。2月は閏年のことも考えてください。 その月が何曜日から始まるかは、getDay( )とgetWeekDay( )から計算します。たとえば、getDay( )が4で、 getWeekDay( )が6だったら、その月の1日は水曜日始まりだというのがわかります。 その月の始まる曜日は、(今日の曜日+7 -(今日の日-1)%7 ) % 7 で求められます。


H−2.探索のアルゴリズム

配列のときに説明したように、配列から特定の要素を探し出すのは、よく必要とされる操作の典型的な例です。これを線形探索法(Linear Search)と2分探索法(Binary Search)の2つのアルゴリズムで記述してみましょう。整数の配列 aをパラメータとして受け取り、この配列からパラメータtargetが示す値を持つ要素を検索します。発見したらその要素の添え字を返し、発見しなかったら-1を返すようにします。

☆線型検索法

線形探索法は、ただ単にはじめから順番にみていくものです。一番最後の方にあれば、配列の要素の個数分だけ探索が遅くなってしまいます。

	int   linearSearch( int target ,  int  a[ ]  )  {
		for ( int   i=0;  i < a.length; i++ ) {
			if  (  a[  i  ] == target ) { return  i; }
		}
		return  -1; 
	}
		

☆2分検索法

2分探索法は、配列が小さい順に整列されているときだけ使える探索法です。電話帳や辞書を調べるみたいに、真ん中辺を取り出して、それが目的とする値よりも小さければ後ろ半分を、大きければ前半分を調べにいきます。以下のメソッドで調べる範囲の下限の添え字をleastが、上限の添え字をmostが示しています。変数middleは丁度真ん中を調べるいくための添え字です。

	int   binarySearch( int target, int  a[ ]  ) {
		int  least = 0,  most = a.length;
		while ( least <= most  ) {
			int middle = (least+most) / 2;
			if  ( a[ middle ] >  target ) {  most = middle + 1; }
			else if ( a[ middle ] < target ) {  ieast= middle -1; }
			else {  return  middle; }
		}
		return -1; 
	}
		
2分検索法を使えば、配列の要素がn個あったとしても、1回の比較で件数を半分にしていきますので比較回数は、log2 n回で終わります。要素の個数が膨大になっても、比較回数は非常に少なくてすみます。

☆実習H-2 2分検索法をArrayListを使って求める

ArrayListを使って2分検索法を実現するメソッドを作成し、利用して見なさい。


H−3.整列のアルゴリズム

■整列法について

☆整列法とよく知られている整列法

小さいものから(大きいものから)順番に並べなおすことを整列(Sorting)あるいは単にソート(Sort)と呼んでいます。整列のアルゴリズムは、昔からよく研究されてきました。整列はアルゴリズムによって、プログラムが高速になったり、低速になったりする典型的な例だからです。有名な整列法について、分類して紹介します。
▼簡単だが遅い整列法
データの件数がn個あると、整列するのにn〜n2回比較や交換を行なわないといけないものです。これには、直接選択法(Straight Selection)、直接交換法(Straight Swapping)、直接挿入法(Straight Insertion)などがあります。直接交換法は、配列の要素が泡が登っていくように交換していくことから、バブルソート(Bubble Sort)あるいは泡立ち法とも呼ばれています。バブルソートには、改良型(Improved Bubble)もあります。
▼やや高速な整列法
バブルソートをさらに改良したものは、比較的少ない比較・交換回数で整列させることができます。間隔の空いたバブルソートとしてシェルソート(Shell Sort)、双方向にバブルソート行なうものとしてシェーカーソート(Shaker Sort)があります。
▼複雑で高速な整列法
データの件数がn個あると、整列するのに log2 n 回の比較・交換で済ませるものです。有名なヒープソート(Heap Sort)や、クィックソート(Quick Sort)がこれにあてはまります。また、大容量データの場合は、マージソート(Merge Sort)が知られています。

■簡単な整列法のプログラミング

以下に整数型の配列 aをパラメータとして受け取り、要素を小さい順にならべるアルゴリズムをメソッドとして記述してみましょう。簡単な「直接」という名前がついた3つの整列法だけをここでは紹介します。

☆直接選択法

配列の中で一番小さいものを探して、その要素と先頭の要素を交換します。これを配列の先頭から最後に向かって順に繰り返して行けば、小さいものから並ぶことになります。

	void  straightSelection(  int  a[ ]  ) {
		int  min;
		for ( int  i = 0; i < a.length-1; i++ ) {
			min = i;
			for ( int  j=i+1; j < a.length; j++ ) {	// 一番小さいものを探す
				if ( a[ min ] > a[ j ] ) {  min = j;  }
			}
			int  temp = a[ min ]; a[ min ] = a[ i ];  a[ i ] = temp;  // 現在の先頭の要素と交換する
		} 
	}
		
直接選択法による並べ替えの例として、int a[ ] = { 19, 64, 3, 30, 10, 39, 20, 53 };という初期値が代入されている配列を考えます。図において、↑が変数が指している要素を示します。枠が現在対象となっている範囲です。
直接選択法のソーティングの様子:
19 64 3 30 10 39 20 53
↑i   ↑min
3 64 19 30 10 39 20 53
  ↑i      ↑min
3 10 19 30 64 39 20 53
    ↑i, min
3 10 19 30 64 39 20 53
      ↑i      ↑min
3 10 19 20 64 39 30 53
         ↑i   ↑min
3 10 19 20 30 39 64 53
           ↑i, min
3 10 19 20 30 39 64 53
             ↑i ↑min

☆直接交換法

一つ手前と一つ後を比較して、手前の方が大きければ交換します。これを配列の終わりの方から始めて、先頭まで繰り返します。この操作を現在の先頭を後ろに1つずつずらして、配列の最後まで繰り返して行けば、小さい順に並んで行きます。

	void   bubbleSort(  int  a[ ]  ) {
		for ( int  i=1; ifor ( int  j=a.length-1; j >= i ; j-- ) {
				if ( a[ j-1 ] > a[ j ] ) {  int temp = a[ j -1 ];  a[ j - 1 ] = a[ j ]; a[ j ] = temp;  }
			}
		}
	}
		
先ほどと同じ配列を使って直接選択法による並べ替えの例を見てみます。図において、←が交換されて前に移動することを示しています。枠が現在対象となっている範囲です。
直接交換法のソーティングの様子
19←64←3 30←10 39←20 53

3 19←64←10 30←20 39 53

3 10 19 64←20 30 39 53

3 10 19 20 64←30 39 53

3 10 19 20 30 64←39 53

3 10 19 20 30 39 64←53

3 10 19 20 30 39 53 64

☆直接挿入法

2番目から1つずつ要素を選びます。先頭に向かって、その選ばれた要素よりも大きいものがいる間は後ろにずらす。最後にあいたところに、選んだ要素を入れます。トランプでカードが配られたときに、手の中で整列していくときを思い出してください。そのときの整列法です。

	void   straightInsertionSort( int [  ]  a) {
		for ( int  i=1; i < a.length; i++)  {
			int j,  target = a[  i  ];
			for (  j=i -1;   j >= 0  &&  a[ j ]>target ;  j-- ) {  a[ j+1] = a[ j ];  }
			a[ j+1 ] = target; 
		}
	}
		
直接挿入法による並べ替えの例を同じ配列でみていきます。図の中で、↑targetが示すのが現在対象となっている要素です。→の左側にある要素がその要素を入れるために1つ後ろにずらされます。枠で囲まれた範囲が、整列が終わった範囲を示します。
直接挿入法のソーティングの様子:
19 64 3 30 10 39 20 53
  ↑target
19→64→3 30 10 39 20 53
    ↑target
3 19 64→30 10 39 20 53
      ↑target
3 19→30→64→10 39 20 53
         ↑target
3 10 19 30 64→38 20 53
           ↑target
3 10 19 30→38→64→20 53
             ↑target
3 10 19 20 30 38 64→53
               ↑target
 

☆3つの整列法の比較

3つの整列法を使ったときに、要素の数がn個あったときに、最良の場合(たとえば配列が元々整列してあった場合)と平均と、最悪の場合について比較回数と交換回数がどれくらい行なわれるのかがわかっています。この中で直接挿入法は、予め整列されている場合は、比較回数も交換回数もn回で済むところが抜きん出ています。実際のプログラムで使われるときを考えますと、整列済みの配列に要素を1つだけ追加して、もう1回整列し直すという場合がほとんどです。このときに、直接挿入法は他の2つに比べて高速に(n回で)整列することができます。
整列法における比較回数と交換回数の比較
 

☆課題H-4 3つの整列法をArrayListを使って求める

ArrayListを使って上記の3つの整列法を実現するメソッドを作成し、利用して見なさい。


H−4.再帰を使ったアルゴリズム

■再帰呼出しとは

再帰呼出し(Recursive Call)とは、あるメソッドから、同じメソッドを直接(あるいは間接的に)呼び出すことを指します。 この場合、呼び出されるメソッドは再帰呼出しに対応していないといけません。 多くの場合は、仮引数を必要とし、その引数の値に応じて、一般的に、次のように処理を分けて考えます。

 基底レベル…それ以上は、再帰的に呼び出されないレベル、このレベルの処理を考える
 それ以上のレベル…再帰的な呼出しがどこかに入る、前後の処理を考える

たとえば、インスタンス変数に値を足していくことを考えます。

		
	int sum; // インスタンス変数
	public void start( ) {
		sum = 0; // 最初は0に初期化
		adder( 10 ); // レベル10で呼出し開始
	}
	
	void adder( int level ) {
		if ( level <= 1 ) { // 基底レベル(levelが1以下だったら)
			sum = sum + level;
			printLine( "Sum " + sum + " at the level " + level );
	   } else { // それ以上のレベル
			sum = sum + level;
			printLine( "Sum " + sum + " at the level " + level );
			adder( level - 1 ); // レベルを1つ小さくして再帰呼出し
		}
	}
		

最初の呼び出されるときの実引数が4の場合、以下の図のように引数が渡されていきます。

さて、このプログラムを実行してみると次のように表示されます。

		
	Sum 10 at the level 10
	Sum 19 at the level 9
	Sum 27 at the level 8
	Sum 34 at the level 7
	Sum 40 at the level 6
	Sum 45 at the level 5
	Sum 49 at the level 4
	Sum 52 at the level 3
	Sum 54 at the level 2
	Sum 55 at the level 1
		

これは、再帰呼出しを使わなくても、以下のように繰返しで記述しても同じ結果が得られます。

		
	int sum;
	public void start( ) {
		sum = 0;
		int  level = 10;
		while ( level >= 1 ) {
			sum = sum + level;
			printLine( "Sum " + sum + " at the level " + level );
			level = level - 1;
		}
	}
		

すなわち、ある意味で繰返しと再帰呼出しは同じものと考えることができます。 また、以下のような定理が存在していますが、再帰で考えるのが面倒な場合は、繰返しで実現することが多いと 思われます。

 すべての繰返しは、再帰呼出しで実現できる(たぶん逆もあり)

☆実習H-9 再帰呼出しによる総和を求める

上記のプログラムを実際に入力して描画してみましょう。クラス名はPracticeH409にて。

■再帰呼出しを使ったタートルグラフィックスの描画

しかしながら、再帰呼出しを使うと、タートルグラフィックスにおいては、複雑な図形を僅かな量の プログラムで記述することができます。 例として、木のような形を描画して見ましょう。まず、基底レベルを考えます。 基底レベルでする処理は、「Vの字を描くもの」です。 右側の斜線を描いて、左側の斜線を描きます。 プログラムの該当する部分は、以下のような感じになります。


	turtle.rotate( 20 );	// 20度右に傾けて
	turtle.forward( 40 );	// 斜線を描いて
	turtle.back( 40 );	// 戻ってくる
	turtle.rotate( -40 );	// 左に40度傾けて
	turtle.forward( 40 );	// 斜線を描いて
	turtle.back( 40 );	// 戻ってくる
	turtle.rotate( 20 );	// 垂直に上を向いておしまい
		

これが基底になるように、プログラムを記述してみます。再帰呼出しの挿入ポイントは、forwardで描いた先です。 そこに更に、同じものを描くように再帰呼出しを入れます。以下のプログラムの断片では、インスタンス変数と startメソッド、およびdrawTreeメソッドを記述しています。その下の図のような木が描けました。

		
	Turtle turtle;
	
	public void start( ) {
		turtle = new Turtle( this );
		drawTree( 5 );
	}
	
	void drawTree( int level ) {
		if ( level <= 1 ) {  // 基底レベル
			turtle.rotate( 20 );
			turtle.forward( 40 );
			turtle.back( 40 );
			turtle.rotate( -40 );
			turtle.forward( 40 );
			turtle.back( 40 );
			turtle.rotate( 20 );
		} else {  // それ以上のレベル
			turtle.rotate( 20 );
			turtle.forward( 40 ); // 右の先端に行かせる
			drawTree( level-1 );  // 再帰呼出し、ただし、レベルを一つ下げる
			turtle.back( 40 );
			turtle.rotate( -40 );
			turtle.forward( 40 ); // 左の先端に行かせる
			drawTree( level-1 ); // 再帰呼出し、ただし、レベルを一つ下げる
			turtle.back( 40 );
			turtle.rotate( 20 );
		}
	}
		

上記のメソッドは、基底レベルとそれ以上のレベルで、ほとんど同じことをしています。 プログラムが長くなるので、逆に条件分岐で再帰呼出しをするかどうか、途中に入れるように drawTreeメソッドを記述してみました。これで、プログラム的にだいぶ短くなりました。

		
	void drawTree( int level ) {
		turtle.rotate( 20 );
		turtle.forward( 40 );
		if ( level > 1 ) { drawTree( level-1 ); } // レベルが1よりも大きいときは再帰呼出し
		turtle.back( 40 );
		turtle.rotate( -40 );
		turtle.forward( 40 );
		if ( level > 1 ) { drawTree( level-1 ); } // レベルが1よりも大きいときは再帰呼出し
		turtle.back( 40 );
		turtle.rotate( 20 );
	}
		

次にレベルに応じて、線の太さを変えてみます。だんだん先に行くに従って、レベルが低くなります から、線が細くなります。再帰呼出しをして戻ってきたら、線のレベルの元に戻します。 線のレベルを戻す文を外に出してありますが、条件分岐のブロックの中に入れても構いません。 drawTreeメソッドの記述を下に示します。 このように太さを変えてみると、その下の図のようになりました。

		
	void drawTree( int level ) {
		turtle.setPenWidth( level ); // レベルに応じた太さを設定
		turtle.rotate( 20 );
		turtle.forward( 40 );
		if ( level > 1 ) { drawTree( level-1 ); }
		turtle.setPenWidth( level ); // そのレベルに応じた太さを再設定
		turtle.back( 40 );
		turtle.rotate( -40 );
		turtle.forward( 40 );
		if ( level > 1 ) { drawTree( level-1 ); }
		turtle.setPenWidth( level ); // そのレベルに応じた太さを再設定
		turtle.back( 40 );
		turtle.rotate( 20 );
	}
		

今度は、線の長さをレベルに応じて変えてみます。このようにすると、 最初はレベルが高いので長い線が描かれますが、レベルが低くなるに従って、 線の長さが短くなります。自然の木に少し近いようになります。なお、線の長さは、レベル×10ドット という形にしました。drawTreeメソッドの記述を下に示します。 レベル5で呼出しを始めると、その下の図のようになりました。

		
	void drawTree( int level ) {
		turtle.rotate( 20 );
		turtle.forward( 10*level ); // レベルに応じて長さを変える(右側)
		if ( level > 1 ) { drawTree( level-1 ); }
		turtle.back( 10*level ); // その分だけ戻る
		turtle.rotate( -40 );
		turtle.forward( 10*level );  // レベルに応じて長さを変える(右側)
		if ( level > 1 ) { drawTree( level-1 ); }
		turtle.back( 10*level );  // その分だけ戻る
		turtle.rotate( 20 );
	}
		

レベルに応じて、色を変えるのも良いかも知れません。今度は、基底レベルに達したら、 赤い実を描くようにしてみました。実は単なる正30角形です。 実を描いたら黒色に戻すようにしています。 メソッド名も少し変更して、「drawFruitTree」としました。 その下にどのような木が描けたのかを表示しました。

		
	void drawFruitTree( int level ) {
		if ( level <= 1 ) {  // 基底レベル
			turtle.setPenColor( Red ); // 赤色にして
			turtle.rotate( -84 ); // 左に回転させて
			for ( int i=0; i < 30; i++ ) { // 実を描く
				turtle.forward( 3 );
				turtle.rotate( 12 );
			}
			turtle.rotate( 84 ); // 回転した分戻す
			turtle.setPenColor( Black ); // 黒に戻す
		} else { // それ以上のレベル
			turtle.rotate( 20 );
			turtle.forward( 10*level ); // 枝の長さはレベルに応じて変える
			drawFruitTree( level-1 );
			turtle.back( 10*level );
			turtle.rotate( -40 );
			turtle.forward( 10*level );
			drawFruitTree( level-1 );
			turtle.back( 10*level );
			turtle.rotate( 20 );
		}
	}
		

☆実習H-10 再帰呼出しによる木の描画

上記のプログラムを実際に入力して描画してみましょう。クラス名はPracticeH410にて。

☆実習H4-11 コッホ曲線の記述

コッホ曲線は、基底においては単なる線を描きます。ところが、次のレベルでは、それを3つの線分に分けて、 真ん中に山を作ります。それぞれの線分に対して、同じように山を作っていったら、下の図のようになります。 かなり有名な曲線です(折れ線だと思うのですが、あるレベル以上になると曲線のように見えてくるので、「曲線」という名前がついています)。 クラス名はKochCurveにて。

☆課題H-6再帰的な星の描画

星のそれぞれの端(5つあります)に来ましたら、そこで、より小さな星を描きます。これを再帰的に繰り返すと以下のような図になります。 これは中央の星を中心にして、4レベルまで描画したものになっています。クラス名は、RecursiveStarsにて。

☆実習H-12 ヒルベルト曲線の記述

■値を戻すメソッドの再帰呼出し

・基底レベル…その演算の元となるような値を返す
・それ以上のレベル…nのときと、n-1のときの関係を再帰呼出しを使って記述する
		
	long  factorial( int  n ) {
		if ( n <= 1 ) { return 1; }
		else { return  n * factorial( n-1 ); }
	}
		
	
	int  summetion( int  n ) {
		if ( n <= 0 ) { return 0; }
		else { return  n + summetion( n-1 ); }
	}
		

☆実習H-13 階乗と総和の記述

上記のメソッドを用いて、与えられた数の階乗と(1からのその数までの)総和を求めるようなプログラムを作成します。

	
	int  fibonatti( int  n ) {
		if ( n <= 0 ) { return 0; }
		else if ( n == 1 ) { return 1; }
		else { int sum = fibonatti( n-1 ) + fibonatti( n-2 );  }
	}
		

☆実習H-14 フィボナッチ数の出力

上記のメソッドを用いて、100個までのフィボナッチ数を端末に出力するようなプログラムを作成します。

■再帰を使った整列法


<<Functions ⋏ Return to Columns >>Integers