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

转载于:https://www.cnblogs.com/Griselda/archive/2013/01/14/2860469.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值