hash和hash碰撞以及解决方案
hash:
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
hash碰撞:
如果两个输入串的hash函数的值一样,则称这两个串是一个碰撞(Collision)。既然是把任意长度的字符串变成固定长度的字符串,所以必有一个输出串对应无穷多个输入串,碰撞是必然存在的。一个优良的hash函数 f 应当满足以下三个条件:
(1)对于任意y,寻找x,使得f(x)=y,在计算上是不可行的。
(2)给定x1∈A,找x2∈B,,使得f(x1)=f(x2),在计算上是不可能的,这也就是弱无碰撞性。
(3)寻找x1,x2,使得f(x1)=f(x2),在计算上也是不可行的,这也就是强无碰撞性。
这样就称为安全保密的Hash函数,除了枚举外不可能有别的更快的方法。如第3条,根据生日定理,要想找到这样的x1,x2,理论上需要大约2^(n/2)的枚举次数。
因为前两条都能被破坏的hash函数太弱而被抛弃,几乎所有的hash函数的**,都是指的破坏上面的第3条性质,即找到一个碰撞。在密码学上还有一个概念是理论**,指的是提出一个算法,使得可以用低于理论值得枚举次数找到碰撞。
解决方法:
对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个对象计算值一样时,这就发生了碰撞冲突。
1.开放地址法
开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)其中,m为哈希表的表长。di 是产生冲突的时候的增量序列。如果di值可能为1,2,3,…m-1,称线性探测再散列。
如果di取1,则每次冲突之后,向后移动1个位置.如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,…k*k,-k*k(k<=m/2),称二次探测再散列。
如果di取值可能为伪随机数列。称伪随机探测再散列。2.再哈希法
当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。比如上面第一次按照姓首字母进行哈希,如果产生冲突可以按照姓字母首字母第二位进行哈希,再冲突,第三位,直到不冲突为止。
3.链地址法(拉链法)
将所有关键字为同义词的记录存储在同一线性链表中。如下:
因此这种方法,可以近似的认为是筒子里面套筒子。
优点:
缺点:
4.建立一个公共溢出区
假设哈希函数的值域为[0,m-1],则设向量HashTable[0..m-1]为基本表,另外设立存储空间向量OverTable[0..v]用以存储发生冲突的记录。