Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2115082
  • 博文数量: 249
  • 博客积分: 1305
  • 博客等级: 军士长
  • 技术积分: 4733
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-17 10:37
个人简介

不懂的东西还有很多,随着不断的学习,不懂的东西更多,无法消灭更多不懂的东西,那就不断的充实自己吧。 欢迎关注微信公众号:菜鸟的机器学习

文章分类

全部博文(249)

文章存档

2015年(1)

2014年(4)

2013年(208)

2012年(35)

2011年(1)

分类: C/C++

2013-06-15 10:49:29


一、单词
(1)为文档中包含的单词生成一个列表?
解答:
    方法一:用到标准模板库中的sets和strings
  1. #include <iostream>
  2. #include <set>
  3. #include <string>

  4. using namespace std;

  5. int main(int argc, char **argv)
  6. {
  7.     set<string> str;
  8.     set<string>::iterator iter;
  9.     string t;
  10.     while(cin >> t)
  11.     {
  12.         str.insert(t);
  13.     }
  14.     for(iter = str.begin(); iter != str.end(); iter++)
  15.     {
  16.         cout << *iter << endl;
  17.     }
  18.     return 0;
  19. }
    while循环读取输入并将每个单词插入集合str(忽略重复的单词),然后for循环迭代整个集合,并按排好的顺序输出单词。

(2)为单词进行计数
    方法一:用标准模板库中的map将整个计数与每个字符串联系起来
  1. #include <iostream>
  2. #include <map>
  3. #include <string>

  4. using namespace std;

  5. int main(int argc, char **argv)
  6. {
  7.     map<string, int> m;
  8.     map<string, int>::iterator iter;
  9.     string t;
  10.     while(cin >> t)
  11.     {
  12.         m[t]++;
  13.     }
  14.     for(iter = m.begin(); iter != m.end(); iter++)
  15.     {
  16.         cout << iter->first << " " << iter->second << endl;
  17.     }
  18.     return 0;
  19. }
    方法二:为了减少处理时间,可以自己建立散列表
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. typedef struct node *nodeptr;
  5. typedef struct node
  6. {
  7.     char *word;
  8.     int count;
  9.     nodeptr next;
  10. }node;

  11. #define NHASH    29989    //圣经中有29131个不同的单词,用跟29131最接近的质数作为散列表的大小
  12. #define MULT 31            //hash时用到的乘数
  13. nodeptr bin[NHASH];        //散列表

  14. unsigned int hash(char *p)
  15. {
  16.     unsigned int h = 0;
  17.     for( ; *p != ''; p++)
  18.     {
  19.         h = MULT * h + *p;
  20.     }
  21.     return h % NHASH;
  22. }

  23. #define NODEGROUP    1000
  24. int nodesleft = 0;
  25. nodeptr freenode;

  26. nodeptr nmalloc()
  27. {
  28.     if(nodesleft == 0)
  29.     {
  30.         freenode = (nodeptr)malloc(NODEGROUP *sizeof(node));
  31.         nodesleft = NODEGROUP;
  32.     }
  33.     nodesleft--;
  34.     return freenode++;
  35. }

  36. #define CHARGROUP    10000
  37. int charleft = 0;
  38. char *freechar;

  39. char *smalloc(int n)
  40. {
  41.     if(charleft < n)
  42.     {
  43.         freechar = (char *)malloc(n + CHARGROUP);
  44.         charleft = n + CHARGROUP;
  45.     }
  46.     charleft -= n;
  47.     freechar += n;
  48.     return freechar - n;
  49. }

  50. //增加原先存在的单词的计数值,若之前没有该单词,则对计数器初始化
  51. void incword(char *s)
  52. {
  53.     nodeptr p;
  54.     int h = hash(s);    //找到与单词对应的箱
  55.     for(p = bin[h]; p != NULL; p = p->next)
  56.     {
  57.         if(strcmp(s, p->word) == 0)
  58.         {
  59.             (p->count)++;
  60.             return;
  61.         }
  62.     }

  63.     p = nmalloc();
  64.     p->count = 1;
  65.     p->word = smalloc(strlen(s) + 1);
  66.     strcpy(p->word, s);
  67.     p->next = bin[h];    //头插法
  68.     bin[h] = p;
  69. }


  70. int main()
  71. {
  72.     int i;
  73.     nodeptr p;
  74.     char buf[100];
  75.     for(i = 0; i < NHASH; i++)
  76.     {
  77.         bin[i] = NULL;
  78.     }
  79.     while(scanf("%s", buf) != EOF)
  80.     {
  81.         incword(buf);
  82.     }
  83.     for(i = 0; i < NHASH; i++)
  84.     {
  85.         for(p = bin[i]; p != NULL; p = p->next)
  86.         {
  87.             printf("%s %dn", p->word, p->count);
  88.         }
  89.     }
  90.     return 0;
  91. }
    前面介绍了表示单词集合的两种方法。平衡搜索树将字符串看作是不可分割的对象进行操作,标准模板库的set和map中大部分实现都使用这种结构。平衡搜索树中的元素始终处于有序状态,从而很容易的指向寻找前驱结点或按顺序输出元素之类的操作。另一方面,散列则需要深入字符串的内部,计算散列函数并将关键字散列到一个较大的表中。散列方法的平均速度很快,但缺乏平衡树提供的最坏情况的保证,也不能支持其他涉及顺序的操作。

