首先是letter-level的马尔科夫链
然后是word-level的马尔科夫链
word-level
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 //输入的字符串 6 char inputchars[4300000]; 7 #define MAXWORDS 80000 8 //字符串中没一个单词 9 char *word[MAXWORDS]; 10 //单词个数 11 int nword=0; 12 //k-order 13 int k=2; 14 15 //hash table,bin[i]存储hash到该位置的第一个word索引j,next[j]存储下一个word索引 16 int next[MAXWORDS]; 17 #define NHASH 49979 18 int bin[NHASH]; 19 #define MULT 31 20 21 22 //以k个单词为单位,进行hash 23 unsigned int hash(char* str) 24 { 25 int n; 26 unsigned int h=0; 27 unsigned char* p=str; 28 for(n=k;n>0;++p) 29 { 30 h=MULT*h+*p; 31 if(*p=='\0') 32 --n; 33 } 34 return h%NHASH; 35 } 36 37 38 //比较前k个单词的大小 39 int wordncmp(char* p,char *q) 40 { 41 int n; 42 for(n=k;*p==*q;++p,++q) 43 { 44 if(*p=='\0'&&(--n)==0) 45 return 0; 46 } 47 return *p-*q; 48 } 49 50 //从当前单词出发,跳过前n个单词 51 char* skip(char* p,int n) 52 { 53 for(;n>0;++p) 54 { 55 if(*p=='\0') 56 --n; 57 } 58 return p; 59 } 60 61 int main() 62 { 63 int i,j,wordsleft,psofar; 64 char *phrase,*p; 65 word[0]=inputchars; 66 //输入字符串,并将每个单词保存到word中,每个单词以'\0'结尾 67 while((scanf("%s",word[nword]))!=EOF) 68 { 69 word[nword+1]=word[nword]+strlen(word[nword])+1; 70 ++nword; 71 } 72 //将最后一个单词的后一个的k个字符设置为\0,保证wordncmp()正确 73 for(i=0;i<k;++i) 74 word[nword][i]='\0'; 75 76 //初始化hash table 77 for(i=0;i<NHASH;++i) 78 bin[i]=-1; 79 80 //构建hash table 81 for(i=0;i<=nword-k;++i) 82 { 83 j=hash(word[i]); 84 next[i]=bin[j]; 85 bin[j]=i; 86 } 87 88 //词组先初始化为字符串开始 89 phrase=inputchars; 90 //预备输出wordsleft个单词 91 for(wordsleft=10000;wordsleft>0;--wordsleft) 92 { 93 //初始化随机取模的值 94 psofar=0; 95 //对phrase hash后的的列表进行遍历,随机取得一个符合要求的单词 96 for(j=bin[hash(phrase)];j>=0;j=next[j]) 97 if(wordncmp(phrase,word[j])==0&&rand()%(++psofar)==0) 98 p=word[j]; 99 //将phrase重新设置 100 phrase=skip(p,1); 101 //输出符合要求单词的后面第k个单词 102 if(strlen(skip(phrase,k-1))==0) 103 break; 104 printf("%s\n",skip(phrase,k-1)); 105 } 106 return 0; 107 }
letter-level
1 //markov:letter-level 2 3 #include <stdio.h> 4 #include <string.h> 5 #include <stdlib.h> 6 7 char str[3000000];//保存将要学习的字符串 8 9 int main() 10 { 11 char *p,*q,*nextp; 12 char c; 13 int n=0,k=5/*k-order*/,maxletter,qsofar,i; 14 //输入字符串,末尾输入结束符 15 while((c=getchar())!=EOF) 16 str[n++]=c; 17 str[n]='\0'; 18 19 //初始化先指向字符串开始处 20 p=str; 21 22 //预备输出maxletter个字符 23 for(maxletter=2000;maxletter>0;--maxletter) 24 { 25 //随机数取模 26 qsofar=0; 27 //从字符串开始到最少还剩k个字符处遍历 28 for(q=str;q<=str+n-k+1;++q) 29 { 30 for(i=0;i<k&&*(p+i)==*(q+i);++i) 31 ; 32 //p和q的前k个字符相同,符合要求 33 if(i==k) 34 //可能有n个q的前k个字符都和p相同,随机取一个 35 if(rand()%(++qsofar)==0) 36 nextp=q; 37 } 38 //c可能会是我们要输出的那一个字符 39 c=*(nextp+k); 40 if(c=='\0') 41 break; 42 putchar(c); 43 //改变p的值 44 p=nextp+1; 45 } 46 47 return 0; 48 }