ぽてとのC言語練習中


■Word.c ソース ver0.10 -- 2002/01/18 02:00
 



/*********************************************************
  二分木を使った単語出現回数カウントプログラム
   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;
}
トップページへ