Powered by SmartDoc

ソフトウェア概論A/B (2010/10/15)
Ver. 1.0

2010年10月15日
栗野 俊一
kurino@math.cst.nihon-u.ac.jp
http://edu-gw2.math.cst.nihon-u.ac.jp/~kurino/2010/soft/soft.html
ソフトウェア概論 A/B2010年10月15日 の資料

目次

講義資料

当日の OHP 資料

当日のOHP資料です。

本日の概要

関数の再帰的定義( Text p.194 - 197 )

-->

講義で利用するサンプルプログラム

sample-001

Download : sample-001.c ( SJIS 版 )

sample-001.c
/*
 * 再帰的関数の例 factrial
 */

#include <stdio.h>

/*
 * 階乗 (factrial) の再帰的定義
 *
 *                   n * f(n-1)      ( n > 0 )
 *         f(n) = {
 *                   1               ( other )
 */

int factrial ( int n ) {

  if ( n > 0 ) {
	return n * factrial ( n - 1 );	// factrial 関数の定義の中で factrial を利用
  } else {
	return 1;
  }

}

/*
 * main
 */

int main ( void ) {
  int nat;		// 自然数

  printf ( "小さな自然数を入力してください : " );
  scanf ( "%d", &nat );

  printf ( "%d の階乗は %d です。\n", nat, factrial ( nat ) );

  return 0;
}
入力例
5

sample-001.c の実行結果
C:\usr\c\> sample-001
小さな自然数を入力してください : 5
5 の階乗は 120 です。
C:\usr\c\> 

sample-002

Download : sample-002.c ( SJIS 版 )

sample-002.c
/*
 * 再帰を利用しない関数定義の例
 */

#include <stdio.h>

/*
 * 
 */

void funcAAA() {
  printf ( "\t\t\tAAA\n" );
}

/*
 * 
 */

void funcAAB() {
  printf ( "\t\t\tAAB\n" );
}

/*
 * 
 */

void funcAA() {
  printf ( "\t\tAA\n" );
  funcAAA();
  funcAAB();
}

/*
 * 
 */

void funcABA() {
  printf ( "\t\t\tABA\n" );
}

/*
 * 
 */

void funcABB() {
  printf ( "\t\t\tABB\n" );
}

/*
 * 
 */

void funcAB() {
  printf ( "\t\tAB\n" );
  funcABA();
  funcABB();
}

/*
 * 
 */

void funcA() {
  printf ( "\tA\n" );
  funcAA();
  funcAB();
}

/*
 * 
 */

void funcBAA() {
  printf ( "\t\t\tBAA\n" );
}

/*
 * 
 */

void funcBAB() {
  printf ( "\t\t\tBAB\n" );
}

/*
 * 
 */

void funcBA() {
  printf ( "\t\tBA\n" );
  funcBAA();
  funcBAB();
}

/*
 * 
 */

void funcBBA() {
  printf ( "\t\t\tBBA\n" );
}

/*
 * 
 */

void funcBBB() {
  printf ( "\t\t\tBBB\n" );
}

/*
 * 
 */

void funcBB() {
  printf ( "\t\tBB\n" );
  funcBBA();
  funcBBB();
}

/*
 * 
 */

void funcB() {
  printf ( "\tB\n" );
  funcBA();
  funcBB();
}

/*
 * main
 */

int main ( void ) {

  printf ( "main\n" );
  funcA();
  funcB();

  return 0;
}
sample-002.c の実行結果
C:\usr\c\> sample-002
main
	A
		AA
			AAA
			AAB
		AB
			ABA
			ABB
	B
		BA
			BAA
			BAB
		BB
			BBA
			BBB
C:\usr\c\> 

sample-003

Download : sample-003.c ( SJIS 版 )

sample-003.c
/*
 * 全ての自然数は偶数か奇数
 */

#include <stdio.h>

/*
 *			EVEN	( n = 0 )
 * parity ( n ) {	ODD	( parity ( n - 1 ) = EVEN )
 *			EVEN	( parity ( n - 1 ) = ODD )
 */

#define	EVEN	0
#define	ODD	1

int parity ( int n ) {

  if ( n == 0 ) {
	return EVEN;
  } else if ( parity ( n - 1 ) == EVEN ) {
	return ODD;
  } else {
	return EVEN;
  }
}

/*
 * main
 */

int main ( void ) {
  int nat;		// 自然数

  printf ( "小さな自然数を入力してください : " );
  scanf ( "%d", &nat );

  if ( parity ( nat ) == EVEN ) {
	printf ( "%d は偶数です\n", nat );
  } else {
	printf ( "%d は奇数です\n", nat );
  }

  return 0;
}
入力例
5

sample-003.c の実行結果
C:\usr\c\> sample-003
小さな自然数を入力してください : 5
5 は奇数です
C:\usr\c\> 

