什么是哈希冲突?哈希冲突怎么解决?
一、什么是哈希冲突?
Ⅰ.什么是哈希?
概念:hash音译为哈希,是把任意长度的输入通过散列算法变换成固定长度的输出,
该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间。
哈希算法其实是一个复杂的运算,它的输入可以是字符串,可以是数据,可以是任何文件,经过哈希运算后,变成一个固定长度的输出,
该输出就是哈希值。但是哈希算法有一个很大的特点,就是你不能从结果推算出输入,所以又称为不可逆的算法。
例如:
System.out.println(hash("星期一"));
System.out.println(hash("星期二"));
Ⅱ.什么是哈希冲突?
就是键(key)经过hash函数得到的结果作为地址去存放当前的键值对,但是却发现该地址已经被占用,这个时候就会发生冲突。这个冲突就是hash冲突了。
概括:如果两个不同对象的hashCode相同,这种现象称为哈希冲突。
二、哈希冲突怎么解决
1.开放地址法
开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
公式为:fi(key) = (f(key)+di) MOD m (di=1,2,3,……,m-1)
例如:
集合为{12,67,56,16,25,37,22,29,15,47,48,34}
我们用散列函数f(key) = key mod l2
当计算前5个数{12,67,56,16,25}时,我们用散列函数存入:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
关键字 | 12 | 25 | 16 | 67 | 56 |
当存入key = 37时,发现f(37) = 1,此时就与25所在的位置冲突。
于是我们应用上面的公式f(37) = (f(37)+1) mod 12 = 2。于是将37存入下标为2的位置:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
关键字 | 12 | 25 | 37 | 16 | 67 | 56 |
2.再哈希法
这种方法是同时构造多个不同的哈希函数:
Hi=RH1(key) i=1,2,…,k
当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……
直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
3.链地址法
将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
4.建立公共溢出区
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。