• Hlg 1618 词频统计.cpp【hash表 + 求字符串hash值】


    题意:

     只有一组数据,数据量为20M

    根据单词出现顺序输出出现次数..

    思路:

    3种方法:① map  ② BKDR求hash值<hash表的线性再散列方法或者是链表形式>

    map的方法因为数据量很大..容易超时

     

    Tips:

    ※ BKDR求字符串hash值方法:

    View Code
     1 unsigned int BKDRHash(char *str)
     2 {
     3     unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
     4     unsigned int hash = 0;
     5 
     6     while (*str)
     7     {
     8         hash = hash * seed + (*str++);
     9     }
    10 
    11     return (hash & 0x7FFFFFFF);
    12 }

    原创是byvoid大人~

     

    ※学到了一种存所有单词的最省空间方法..

    View Code
     1 char buf[MAX_SIZE];
     2 char *sa[MAXN];
     3 char *ch;
     4 int cnt;
     5 // 读入字符串
     6 ch = buf;
     7 while (EOF != scanf("%s", ch)) {
     8     sa[cnt++] = ch;
     9     ch += strlen(ch) + 1;
    10 }

    原创是黄老~

    ※ 以前用map的时候都是

    if(map[str] == 0) map[str] = tot++;

    count[map[str]]++;

    这样..但是因为调用map其实很费时间..

    所以改进为int tmp = map[str];

    if(tmp != 0) count[tmp]++;

    else {

      map[str] = tot++;

      count[tot-1] = 1;

    }

    ※ 对于hash链表和BKDR求hash值方法~个人感觉可以不一起使用~

    hash链表比线性再散列快..因为不管是插入新值还是查询的时候都比线性再散列比较次数少..但是BKDR已经可以很大程度的减少了冲突..所以重叠使用反而不如BKDR+线性再散列快..

    ※ ※ ※ 这里无法忽视的都是数据的存储问题..

    数组的大小很难控制..

    太大了程序要崩溃..太小了会越界~

    所以代码是存在问题的..

    在数组大小那里..仅仅因为数据弱而ac了..

    解决方案可以是先把字符串读入并记录单词个数

    然后根据单词个数为数组开内存..

    而解决单词的问题就用黄老的单词缓存方法~

    Code:

    Map
     1 #include <stdio.h>
     2 #include <map>
     3 #include <string>
     4 using namespace std;
     5 
     6 map<string, int> m;
     7 char arr[4000024];
     8 int cnt[100024];
     9 int main()
    10 {
    11     int tot = 1;
    12     while(scanf("%s", arr) != EOF) {
    13         int tt = m[arr];
    14         if(tt != 0) cnt[tt]++;
    15         else {
    16             m[arr] = tot++;
    17             cnt[tot-1]++;
    18         }
    19     }
    20     for(int i = 1; i < tot; ++i)
    21         printf("%d\n", cnt[i]);
    22     return 0;
    23 }
    BKDR+Hash链表
     1 #include <stdio.h>
     2 #include <cstring>
     3 using namespace std;
     4 const int MAX_SIZE = 21000000;
     5 const int MAXN = 3000;
     6 
     7 struct Node
     8 {
     9     char *s;
    10     Node *next;
    11     int value;
    12 }*hash[MAX_SIZE], *p;
    13 
    14 unsigned int BKDRHash(char *str) {
    15     unsigned int seed = 131; //31 131 1313 13131 131313 etc...
    16     unsigned int hash = 0;
    17 
    18     while(*str) hash = hash*seed + (*str++);
    19 
    20     return (hash&0x7FFFFFFF);
    21 }
    22 
    23 char buf[MAX_SIZE];
    24 int cnt[180000];
    25 int tot;
    26 char *ch;
    27 unsigned int key;
    28 
    29 int main()
    30 {
    31     bool flag;
    32     ch = buf;
    33     tot = 0;
    34     for(int i = 0; i < MAXN; ++i)
    35     hash[i] = NULL;
    36     while(EOF != scanf("%s", ch)) {
    37         flag = false;
    38         key = BKDRHash(ch);
    39         for(p = hash[key%MAXN]; p; p = p->next)
    40         if(strcmp(p->s, ch) == 0) {
    41             cnt[p->value]++;
    42             flag = true;
    43         }
    44         if(!flag) {
    45             Node *tmp = new Node;
    46             tmp->s = ch;
    47             tmp->value = tot++;
    48             cnt[tot-1] = 1;
    49             tmp->next = hash[key%MAXN];
    50             hash[key%MAXN] = tmp;
    51             ch = ch+strlen(ch)+1;
    52         }
    53     }
    54     for(int i = 0; i < tot; ++i)
    55     printf("%d\n", cnt[i]);
    56     return 0;
    57 }
    BKDR+线性再散列
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 
     5 const int maxn = 180000;
     6 
     7 int BKDRHash(char *str)
     8 {
     9     int hash = 0;
    10     while (*str)
    11     {
    12         hash = hash*31 + (*str++);
    13     }
    14     return (hash & 0x7FFFFFFF);
    15 }
    16 
    17 struct node
    18 {
    19     int count;
    20     char *s;
    21 }h[maxn];
    22 
    23 int num[maxn]={0};
    24 int tot = 0;
    25 void hashinsert(char *str)
    26 {
    27     int val = BKDRHash(str)%maxn;
    28     while (h[val].count != 0)
    29     {
    30         if (strcmp(h[val].s,str)==0)
    31         {
    32             h[val].count++;
    33             break;
    34         }
    35         val = (val+1)%maxn;
    36     }
    37     if (h[val].count == 0)
    38     {
    39         int len = strlen(str);
    40         h[val].s = (char*)malloc(sizeof(char)*(len+1));
    41         strcpy(h[val].s,str);
    42         h[val].count++;
    43         num[++tot] = val;
    44     }
    45 }
    46 
    47 char ss[3000000];
    48 
    49 int main()
    50 {
    51     memset(h,0,sizeof(h));
    52     while (scanf("%s",ss)!=EOF)
    53     {
    54         hashinsert(ss);
    55     }
    56     int i;
    57     for (i=1; i<=tot; i++)
    58         printf("%d\n",h[num[i]].count);
    59     return 0;
    60 }

    题目链接:

    http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1618

  • 相关阅读:
    linux的find命令详解
    在接口中的静态方法来获取model的实例对象
    php函数decbin
    cookie的默认有效目录
    html的base标签
    mysql多位小数字段用decimal类型
    vmware在桥接模式下配置centos7网络
    iis_rewrite3突然无法使用(因为它过期啦)
    LightGBM 调参方法(具体操作)
    沪深股票的复权计算(复权因子的应用)--代码实现
  • 原文地址:https://www.cnblogs.com/Griselda/p/2860469.html
Copyright © 2020-2023  润新知