sample-004

Download : sample-004.c ( SJIS 版 )

sample-004.c
/*
 * 配列の要素の総和を計算する再帰的な関数
 */

#include <stdio.h>

/*
 *					sum ( array, size-1 ) + array[size-1]	( size > 0 )
 *	sum ( array, size ) = {
 *					0					( othewise )
 */

int sum ( int array[], int size ) {

  if ( size > 0 ) {
	return sum ( array, size - 1 ) + array [ size - 1 ];
  } else {
	return 0;
  }
}

/*
 * main
 */

#define	ARRAY_SIZE	5

int main ( void ) {

  int numbers[ARRAY_SIZE];	// ARRAY_SIZE 個の整数値を保存する配列
  int index;			// 何番目の整数か

  printf ( "%d 個の整数値を入力し、その逆順に出力します。\n", ARRAY_SIZE );

  for ( index = 0; index < ARRAY_SIZE; index++ ) {
	printf ( "%2d 番目の数値を入力してください : ", index + 1 );
	scanf ( "%d", &numbers[index] );			// index 番目の数値の入力
  }

  printf ( "これらの数の総和は %d です。\n", sum ( numbers, ARRAY_SIZE ) );

  return 0;
}
入力例
47304
3
2957
602
73
sample-004.c の実行結果
C:\usr\c\> sample-004
5 個の整数値を入力し、その逆順に出力します。
 1 番目の数値を入力してください : 47304
 2 番目の数値を入力してください : 3
 3 番目の数値を入力してください : 2957
 4 番目の数値を入力してください : 602
 5 番目の数値を入力してください : 73
これらの数の総和は 50939 です。
C:\usr\c\> 

sample-005

Download : sample-005.c ( SJIS 版 )

sample-005.c
/*
 * 再帰による自然数の判定
 */

#include <stdio.h>

/*
 *			n が 0 なら自然数
 *	isNat ( n ) {
 *			n - 1 が自然数なら n も自然数
 */

#define	NO	0
#define	YES	(!NO)

int isNat ( int n ) {

  if ( n == 0 ) {
	return YES;
  } else {
	return isNat ( n - 1 );
  }

  /*
   * n に負の数を入力すると、無限ループになる事に注意しよう
   */

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "自然数を入力してください : " );
  scanf ( "%d", &nat );

  if ( isNat ( nat ) == YES ) {
	printf ( "%d は自然数です\n", nat );
  } else {
	printf ( "%d は自然数ではありません\n", nat );
	/* 実際には、ここに来る事はない */
  }

  return 0;
}
入力例
6
sample-005.c の実行結果
C:\usr\c\> sample-005
自然数を入力してください : 6
6 は自然数です
C:\usr\c\> 

sample-006

Download : sample-006.c ( SJIS 版 )

sample-006.c
/*
 * 再帰を利用した自然数上の計算
 */

#include <stdio.h>

/*
 * succ n = n' = n + 1
 */

int succ ( int n ) {

  return n + 1;
}

/*
 *			n				( m = 0 )
 * add ( n, m ) = {
 *			succ ( add ( n, m - 1 ) )	( otherwise )
 */

int add ( int n, int m ) {

  if ( m == 0 ) {
	return n;
  } else {
	return succ ( add ( n, m - 1 ) );
  }
}

/*
 *			0				( m = 0 )
 * mul ( n, m ) = {
 *			add ( mul ( n, m - 1 ), n )	( otherwise )
 */

int mul ( int n, int m ) {

  if ( m == 0 ) {
	return 0;
  } else {
	return add ( mul ( n, m - 1 ), n );
  }
}

/*
 *			1				( m = 0 )
 * power ( n, m ) = {
 *			mul ( power ( n, m - 1 ), n )	( otherwise )
 */

int power ( int n, int m ) {

  if ( m == 0 ) {
	return 1;
  } else {
	return mul ( power ( n, m - 1 ), n );
  }
}

/*
 * main
 */

int main ( void ) {
  int base;
  int exponent;

  printf ( "底を入力してください : " );
  scanf ( "%d", &base );

  printf ( "指数を入力してください : " );
  scanf ( "%d", &exponent );

  printf ( "%d の %d は %d です。\n", base, exponent, power ( base, exponent ) );

  return 0;
}
入力例
6
3
sample-006.c の実行結果
C:\usr\c\> sample-006
底を入力してください : 6
指数を入力してください : 3
6 の 3 は 216 です。
C:\usr\c\> 

sample-007

Download : sample-007.c ( SJIS 版 )

sample-007.c
/*
 * 配列の要素を再帰的に処理する関数
 */

#include <stdio.h>

/*
 *					scanf ( array[size-1] ); input ( array, size-1 ) 	( size > 0 )
 *	input ( array, size ) = {
 *					--							( othewise )
 */