二、短语
    给定一个文本文件作为输入,插在其中最长的重复子字符串。例如,“Ask not what your country can do for you, but what you can do for your country”中最长的重复字符串是“can do for you”,第二长的是“your country”。
    
    方法一:双重for循环依次比较每个字符串,找到最长重复子字符串
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>

  4. //找到两个字符串公共部分的长度
  5. int comlen(char *p, char *q)
  6. {    
  7.     int i = 0;
  8.     while (*p && (*p++ == *q++))
  9.     {
  10.         i++;
  11.     }
  12.     return i;
  13. }

  14. int main()
  15. {
  16.     int i, j;
  17.     int maxi, maxj;
  18.     int currentlen, maxlen = -1;
  19.     char *str = "ask not what your country can do for you, but what you can do for your country";
  20.     int length = strlen(str);

  21.     for(i = 0; i < length; i++)
  22.     {
  23.         for(j = i + 1; j < length; j++)
  24.         {
  25.             currentlen = comlen(str + i, str + j);
  26.             if(currentlen > maxlen)
  27.             {
  28.                 maxlen = currentlen;
  29.                 maxi = i;
  30.                 maxj = j;
  31.             }
  32.         }
  33.     }

  34.     for(i = 0; i < maxlen; i++)
  35.     {
  36.         printf("%c", str[maxi + i]);
  37.     }
  38.     printf("n");
  39.     return 0;
  40. }

    方法二:采用后缀数组来处理该问题
    我们的程序最多处理MAXN个字符,这些字符存储在数组c中。
    #define MAXN  50000
    char c[MAXN], *a[MAXN];
    我们使用一个称为“后缀数组”的数据结构,这个结构是一个字符指针数组,记为a。读取输入时,我们对a进行初始化,使得每个元素指向输入字符串中的相应字符:
    while(ch  = getchar() != EOF)
    {
            a[n] = &c[n];
            c[n] = ch;
    }
    c[n] = 0;

    元素a[0]指向整个字符串,下一个元素指向从第二个字符开始的数组后缀,等等。对于输入字符串“banana”,该数组能够表示如下后缀:
                            char *a="banana"
                            a[0]=banana
                            a[1]=anana
                            a[2]=nana
                            a[3]=ana
                            a[4]=na
                            a[5]=a
    如果某个长字符串在数组c中出现了两次,那么它将出现在两个不同的后缀中,因此我们队数组进行排序以寻找相同的后缀。“banana”数组排序为:
                            a[0]=a
                            a[1]=ana
                            a[2]=anana
                            a[3]=banana
                            a[4]=na
                            a[5]=nana
    然后就可以扫描数组,通过比较相邻元素来找出最长的重复字符串。
    该方法由于排序的存在,时间复杂度为O(nlogn)。
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>

  4. int pstrcmp(char **p, char **q)
  5. { return strcmp(*p, *q); }//只能比较字符串,两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇''为止。

  6. int comlen(char *p, char *q)//返回两个参数共同部分的长度
  7. {    int i = 0;
  8.     while (*p && (*p++ == *q++))
  9.         i++;
  10.     return i;
  11. }

  12. #define M 1
  13. #define MAXN 5000000
  14. char c[MAXN], *a[MAXN];

  15. int main()
  16. { int i, ch, n = 0, maxi, maxlen = -1;
  17.     while ((ch = getchar()) != EOF) {
  18.         a[n] = &c[n];
  19.         c[n++] = ch;
  20.     }
  21.     c[n] = 0;
  22.     qsort(a, n, sizeof(char *), pstrcmp);//快速排序
  23.     for (i = 0; i < n-M; i++)
  24.         if (comlen(a[i], a[i+M]) > maxlen) {//比较相邻字符串相同个数
  25.             maxlen = comlen(a[i], a[i+M]);
  26.             maxi = i;
  27.         }
  28.     printf("%.*sn", maxlen, a[maxi]);
  29.     return 0;
  30. }

