关于哈希的总结

来源:互联网 发布:诺亚幻想 知乎 编辑:程序博客网 时间:2024/06/05 15:40

注:
1. 本文章主要为了说明关于哈希函数的选取,但不说明为什么要这么选。
2. 只针对做题的哈希及哈希表的总结,不是工业加密的那个哈希。。
主要选取以下题目:
poj1840 poj3640 poj3349 poj2002 poj1200 poj2503 poj1496 poj3274 poj1077

哈希的作用我觉得就是判重和查找,其实是一个意思。如果题目要求判断数组,字符串,一个数,等等是否出现过,或者是否和另一个数组,字符串相等。这时候我们就可以利用哈希的特性,将其转换成一个数字,然后进行判断。

考哈希的题都有以上特点,那时只需用一个哈希函数转换一下就ok了,那么该如何转换呢?

  • 数组的转换
int getkey(int *v,int k){       int i,p=0;       for(i=1; i<k; i++)              p=((p<<2)+(v[i]>>4))^(v[i]<<10);       p = p%prime;       if(p<0)    p=p+prime;       return p;}
  • 字符串的转换(cf 835D(可参考我的另一篇博客))
unsigned long long p[maxn+10];//maxn为字符串的最长长度unsigned long long S[maxn+10];void init(){    p[0]=1;    for(int i=1;i<=maxn;i++)        p[i]=p[i-1]*hashsize;    for(int i=1;i<=len;i++)        S[i]=S[i-1]*hashsize+a[i-1];}unsigned long long HS(int l,int r){    if(l==r)return a[l];    l++,r++;    return S[r]-S[l-1]*p[r-l+1];}
  • 从1到n的全排列
    这个专业术语叫做康拓展开,但我感觉和hash如出一辙,将一个排列转换成一个0-n!-1的一个数。
int fact[10];                                           //fact[i] = i!fact[0] = 1;for(int i = 1; i < 9; ++i) fact[i] = fact[i-1]*i;int kt(int s[], int n) {                                //n个数的排列s[0,n-1]    int ans = 0, cnt = 0;                               //返回其在全排列中的位置-1    for(int i = 0; i < n; ++i) {        cnt = 0;                                        //cnt为在i后面出现的小于s[i]的数的个数        for(int j = i+1; j < n; ++j) if(s[j] < s[i]) ++cnt;        ans += cnt*fact[n-i-1];    }    return ans;}

结语: 博主其实对哈希的理解非常浅薄,如果有更好的哈希函数,希望能和读者一起探讨,谢谢。