ついでにコードも載せとく。
mc.h
- ツリー状のデータで文字のつながりを表現。
- 次に来る可能性のある文字を「子供」と呼ぶ
- 末っ子へのポインタと、直上の兄/姉へのポインタがあれば家系図を表現できる
class MCDat { public: int val; //文字の番号 int hist; //発生頻度 int chist; //Σ子供の発生頻度 class MCDat *child; //末っ子へのポインタ class MCDat *next; //直上の兄/姉へのポインタ MCDat(int c0); class MCDat *find_child(int c0); //文字c0 の子供へのポインタ。ないならNULL class MCDat *add_child(int c0); //文字c0 の子供を末っ子に追加 class MCDat *random_child(); //記録された頻度を元に子供を選ぶ };
mc.cc
#include <stdlib.h> #include "mc.h" MCDat::MCDat(int c0) { val = c0; hist = 0; chist = 0; child = NULL; next = NULL; } MCDat *MCDat::find_child(int c0) { MCDat *p = child; while(p!=NULL) { if (p->val == c0) break; p = p->next; } return p; } MCDat *MCDat::add_child(int c0) { MCDat *p = find_child(c0); if (!p) { p=new MCDat(c0); p->next = child; child = p; } chist++; p->hist++; return p; } MCDat *MCDat::random_child() { MCDat *p; double r0 = rand()*1.0/RAND_MAX; int r = (int)(r0 * chist); for (p=child;p!=NULL;p=p->next) { r -= p->hist; if (r<=0) break; } return p; }
四文字前まで参考にするコード、サンプル読み込みフェーズ
MCDat *p1, *p2, *p3, *p4, *root; root = new MCDat(0); p1=p2=p3=p4 = NULL; while(1) { unsigned char *c = buf; fgets((char *)buf,10000, fp); if(feof(fp))break; while(1) { int c0 = getwchar(&c); if (c0 == -1) break; if(p4) p4->add_child(c0); //ツリー第五世代 if(p3) p4 = p3->add_child(c0); //ツリー第四世代 if(p2) p3 = p2->add_child(c0); //ツリー第三世代 if(p1) p2 = p1->add_child(c0); //ツリー第二世代 p1 = root->add_child(c0); //ツリー第一世代 if (c0 == kidxs("。") || c0 == kidxs(".") || c0 == kidxs("?") ) { //Terminate chain p1=p2=p3=p4=NULL; } }//buf }
表示フェーズ
for(i=0;i<100;i++) { double r=1.0*rand()/RAND_MAX; int ri = (int)(tophist_sum*r); int c0 = 0; while(c0<kmax) { ri -= tophist[c0]; if (ri<=0)break; c0++; } prtkidx(c0); p1 = root->find_child(c0); p2 = p3 = p4 = NULL; while(1) { MCDat *p; if (p4) p = p4->random_child(); else if (p3) p = p3->random_child(); else if (p2) p = p2->random_child(); else if (p1) p = p1->random_child(); else break; if (!p) break; c0 = p->val; prtkidx(c0); if (p3) p4 = p3->find_child(c0); if (p2) p3 = p2->find_child(c0); if (p1) p2 = p1->find_child(c0); p1 = root->find_child(c0); } putchar(10); }