哈希hash

传统搜索算法是基于比较的,而哈希搜索算法通过关键字的值来标记元素的位置。
哈希算法由两部分组成,首先是能够将查询关键字转换成表地址的哈希函数。理想情况是不同的关键字映射到不同的地址,但经常出现两个或者多个关键字对应同一表地址的情况,如果两个输入关键字的hash函数的值一样,则称这两个关键字是一个碰撞(Collision),处理这种关键字的过程就是哈希搜索算法的第二部分冲突调节。
哈希函数:
如果我们有一个长度为M的表,那么我们需要的是能把关键字转化成[0,M-1]范围内整数的函数,理想的哈希函数要易于计算并且近似为随机函数,随机是指每一个输入,相应的输出应在某种程度上是等概率的。最简单的哈希函数h(k)=k mod M 其中M最好是接近表长的素数,这样可以减少冲突的几率,实际运算中k的值会比较大,可以采取分段计算的办法,因为
(a mod M + b) mod M = (a+b) mod M。对于字符串一个简单的哈希算法


int hash(char *v, int M)
{
int h = 0,a = 127;
for(; *v != 0; v++)
h = (a*h + *v) % M;

return h;
}
/*
本程序采用霍纳算(Horner)法,7位ASCII码基数为128,这里采用127素数
*/

上面的算法中乘数是固定的,我们可以选择乘数为随机数的算法
字符串的通用哈希算法

int hashU(char *v,int M)
{ int h,a = 31415,b = 27183;
for(h = 0; *v != 0; v++,a = a*b % (M-1))
h = (a*h + *v) % M

return (h < 0) ? (h + M) : h;
}
//为了算法效率的问题采用了一种简单的伪随机数

通用算法显然还是要比前一种算法慢很多,一般而言,最快的算法是使M为2的幂且使用下面的散列函数

inline int hash(Key v, int M)
{return v & (M-1);}


下面来看看JDK中的哈希算法

String的哈希算法


public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;

for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}

在hashMap中

再哈希

private static int oldHash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}

取下标

static int indexFor(int h, int length) {
return h & (length-1);
}

表长度都是2^t这样下标范围在0~2^t-1,将哈希值与2^t-1进行&操作就得到了该范围内的下标,注意2^t-1的最后t位上全都是1,这样才能让哈希值的最后t位都能发挥作用,最大限度进行随机。 表扩容时是在原有长度(默认从16开始)翻倍,这样最后t位上始终是1

利用哈希算法的还有
Rabin-Karp字符串匹配算法

假定字符集Σ ={0, 1, 2, ……, 9}, 每一个字符对应一个十进制数字
(一般情况, 假定每个字符是基数为d的表示法中的一个数字, d=|Σ|。)可以用一个长度为k的十进制数字来表示由k个连续字符组成的字符串.
因此,字符串"31415" 对应于十进制数31415
已知模式P[1..m],设p表示其相应十进制数地值,类似地, 对于给定的文本T[1..n]. 用
ts 表示长度为m的子字符串 T[s + 1 ‥ s + m]( s = 0, 1, . . . , n – m), ts = p 当且仅当 [s + 1 ‥ s + m] = P[1 ‥ m]; 因此s是有效位移当且仅当 ts = p.
可以用霍纳规则(Horner’s rule) 在Θ(m) 的时间内计算p的值
p = P[m] + 10 (P[m - 1] + 10(P[m - 2] + · · · + 10(P[2] + 10P[1]) )).

类似地,可以在Θ(m)时间内,根据T[1..m]计算出t0 的值。
如果能在总共Θ(n - m + 1) 时间内计算出所有的ts 的值,那么通过把p值与每个ts(有n-m+1个)进行比较,就能够在Θ(m) + Θ(n - m + 1)= Θ(n) 时间内求出所有有效位移。(计算出1个ts 就跟p比较,处理结果。)
为了在Θ(n - m) 时间内计算出剩余的值t1, t2, . . . , tn-m 可以在常数的时间内根据ts计算出ts+1,先看例子,假如m = 5,ts = 31415, 我们去掉高位数字T [s + 1] = 3,然后在加入一个低位数字T [s + 5 + 1](假设为2),得到:
ts+1 = 10(31415 - 10000 • 3) + 2 = 14152.

哈希算法在密码学中应用非常广泛
在这方面目前应用最为广泛的hash函数是SHA-1和MD5,他们哈希值大多是128位和更长

hash函数在现实生活中应用十分广泛。很多下载网站都提供下载文件的MD5码校验,可以用来判别文件是否完整。另外,比如在重要的数据库中,所有密码都是保存的MD5码,这样即使数据库的管理员也无法知道用户的原始密码(MD5理论上是不可逆的,但现在好像已经被破解了,可以制造一个MD5码相同的字符串),避免隐私泄露(很多人在不同地方都是用的同一个密码)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值