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

你可能感兴趣的:(hash表)