第12回:乱数と再帰呼び出し (12/10)


第10回演習:解答例


情報処理・演習2 2008年度  中間演習 (12/3)

まず前回の演習のプログラムを動かしてみましょう.

1 次に示すアルゴリズムとプログラムは,自然数aとbの最大公約数をユークリッドの互除法により求めるものである.

[アルゴリズム]

  1. 入力を a, b (a ≧ b) とする.違うならば入れ替えを行う.
  2. b = 0 なら, a を出力してアルゴリズムを終了する.
  3. a が b で割り切れるなら,繰り返しを終了.
  4. a を b で割った余りを新たに a とし,更に a と b を取り替えて アルゴリズムの3. が成り立つまで行う.
  5. b を出力してアルゴリズムを終了する.

[プログラム]



#include <stdio.h>

int gcd (int a, int b)
{
    int tmp;

    if(a < b) {
	(A)
    }
    
    if( (B) ) {
	return a;
    }

     while( (C) ) {
	(D)
    }
    
       return b;
}

void main()
{
    int a, b;

    printf("Input A="); scanf("%d", &a);
    printf("Input B="); scanf("%d", &b);

    printf("最大公約数は,%d です.¥n", gcd(a, b));
}

(1) (A),(B),(C),(D)の空欄には,それぞれプログラム(一行とは限らない)が入る.(A)はアルゴリズムの1,(B)はアルゴリズムの2,(C)はアルゴリズムの3,(D)はアルゴリズムの4,最後のreturn b; はアルゴリズムの5に相当する部分の一部又は全部である.それぞれの空欄に当てはまるプログラムを答えよ.

(2) このプログラムを実行して,変数aに54,変数bに98を入力したとき,(D)は何回実行されるか.

(3) この最大公約数を求めるgcd関数を用いて,最小公倍数と最大公約数の関係を利用して,最小公倍数を求めるプログラムを作成したい.自然数aとbの最小公倍数を求めるプログラムのmain関数部分を答えよ.

2 あるクラスの生徒20人の身長(実数)が順に並んだファイルsincho.txtがある.

sincho.txt の中身
←1番目の身長
←2番目の身長
←20番目の身長

(1) 実数の配列と配列の要素数を渡すと,全ての要素の平均値を求めて戻り値として返す関数averageを定義せよ.

(2) ファイルから身長を配列に読み込み,クラスの生徒の平均身長を求め,結果を画面に表示するプログラムを,前問で作成したaverage関数を利用して作成せよ.ただし,関数の定義部分は,解答に含めなくても良い.

3 キーボードから文字列を入力し,何文字入力されたかを画面に表示するプログラムを作成せよ.


関数の再帰呼び出し

関数の新しい使い方を学ぶ.

C言語では,関数の中から自分自身を呼び出すことができる.(これを再帰という.)

例えば,階乗を求める関数において, n! = n * (n-1)! ,即ち階乗の計算自身が,階乗を繰り返し行うことで表されることから,この性質を利用する計算法について考えよう.


#include <stdio.h>

/* ある数 n の階乗 n! を求めるプログラム */
/* 再帰関数バージョン*/
int fact(int n)
{
    if (n == 0) {
        return 1;                /* n = 0 の場合は 1 を返す.0 の階乗は 1 */
    } else {
        return n * fact (n-1);  /*  自分自身 factを呼び出す.引数として n-1 を渡している.  */
    }
}

void main()
{
    int n;

    printf("n=");
    scanf("%d", &n);

    printf("n! = %d ¥n", fact(n) );
}

関数の再帰呼び出しを上手に利用することにより, for や while が無くても,繰り返し文が実現できる.
但し,再起呼び出しがいつか必ず終わるような条件判定または処理を組み込んでおく必要がある.


乱数

さらに,ゲームなどのプログラムを作成するのに必ず必要となる乱数について説明する.
乱数を用いれば、じゃんけんや,おみくじなど簡単なゲームを作れます.
「でたらめな数」を乱数といい,プログラミングの重要なテクニックになっています.まずは,乱数の使い方を見てみましょう.
まず,randomize()で,乱数を初期化しておきます.乱数を取り出すには,rand()を使います.これは,



#include <stdlib.h>
#include <stdio.h>

void main( )
{
    int i;

    randomize();    // 乱数発生ルーチンの初期化
    printf("0 から 99 の間の 10 個の乱数¥n¥n");
    for(i=0; i<10; i++)
       printf("%d番目の数 %d¥n", i+1, rand() % 100);
}


演習課題

(1) 乱数を用いて,0をグー,1をチョキ,2をパーとするじゃんけんのプログラムを作成せよ.

(2) 1.のプログラムを用いて3以上を入力するまでじゃやんけんを続ける関数を作成せよ.


#include <stdio.h>
#include <stdlib.h>

void jyanken(int you)
{
	int cpu;

	randomize();
	cpu = rand() % …;
	
	//じゃんけんのプログラム
	…
}

void main()
{
	int you;
	
	printf("--------じゃんけん----------¥nあなたの手を決めてください:¥n 0:グー,1:チョキ,2:パー,3:終了");
	scanf("%d",&you);
	
	……

}

(3) 中間演習の問題1のアルゴリズムを以下のように変えて,関数の再帰呼び出しを用いたプログラムを作成せよ.

[アルゴリズム]

  1. 入力を a, b (a ≧ b) とする.違うならば入れ替えを行う.
  2. b = 0 なら, a を出力して終了する.
  3. a が b で割り切れるなら,b を出力して終了する.
  4. a を b で割った余りを新たに a とし,更に a と b を取り替えて 1.に戻る.

授業終了時までのプログラムと完成した提出用プログラムをoh-meijiシステムを使って提出すること.
授業終了時に送るのは出席の確認用であり,完成した課題は提出用の回に送ること.
(提出期限を厳守し,提出用の回に提出しないと採点を行わない)


また提出の行い方については,以下のページを参照してください.
課題の提出方法