三、生成随机文本
    基于字母:下一个字母设置为前一个字母的随机函数,或者下一个字母设置为前k个字母的随机函数。
  1. /* Copyright (C) 2000 Lucent Technologies */
  2. /* Modified from markov.c in 'Programming Pearls' by Jon Bentley */

  3. /* markovlet.c -- generate letter-level random text from input text
  4.     Alg: Store text in an array on input
  5.          Scan complete text for each output character
  6.             (Randomly select one matching k-gram)
  7.  */

  8. #include <stdio.h>
  9. #include <stdlib.h>

  10. char x[5000000];

  11. int main()
  12. {    int c, i, eqsofar, max, n = 0, k = 5;
  13.     char *p, *nextp, *q;
  14.     while ((c = getchar()) != EOF)
  15.     {
  16.         x[n++] = c;
  17.     }
  18.     x[n] = 0;
  19.     p = x;
  20.     srand(1);
  21.     for (max = 2000; max > 0; max--)
  22.     {
  23.         eqsofar = 0;
  24.         for (q = x; q < x + n - k + 1; q++)
  25.         {
  26.             for (i = 0; i < k && *(p+i) == *(q+i); i++)
  27.                 ;
  28.             if (i == k)
  29.             {
  30.                 if (rand() % ++eqsofar == 0)
  31.                 {
  32.                     nextp = q;
  33.                 }
  34.             }
  35.         }
  36.         c = *(nextp+k);
  37.         if (c == 0)
  38.         {
  39.             break;
  40.         }
  41.         putchar(c);
  42.         p = nextp+1;
  43.     }
  44.     return 0;
  45. }

    基于单词:
    方法一:最笨的方法是随机输出字典中的单词;
    方法二:稍微好点的方法是读取一个文档,对每个单词进行计数,然后根据适当的概率选择下一个输出的单词;
    方法三:如果使用在生成下一个单词时考虑前面几个单词的马尔科夫链,可以得到更加令人感兴趣的文本;
    下面是香农的算法:以构建【字母级别的一阶文本】为例,随机打开一本书并在该页随机选择一个字母记录下来。然后翻到另一页开始读,直到遇到该字母,此时记录喜爱其后面的那个字母。再翻到另外一页搜索上述第二个字母并记录其后面的那个字母。依次类推。对于【字母级别的1阶、2阶文本和单词级别的0阶、1阶文本】,处理过程类似。
  1. /* Copyright (C) 1999 Lucent Technologies */
  2. /* From 'Programming Pearls' by Jon Bentley */

  3. /* markov.c -- generate random text from input document */

  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. char inputchars[4300000];
  8. char *word[800000];
  9. int nword = 0;
  10. int k = 2;

  11. int wordncmp(char *p, char* q)
  12. {    
  13.     int n = k;
  14.     for ( ; *p == *q; p++, q++)
  15.     {
  16.         if (*p == 0 && --n == 0)
  17.             return 0;
  18.     }
  19.     return *p - *q;
  20. }

  21. int sortcmp(char **p, char **q)
  22. {    
  23.     return wordncmp(*p, *q);
  24. }

  25. char *skip(char *p, int n)
  26. {    for ( ; n > 0; p++)
  27.     {
  28.         if (*p == 0)
  29.             n--;
  30.     }    
  31.     return p;
  32. }

  33. int main()
  34. {    
  35.     int i, wordsleft = 10000, l, m, u;
  36.     char *phrase, *p;
  37.     
  38.     word[0] = inputchars;
  39.     while (scanf("%s", word[nword]) != EOF)
  40.     {
  41.         word[nword+1] = word[nword] + strlen(word[nword]) + 1;
  42.         nword++;
  43.     }

  44.     for (i = 0; i < k; i++)
  45.         word[nword][i] = 0;
  46.     for (i = 0; i < k; i++)
  47.         printf("%sn", word[i]);

  48.     qsort(word, nword, sizeof(word[0]), sortcmp);

  49.     phrase = inputchars;
  50.     for ( ; wordsleft > 0; wordsleft--)
  51.     {
  52.         l = -1;
  53.         u = nword;
  54.         while (l+1 != u)
  55.         {
  56.             m = (l + u) / 2;
  57.             if (wordncmp(word[m], phrase) < 0)
  58.                 l = m;
  59.             else
  60.                 u = m;
  61.         }
  62.         for (i = 0; wordncmp(phrase, word[u+i]) == 0; i++)
  63.         {
  64.             if (rand() % (i+1) == 0)
  65.             {
  66.                 p = word[u+i];
  67.             }
  68.         }
  69.         phrase = skip(p, 1);
  70.         if (strlen(skip(phrase, k-1)) == 0)
  71.         {
  72.             break;
  73.         }
  74.         printf("%sn", skip(phrase, k-1));
  75.     }
  76.     return 0;
  77. }
    关于生成随机文本的代码,需要慢慢的理解其思想,先记录下来,慢慢体会。






    
阅读(2482) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~