1997年後期中間情報構造論テスト問題

教科書・ノート持ち込み不可。
解答に使用するプログラム言語は、問題の趣旨に沿っていれば何を用いても良い。 解答を裏に書く場合、どの設問に対する答か解るようにすること。 すべての大きな6つの設問の中から、5題以上について回答せよ。 採点は、各設問毎に行ない点数の高いものから5題について評価する。
5題よりより多く回答されている場合は、点数の 1/2 で加算する。

1.さまざまなデータ構造について

名前と電話番号のデータベースを作り、 データ構造を書記化し(関数名init())、 名前と電話番号を登録し(関数名add())、 名前から電話番号を検索する(関数名find())プログラムを、 さまざまなデータ構造で作るものとする。

呼び出し側のプログラムは、あらかじめファイル(data.txt)から入力し、 標準入力から、探すべき名前を入力し、その結果を表示する。
(次のプログラムを参考)

	void main()
	{
	    char  name[ 128 ] , phone[ 32 ] , *ans ;
	    FILE* fp ;

	    init() ;  /* データベースの初期化 */

	    if ( (fp = fopen( "data.txt" , "rt" )) != NULL ) {
	        while( fscanf( fp , "%s %s" , name , phone ) == 2 )
	            add( name , phone ) ; /* データベースへの登録 */
	        fclose( fp ) ;
	    }

	    scanf( "%s" , name ) ;
	    ans = find( name ) ; /* データベースから検索 */
	    if ( ans == NULL )
	        printf( "みつからない\n" ) ;
	    else
	        printf( "%s = %s\n" , name , ans ) ;
	}

2.間違ったプログラム例

	int  size ;                /* データ件数 */
	char *name_table[ 100 ] ;  /* 名前の配列 */
	char *phone_table[ 100 ] ; /* 電話番号の配列 */

	void init() { size = 0 ; }
	void add( char* n , char* p )
	{
	    name_table[ size ] = n ;
	    phone_table[ size ] = p ;
	    size++ ;
	}
	char* find( char* n )
	{   int i ;
	    for( i = 0 ; i < size ; i++ )
	        if ( strcmp( name_table[ i ] , n ) == 0 )
	            return name_phone[ i ] ;
	    return NULL ;
	}
このプログラムは、登録が正しく行われない。
  1. 正しく動作しない理由を分かりやすく説明し、
  2. どの様に修正すべきか説明せよ。

3.ハッシュ法によるプログラム

前の設問 2 のプログラムの データ構造にハッシュ法を採用する。 以下の問に答えよ。

	#define HashSize  128
	struct NamePhoneList {
	    char   name[ 64 ] ;
	    char   phone[ 32 ] ;
	    struct NamePhoneList* next ;
	} ;
	struct NamePhoneList* table[ HashSize ];
	void init()
	{   int  i ;
	    for( i = 0 ; i < HashSize ; i++ )
	        table[ i ] = NULL ;
	}
	int hash_func( char* n )
	{   int sum ;
	    for( sum = 0 ; *n != '\0' ; n++ )
	        sum += *n ;
	    return sum % HashSize ;
	}

	struct NamePhoneList* np_cons( char* n , char* p ,
	                               struct NamePhoneList* nxt )
	{   struct NamePhoneList* np ;
	    np = (struct NamePhoneList*)
	             malloc( sizeof( struct NamePhoneList ) ) ;
	    strcpy( np->name ,  n ) ;
	    strcpy( np->phone , p ) ;
	    np->next = nxt ;
	    return np ;
	}
	void add( char* n , char* p )
	{   int  index = hash_func( n ) ;

		/* リストの先頭に追加 */
	    table[ index ] = np_cons( n , p , table[ index ] ) ;
	}
	char* find( char* n )
	{
	    /* この部分を作成せよ。*/
	}
  1. 関数hash_func()は、どのような特徴を持つことが 理想的か説明せよ。
  2. このプログラムの find() の部分を作成せよ。

4.処理速度の見積もり

前の設問 3 でのハッシュ法のプログラムと、 2分探索法のプログラムの検索速度の比較を行った結果、 全データ件数 N が1024件の時、以下の通りであった。

検索方式 平均処理速度
ハッシュ法 8[msec]
2分探索法 10[msec]

このとき、データが 16384 件( = 214 件)の場合、 ハッシュ法と2分探索法で、同程度の処理速度になるためには、 ハッシュ法のプログラムをどの様に改良すべきか、 具体的な数値を用いて説明せよ。

5.基礎問題

	#include 
	#include 
	#include 
	int eval( char* str )
	{
	    int  sp , digit ;
	    int  st[ 100 ] ;
	    int  flag = 0 ;
	    for( sp = 0 ; *str != '\0' ; str++ ) {
	        if ( isdigit( *str ) ) {
	            if ( !flag ) /* 直前が数字以外 */
	                digit = 0 ;
	            digit = digit * 10 + (*str - '0') ;
	            flag = 1 ;
	        } else {
	            if ( flag ) /* 直前が数字なら */
	                st[ sp++ ] = digit ;
	            switch( *str ) {
	            case '+' : st[sp-2] = st[sp-2] + st[sp-1] ; sp-- ; break ;
	            case '-' : st[sp-2] = st[sp-2] - st[sp-1] ; sp-- ; break ;
	            case '*' : st[sp-2] = st[sp-2] * st[sp-1] ; sp-- ; break ;
	            case '/' : st[sp-2] = st[sp-2] / st[sp-1] ; sp-- ; break ;
	            case 'N' : st[sp-1] = -st[sp-1] ; break ;
	            }
	            flag = 0 ;
	        }
	    }
	    return st[ --sp ] ;
	}
	void main()
	{
       printf( "%d\n" , eval( "1 2+3+" ) ) ;
       printf( "%d\n" , eval( "12 2*10-" ) ) ;
	}

このプログラムの実行結果を示せ。

6.unix環境と入出力リダイレクトとパイプ

以下の合計点数を求めるプログラム sum.c をコンパイルし、 その実行プログラムの名前を sum とした。

	/* sum.c : gcc -o sum sum.c */
	#include 
	#define SIZE 5
	void main()
	{
	   char	name[ 100 ] ;
	   int   point , sum , i ;
	   while( scanf( "%s" , name ) == 1 ) {
	      for( i = 0 , sum = 0 ; i < SIZE ; i++ ) {
	         scanf( "%d" , &point ) ;
	         sum += point ;
	      }
	      printf( "%s %d\n" , name , sum ) ;
	   }
	}

また、データファイルとして data1.txt,data2.txt がある。

ファイル名=data1.txt ファイル名=data2.txt
t-saitoh  10  20  30  40  50
inteli   100 100 100 100 100
aoyama    22  45  84 123  62
okada     49  33  75  64  89
sakamoto 104  66  43  98 100
  1. unix 環境で以下のコマンドを実行した場合の結果を示せ。
    $ sum < data1.txt
  2. データファイル data2.txt には、100 点以上の採点結果が 含まれており、100点を越える教科については 100 点に切り下げ して合計点を求めたい。このために、100点以上の切り下げ処理 のプログラム(実行ファイル名=a.out)を作り、 以下のようなコマンドにより、切り下げ後の合計点数を求めたい。
    $ a.out < data2.txt | sum
    この切り下げ処理のプログラムを示せ。

7.説明問題

以下の2つの説明問題の中から、1つについて説明を加えよ。

  1. ハッシュ衝突とは何か? および、その現象が発生した時の2つの対処方法について 具体的に説明せよ。
  2. unix におけるファイルのセキュリティに関する 利用制限として、どのようなことが可能か 具体的に説明せよ。