サイトマップ / C言語講座>出入り口>総目次>目次:ファイル>二分木探索(バイナリサーチ)||デモ用
[空白文字の出現頻度]←このソース→[バッファリング有り無し]
/* まず最初にこのファイルを開いて下さい。そして、ファイル名を”Wtest.c”に変更しておいてください。今日は、Cのソースプログラムから、英単語を抜き出して、Cの予約語かどうか調べて、予約語だったらカウントするプログラムを作ります。
予約語とカウンタはセットになっている方が自然なので、構造体の配列を使います。構造体の配列は下に示すように型宣言をします。name[10] に予約語を入れ、countに数えた結果を入れます。
typedef struct { char name[10]; int count; } KEYWORD;
構造体の配列を下記のように宣言します。予約語は、後に述べる 二分木探索に使うので、整列してあります。
KEYWORD keyword[NUM_KW] = { {"break", 0} {"case", 0}, - - - - - - - - - - - - - - {"while", 0} };
では、プログラムの流れについて、考えて見ましょう。
ファイルから英単語を読み込む関数の名前を、GetWord( ) とします。この関数は引数として、ファイルポインタと、取り出した英単語をしまう文字列へのポインタを取ります。戻り値は成功したら読み込んだ文字数を、失敗したら0を返すようにします。
単語を取り出すには、ライブラリ関数、strtok( ) を使っても良いと思います。しかし、strtok( ) は1回目と2回目以降の呼び出しで、引数を変えなければならず、使いづらいので、今回は自作することにします。
英単語はアルファベットでできています。そこで、次のアルゴリズムで英単語を読み込みます。
ファイルの先頭から1文字ずつ読み、 もし、アルファベットでなければ、読み飛ばし、 アルファベットなら、英単語をしまう配列に、その文字を書き込みます。 それをアルファベットでない文字が出るまで続け、 アルファベットでない文字が来たら、 文字列の終末にヌル文字を追加して、読み込んだ文字数をリターンする。
アルファベットかどうかは、下記のライブラリ関数を使って調べます。
#include <ctype.h> int isalpha(char c); 例:n = isalpha(c); 実行結果 戻り値 条件を満たせば 0以外の値 条件を満たさなければ 0
ソースプログラムに詳しい説明を付けておきましたが、少し、補足します。int 型の変数 n に読み込んだ文字数を入れます。c = getc(fp) で、ファイルから c に1文字読み込みます。
if (!n && !isalpha(c)) が真になるのは、まだ1文字も読んでいなくて、かつ、c がアルファベットでない時です。この時は、読み飛ばします。if (n && !isalpha(c)) が真になるのは、文字を読み込んでいて、かつ、c がアルファベットでない時です。つまり、英単語を読み終わった時です。補足は、以上です。
次に、ファイルから読み込んだ単語が予約語かどうか調べて、予約語ならカウントする関数を作ります。この関数は、読み込んだ英単語をしまってある文字列へのポインタを取ります。戻り値は、予約語だった時は、見つけた位置 ( 後述 ) を返します。下記に関数の名前を示します。
int BSearch(char *word);
予約語であるかどうかは、構造体の配列の中に、英単語と同じものがあるかどうかを、調べればわかります。
予約語の探索には、バイナリサーチ ( 二分木探索 ) という方法を使います。バイナリサーチを行うには、データが昇順に整列してあることが必要です。英単語の場合は、辞書のような順に並んでいるということです。
このアルゴリズムについて説明します。左から右に辞書順に予約語が並んでいるとします。
英単語と、予約語の並びの中央のものと比較します。 もし、一致したら予約語の位置を返して、終了します。 もし、予約語の方が大きければ、次の探索対象は中央値の右側です。 もし、予約語の方が小さければ、次の探索対象は中央値の左側です。
このように、順次探索の範囲をせばめていって、分割不能になったら、-1 を返して終了します。
ソースプログラムに詳しい説明をつけて置きましたので、あとはそちらをごらん下さい。探索結果を表示する関数は、簡単なのでソースプログラムをごらん下さい。 */
#include <stdio.h> #include <stdlib.h> /* exit( ) で必要 */ #include <string.h> /* strcmp( ) で必要 */ #include <ctype.h> /* isalpha( ) で必要 */ #define NUM_KW 25 /* 25 の予約語を対象にする */ typedef struct { char name[10]; /* Cの予約語を入れる */ int count; /* カウンタ */ } KEYWORD; /* 構造体配列の宣言 */ KEYWORD keyword[NUM_KW] = { /* 二分木探索 ( バイナリサーチ ) に使うので */ {"break", 0}, /* 構造体の最初の要素は整列してある */ {"case", 0}, {"char", 0}, {"continue", 0}, {"do", 0}, {"double", 0}, {"else", 0}, {"enum", 0}, {"extern", 0}, {"float", 0}, {"for", 0}, {"if", 0}, {"int", 0}, {"long", 0}, {"register", 0}, {"return", 0}, {"short", 0}, {"static", 0}, {"struct", 0}, {"switch", 0}, {"typedef", 0}, {"union", 0}, {"unsigned", 0}, {"void", 0}, {"while", 0} }; int GetWord(FILE *fp, char *temp); int BSearch(char *word); void ShowResult(void); void main(void); /* 英単語を temp[n] に読み込む */ int GetWord(FILE *fp, char *temp) { int c; int n = 0; /* 読み込んだ文字数 */ while ((c = getc(fp)) != EOF) { /* 文字を 読み込んでいなくて */ if (!n && !isalpha(c)) /* かつ、c はアルファベットでない */ continue; /* 読み飛ばす */ else if (n && !isalpha(c)) { /* 英単語を読みおわったら */ temp[n] = '\0'; /* 末尾にヌル文字を付けて */ return (n); /* 読み込んだ文字数を返す */ } else if (isalpha(c)) { /* アルファベットの時 */ temp[n] = (char)c; /* 英単語の読み込み */ n++; } } return (0); /* キーワードの読み込みに失敗 */ } /* 二分木探索 ( バイナリサーチ ) を行って、 */ /* 予約語が見つかったら、カウンタに1加える */ int BSearch(char *word) { int left = 0; int right = NUM_KW - 1; int mid; int x; /* 左から右へ辞書的に予約語が並んでいるとすると */ while (left <= right) { mid = left + (right - left) / 2; x = strcmp(keyword[mid].name, word); if (x > 0) /* 予約語は mid より左にある */ right = mid -1; /* 左を探索 */ else if (x < 0) /* 予約語は mid より右にある */ left = mid + 1; /* 右を探索 */ else { /* 見つかったら */ keyword[mid].count += 1; /* カウンタに1加えて、 */ return (mid); /* リターンする */ } } return (-1); } /* 構造体の中身を表示 */ void ShowResult(void) { int i; for (i = 0; i < NUM_KW ; i++) { printf("%10s %3d ", keyword[i].name, keyword[i].count); if (!((i + 1) % 4)) /* 予約語を4つ表示したら改行 */ printf("\n"); } } void main(void) { FILE *fp; char word[100]; if ((fp = fopen("wtest.c", "r")) == NULL) { /* ファイルを開けなかったら */ fprintf(stderr, "Can't Open C Source File!\n");/* メッセージを表示して */ exit(2); /* シェルへ戻る */ } /* 英単語が見つかったら予約語かどうか調べる */ while (GetWord(fp, word)) { BSearch(word) ; } ShowResult( ) ; fclose(fp); } |
/* このプログラムで開いたファイル "Wtest.c" は、このプログラムから日本語のコメントを削ったファイルです。 */
[空白文字の出現頻度]←このソース→[バッファリング有り無し]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−