void input ( int array[], int size ) {

  if ( size > 0 ) {
	printf ( "数を入力してください : " );
	scanf ( "%d", &array[ size - 1 ] );
	input ( array, size - 1 );
  }
}

/*
 *					sum ( array, size-1 ) + array[size-1]	( size > 0 )
 *	sum ( array, size ) = {
 *					0					( othewise )
 */

int sum ( int array[], int size ) {

  if ( size > 0 ) {
	return sum ( array, size - 1 ) + array [ size - 1 ];
  } else {
	return 0;
  }
}

/*
 *					print ( array, size-1 ) ; print ( array[size-1] )	( size > 0 )
 *	print ( array, size ) = {
 *					--							( othewise )
 */

void print ( int array[], int size ) {

  if ( size > 0 ) {
	printf ( "%d\n", array [ size - 1 ] );
	print ( array, size - 1 );
  }
}

/*
 * main
 */

#define	ARRAY_SIZE	5

int main ( void ) {

  int numbers[ARRAY_SIZE];	// ARRAY_SIZE 個の整数値を保存する配列

  input ( numbers, ARRAY_SIZE );
  print ( numbers, ARRAY_SIZE );
  printf ( "総和は %d です\n", sum ( numbers, ARRAY_SIZE ) );

  return 0;
}
入力例
47304
3
2957
602
73
sample-007.c の実行結果
C:\usr\c\> sample-007
数を入力してください : 47304
数を入力してください : 3
数を入力してください : 2957
数を入力してください : 602
数を入力してください : 73
47304
3
2957
602
73
総和は 50939 です
C:\usr\c\> 

sample-008

Download : sample-008.c ( SJIS 版 )

sample-008.c
/*
 * 最大公約数を計算する
 */

#include <stdio.h>

/*
 *				n			( m = 0 )
 *	gcm ( n, m ) = {
 *				gcm ( m, n % m )	( otherwise )
 */

int gcm ( int n, int m ) {

  if ( m == 0 ) {
	return n;
  } else {
	return gcm ( m, n % m );
  }

}

/*
 * main
 */

int main ( void ) {
  int n;
  int m;

  printf ( "一つ目の数を入力してください : " );
  scanf ( "%d", &n );

  printf ( "二つ目の数を入力してください : " );
  scanf ( "%d", &m );

  printf ( "%d と %d の最大公約数は %d です。\n", n, m, gcm ( n, m ) );

  return 0;
}
入力例
12
18
sample-008.c の実行結果
C:\usr\c\> sample-008
一つ目の数を入力してください : 12
二つ目の数を入力してください : 18
12 と 18 の最大公約数は 6 です。
C:\usr\c\> 

sample-009

Download : sample-009.c ( SJIS 版 )

sample-009.c
/*
 * 再帰呼び出しと処理の順番 ( 前に処理 )
 */

#include <stdio.h>

/*
 *	recf 0 〜 n まで処理する
 */

void recf ( int n ) {

  printf ( "recf ( %d )\n", n );	/* 再帰の前に処理をする */ 

  if ( n > 0 ) {
	recf ( n - 1 );
  }

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "一つの数を入力してください : " );
  scanf ( "%d", &nat );

  recf ( nat );

  return 0;
}
入力例
6
sample-009.c の実行結果
C:\usr\c\> sample-009
一つの数を入力してください : 6
recf ( 6 )
recf ( 5 )
recf ( 4 )
recf ( 3 )
recf ( 2 )
recf ( 1 )
recf ( 0 )
C:\usr\c\> 

sample-010

Download : sample-010.c ( SJIS 版 )

sample-010.c
/*
 * 再帰呼び出しと処理の順番 ( 後で処理 )
 */

#include <stdio.h>

/*
 *	recb 0 〜 n まで処理する
 */

void recb ( int n ) {

  if ( n > 0 ) {
	recb ( n - 1 );
  }

  printf ( "recb ( %d )\n", n );	/* 再帰の後で処理をする */ 

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "一つの数を入力してください : " );
  scanf ( "%d", &nat );

  recb ( nat );

  return 0;
}
入力例
6
sample-010.c の実行結果
C:\usr\c\> sample-010
一つの数を入力してください : 6
recb ( 0 )
recb ( 1 )
recb ( 2 )
recb ( 3 )
recb ( 4 )
recb ( 5 )
recb ( 6 )
C:\usr\c\> 

sample-011

Download : sample-011.c ( SJIS 版 )

sample-011.c
/*
 * 再帰呼び出しと処理の順番 ( 前後で処理 )
 */

#include <stdio.h>

/*
 *	recfb 0 〜 n まで処理する
 */

