[编程珠玑]马尔科夫链自动产生文本

首先是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 }

你可能感兴趣的:(编程珠玑)