/*********************************************************
二分木を使った単語出現回数カウントプログラム
Word.c ver0.10 完成版 (2002/01/19 02:00)
**********************************************************/
/*********************************************************
ver0.10になり大幅に変更しました。
プログラムの関数化が主な変更点となっています。
→考えられる問題点
○ファイル名が固有。(これは次のバージョンで直します)
○単語判定がしっくりこない。
○関数化がまとまっていない。
(作業別ではなく、もっと機能別で分けたいのですが…)
**********************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXCHAR 64
#define MAXWORD 256
#define FILENAME_IN "file1.txt"
#define FILENAME_OUT "file2.txt"
typedef struct tnode{
char word[MAXCHAR];
int count;
struct tnode *left;
struct tnode *right;
}NODE;
/******************************************************************
FileOpen--[ファイルオープン関数]
ファイルが開ければファイルポインタを返し、エラーが出れば
そこでプログラムを終了する。
引数----ファイルポインタ、ファイル名、ファイルタイプ(r/w)
返り値--ファイルポインタ
*******************************************************************/
FILE *FileOpen(FILE *fp, const char *filename, const char *filetype){
fp=fopen(filename, filetype);
if (fp==NULL){
fprintf(stderr, "file error.\n");
exit(0);
}
return fp;
}
/******************************************************************
MyToLower--[小文字変換関数]
引数の文字を小文字に変換して返す。
引数----文字
返り値--文字
*******************************************************************/
char MyToLower(char c){
if (c>='A' && c<='Z')
c=c-('A'-'a');
return c;
}
/******************************************************************
talloc--[メモリ確保関数]
新たにNODE型の構造体分のメモリを確保して、
そこへのポインタを返す関数。
引数----なし
返り値--確保したメモリへのポインタ
*******************************************************************/
NODE* talloc(void){
return (NODE *)malloc(sizeof(NODE));
}
/******************************************************************
MakeNode--[新ノード作成関数]
文字列を受け取り、単語を新ノードに代入して初期化する。
そして新ノードへのポインタを返す。
引数----文字列(単語)
返り値--新ノードへのポインタ
*******************************************************************/
NODE* MakeNode(const char *str){
NODE *node;
node=talloc();
strcpy(node->word, str);
node->count=1;
node->left=node->right=NULL;
return node;
}
/******************************************************************
CheckNode--[二分木調査関数]
ノードを調べ、単語を追加するか判断する。
||単語を新たに追加する場合 -> MakeNode関数へ ||
||単語がすでに存在した場合 -> 単語出現回数に1を加える ||
引数----ファイルポインタ、ファイル名、ファイルタイプ(r/w)
返り値--ファイルポインタ
*******************************************************************/
NODE* CheckNode(NODE* p, const char *str){
if (p==NULL){ /*今いるところが空欄なら新ノードを作成*/
p=MakeNode(str);
}
else if (!strcmp(str, p->word))
p->count++;
else if (strcmp(str, p->word)<0)
p->left=CheckNode(p->left, str);
else
p->right=CheckNode(p->right, str);
return p;
}
/******************************************************************
InputNode--[単語抽出、二分木構成関数]
ファイルから読み込んだ単語をCheckNode関数に渡し、
二分探索木を作成する。
引数----二分探索木の基(NODE型構造体へのポインタ)
返り値--NODE型構造体へのポインタ
*******************************************************************/
NODE *InputNode(NODE *node){
char c, temp[MAXCHAR];
unsigned int i=0;
FILE *fp;
fp=FileOpen(fp, FILENAME_IN, "r+");
while (!feof(fp)){
c=fgetc(fp);
if (isalpha(c) || c=='\'' || isdigit(c)) { /*英文字が来た時*/
c=MyToLower(c);
temp[i]=c;
i++;
}
else if (!isalpha(c) && i>0){ /*単語を1つ読み終えたとき*/
temp[i]='\0';
node=CheckNode(node, temp); /*単語をノードとして二分木を形成*/
i=0;
}
else{/*英字以外の文字が続いた時*/
;
}
}
fclose(fp);
return node;
}
/******************************************************************
TraverseNode--[二分探索木出力関数]
引数として受け取ったポインタが指すノードからの
すべての葉の内容をファイルに出力する。
引数----ノードへのポインタ、ファイルポインタ
返り値--なし
*******************************************************************/
void TraverseNode(const NODE *p, FILE *fp){
if (p!=NULL){
TraverseNode(p->left, fp);
fprintf(fp, "%20s %4d\n", p->word, p->count);
TraverseNode(p->right, fp);
}
}
/******************************************************************
PrintNode--[二分探索木出力準備関数]
ファイルを開き、二分探索木の基(root)を
二分探索出力関数TraverseNodeに渡す。
引数----ノードへのポインタ(root)
返り値--なし
*******************************************************************/
void PrintNode(NODE *node){
FILE *fp;
fp=FileOpen(fp, FILENAME_OUT, "w+");
TraverseNode(node, fp);
fclose(fp);
}
/******************************************************************
main--[メイン関数]
二分探索木の基を宣言し、InputNodeで二分探索木を作成して
PrintNodeでファイル出力する。
引数----なし
返り値--0(正常終了)
*******************************************************************/
int main(void){
NODE *root=NULL;/*基となるノードを宣言*/
root=InputNode(root);/*二分探索木作成*/
PrintNode(root);/*二分探索木の内容をファイルに出力*/
return 0;
}
|