字符串哈希(进制哈希)

哈希

  简单来说,哈希相当于一种单向加密,一种映射过程,并且要尽量保证加密后不会重复,通过这种方式来替代一些很费时间的操作

字符串哈希 也叫进制哈希

      当你想判断两个字符串是否相等时,不知道你有没有过一种想法,将两个字符串通过一些独特方式的计算转换成两个数字,然后判断两个数是否相等不就好了,那么进制哈希就提供了一种转换方式——将这个字符串看成一个base进制的数,因为进制计算的特殊性,可以保证每个数都代表这一种字符串的情况

      当然,你可能会有疑问 当字符串是s1“100000”和s2“50000”,base=5时 算出的结果是('1'-'0')*5^5与('5'-'0')*5^4的答案是相同的(这里方便理解-了‘0’然鹅与找到ASCII表中相差4倍的情况相同)但由于进制的特殊性, 满base进一,所以这种情况被pass了,我们无法控制给出的数据 但我们能改变base值,所以在实际应用中 要让base大于所有能出现的字符的可能,ASCII码最大为127 而大于127的最小质数为131,所以一般base取131即可。

       base的情况解决了,但如果字符串的长度太大,一般的 int 甚至是long long 都有可能存不下,所以我们可以通过对这个数取模来解决,但他还是有个弊端——两个相同的数对mod取余后得到的数是一样的!!这就导致了传说中的哈希冲突……

        我们设置进制(base)为131,模数(mod)为1e9+7,现在我们对一个字符串s进行哈希   

1        char s[10009];
2       scanf("%s",s+1);
3       int len=strlen(s+1);
4       int base=131,mod=1e9+7; 
5       for(int i=1;i<=len;i++)
6       {
7             hash[i] = ( ( hash[i-1] * base ) + s[i] ) % mod ;
8       }

     借用这张图片更为直观

       因为哈希的处理是一个字符一个字符的而且计算具有规律性,所以我们还可以取到子串的hash值

hash[l,r] = ( hash [r] - hash[l-1] * fpow(base,r-l+1) ) %mod
//fpow(base,r-l+1)为base的(r-l+1)次方

如何处理哈希冲突??

 1.模数选取大质数

    如果选取合数那么他的剩余系将会有所浪费,如果质数过小将会导致剩余系过小,哈希冲突几率增大

  /* 所谓“剩余系”,就是指对于某一个特定的正整数n,一个整数集中的数模n所得的余数域。*/

 2.双模数哈希

    我们可以通过设置两个不同的哈希方式,对于一个字符串,当且仅当两个哈希值都相同时才判定相当。

        这就相当于是双重加密,应该就很靠谱了吧。

猜你喜欢

转载自www.cnblogs.com/YangKun-/p/12488843.html