void recfb ( int n ) {

  printf ( "< recfb ( %d )\n", n );	/* 再帰の前に処理をする */ 

  if ( n > 0 ) {
	recfb ( n - 1 );
  }

  printf ( "> recfb ( %d )\n", n );	/* 再帰の後で処理をする */ 

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "一つの数を入力してください : " );
  scanf ( "%d", &nat );

  recfb ( nat );

  return 0;
}
入力例
6
sample-011.c の実行結果
C:\usr\c\> sample-011
一つの数を入力してください : 6
< recfb ( 6 )
< recfb ( 5 )
< recfb ( 4 )
< recfb ( 3 )
< recfb ( 2 )
< recfb ( 1 )
< recfb ( 0 )
> recfb ( 0 )
> recfb ( 1 )
> recfb ( 2 )
> recfb ( 3 )
> recfb ( 4 )
> recfb ( 5 )
> recfb ( 6 )
C:\usr\c\> 

sample-012

Download : sample-012.c ( SJIS 版 )

sample-012.c
/*
 * 再帰呼び出しと処理の順番 ( 前から加える )
 */

#include <stdio.h>

/*
 *	1 〜 1/n まで、前から加える
 */

float sumif ( int n ) {

  if ( n > 0 ) {
	return sumif ( n - 1 ) + ( 1/(float)n );
  } else {
	return 0.0;
  }

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "一つの数を入力してください : " );
  scanf ( "%d", &nat );

  printf ( "1 〜 1/%d までの総和は %f です\n", nat, sumif ( nat ) );

  return 0;
}
入力例
100000
sample-012.c の実行結果
C:\usr\c\> sample-012
一つの数を入力してください : 100000
1 〜 1/100000 までの総和は 12.090146 です
C:\usr\c\> 

sample-013

Download : sample-013.c ( SJIS 版 )

sample-013.c
/*
 * 再帰呼び出しと処理の順番 ( 後から加える )
 */

#include <stdio.h>

/*
 *	1 〜 1/n まで、後から加える
 */

float sumib0 ( int n, float sum ) {

  if ( n > 0 ) {
	return sumib0 ( n - 1, sum + ( 1/(float)n ) );
  } else {
	return sum;
  }

}

float sumib ( int n ) {

  return sumib0 ( n, 0.0 );

}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "一つの数を入力してください : " );
  scanf ( "%d", &nat );

  printf ( "1 〜 1/%d までの総和は %f です\n", nat, sumib ( nat ) );

  return 0;
}
入力例
100000
sample-013.c の実行結果
C:\usr\c\> sample-013
一つの数を入力してください : 100000
1 〜 1/100000 までの総和は 12.090152 です
C:\usr\c\> 

sample-014

Download : sample-014.c ( SJIS 版 )

sample-014.c
/*
 * ハノイの塔の問題を解く手順
 */

#include <stdio.h>

/*
 *	ハノイの塔
 */

void hanoi ( int n, char from, char to, char work ) {

  if ( n > 1 ) {
	hanoi ( n - 1, from, work, to );
	printf ( "%d の番号の円板を %c から %c に移動する\n", n, from, to );
	hanoi ( n - 1, work, to, from );
  } else {
	printf ( "%d の番号の円板を %c から %c に移動する\n", n, from, to );
  }
}

/*
 * main
 */

int main ( void ) {
  int hight;

  printf ( "円板の枚数を入力してください : " );
  scanf ( "%d", &hight );

  printf ( "%d 枚の円板を A から C に移動する手順は以下のようになります。\n", hight );
  hanoi ( hight, 'A', 'C', 'B' );

  return 0;
}
入力例
3
sample-014.c の実行結果
C:\usr\c\> sample-014
円板の枚数を入力してください : 3
3 枚の円板を A から C に移動する手順は以下のようになります。
1 の番号の円板を A から C に移動する
2 の番号の円板を A から B に移動する
1 の番号の円板を C から B に移動する
3 の番号の円板を A から C に移動する
1 の番号の円板を B から A に移動する
2 の番号の円板を B から C に移動する
1 の番号の円板を A から C に移動する
C:\usr\c\> 

sample-015

Download : sample-015.c ( SJIS 版 )

sample-015.c
/*
 * フィボナッチ数の計算
 */

#include <stdio.h>

/*
 *	フィボナッチ数
 */

int fibnacci ( int n ) {

  if ( n > 1 ) {
	return fibnacci ( n - 1 ) + fibnacci ( n - 2 );
  } else {
	return 1;
  }
}

/*
 * main
 */

int main ( void ) {
  int nat;

  printf ( "フィボナッチ数の何項目が欲しいですか ? : " );
  scanf ( "%d", &nat );

  printf ( "フィボナッチ数の第 %d 項は %d です。\n", nat, fibnacci ( nat ) );

  return 0;
}
入力例
6
sample-015.c の実行結果
C:\usr\c\> sample-015
フィボナッチ数の何項目が欲しいですか ? : 6
フィボナッチ数の第 6 項は 13 です。
C:\usr\c\>