浅谈哈希hash

哈希表

哈希表其实就是建立和存储一种映射关系

离散化、桶排序就是一种简单数值哈希

常见的哈希方法:

除法哈希法  hash(key)=keymod M(M为素数)

乘法哈希法  hash(key)=floor(M/W*(a*key mod W))

	通常设置M为2的幂次方
    
	W为计算机字长大小(也为2的幂次方)
    
	a为一个非常接近于W的数

	若a=W*(√5-1)/2,则为斐波拉契哈希法

相同的输入hash之后一定相同hash值相同的值一定是同一个输入吗?

—— “哈希冲突”

哈希冲突

分布示意图

是哈希就会冲突,但是合理的选择哈希函数可以让冲突的概率降低真的冲突了怎么办?

冲突解决办法:

拉链法  链表实现,每个位置一个链表,存储冲突的元素

开放地址法  如果冲突,就按一定的规则放到其它位置
哈希冲突解决方法

字符串哈希

OI里面常常涉及到的时候字符串哈希,字符串哈希的算法也有很多

最著名的就是BKDR Hash具体做法:

	•将字符串变成数值,并且最后变成的数值是一个P进制的数(一般取131或者13331)一般来说P最好为素数.

	•由于字符串相同,就转化为区间的值相同,所以求一个前缀和

构造方法:

假如给你一个数字1166,形式上你只知道它只是1和6的组合

但你知道它代表的实际大小1103+1102+6101+6100

同理,给你一个字符串,要把它转换为数字

就可以先把每一个字符都先对应一个数字

然后把它们按照顺序乘以进制的幂进行相加

算法过程

处理过程

      •把字符串看成P进制数

      •预处理字符串所有的前缀hashhash[i] = (hash[i-1] * P + str[i])mod Q

      •计算区间hashhash[l, r] = hash[r] -hash[l-1] * p[r -l + 1]这里P一般取131或者13331

      •Q一般取1e9+71e9+9等大素数,这样冲突的机率极小(姑且视作不冲突)

      •如果Q取,可以直接用unsigned long long自然溢出反复求值,提前预处理p[n]:更佳

一本通另一种求区间hash值的方法

H[m]=(C1pm-1+C2pm-2+...+Cmp0)% MOD

H[k]=H[k-1]*p+str[k];

举个例子:

C=“ABCD”

H[1]=1;

H[2]=1*p+2;

H[3]=1p2+2p+3;

H[4]=1p3+2p2+3*p+4;

然后对于某一段字符串的哈希值,C'=“BC”

H[C']=H[3]-H[1]*p2

对于C'=Ck+1Ck+2...Ck+n

H[C']=H[k+n]-H[k]*pn

双哈希

为什么要双哈希?

单次哈希判断相同容易被hack,也就是说不同的输入会得到相同的结果,所以建议多次哈希经验证明:其实只需要两次哈希就行了,称为双哈希(要是不放心,三哈希也行,但经过历代older的实践,几乎所有时候双哈希就ok了)

h1[i] = (h1[i]*base1+s[i][j]) % mod1;

h2[i] = (h2[i]*base2+s[i][j]) % mod2;

判断是否相等:h1[i]h1[j]&&h2[i]h2[j]

双哈希参考代码

#include<bits/stdc++.h>
using namespace std;
const int mod1=10000007,mod2=13333337;
int h1[10002], h2[10002];
char s[10002][1502];
int n;
int p1, p2;
int main() {
	srand((unsigned)time(0));
	p1 = rand()%100+200, p2 = rand()%300+400;
	scanf("%d",&n);
  	for(int i=1; i<=n; i++)
		scanf("%s", s[i]);
	for(int i=1; i<=n; i++) {
		int len=strlen(s[i]);
		for(int j=0; j<len; ++j) {
			h1[i]=(h1[i]*p1+s[i][j]) % mod1;
			h2[i]=(h2[i]*p2+s[i][j]) % mod2;
		}
	}
	int ans= n;
	for(int i=1; i<=n; ++i)
		for(int j=i-1; j>=1; --j)
			if(h1[i]==h1[j] && h2[i]==h2[j]         ) {
				--ans;
				break;
			}
	printf("%d",ans);
	return 0;
}

STL:map

在STL里也有一个类似于哈希一样的key-value对应的东西

map

定义:map<key类型,value类型> namemap

hash_map

使用了拉链法的哈希表,可以自定义哈希函数(默认有一个哈希函数)

本文作者:Yvette的博客

本文链接:https://www.cnblogs.com/yvette1217/p/16348974.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Youngxy  阅读(89)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示