Happyunlimited 2019-12-08
双重散列是线性开型寻址散列(开放寻址法)中的冲突解决技术。双重散列使用在发生冲突时将第二个散列函数应用于键的想法。
此算法使用:
(hash1(key) + i * hash2(key)) % TABLE_SIZE
来进行双哈希处理。hash1() 和 hash2() 是哈希函数,而 TABLE_SIZE 是哈希表的大小。当发生碰撞时,我们通过重复增加 步长i 来寻找键。
第一个Hash函数:hash1(key) = key % TABLE_SIZE。
/**
* 计算首次的Hash值
*
* @param key
* @return
*/
private int hash1(int key) {
return (key % TABLE_SIZE);
}第二个Hash函数是:hash2(key) = PRIME – (key % PRIME),其中 PRIME 是小于 TABLE_SIZE 的质数。
/**
* 发生碰撞是时继续计算Hash值
*
* @param key
* @return
*/
private int hash2(int key) {
return (PRIME - (key % PRIME));
}第二个Hash函数表现好的特征:
绝对不会产生 0 索引
能在整个HashTable 循环探测
计算会快点
与第一个Hash函数互相独立
PRIME 与 TABLE_SIZE 是 “相对质数”

Java实现代码:
package algorithm.hash;
/**
* 双重哈希
*/
public class DoubleHash {
private static final int TABLE_SIZE = 13; // 哈希表大小
private static int PRIME = 7; // 散列函数值
private int[] hashTable;
private int curr_size; // 当前表中存的元素
public DoubleHash() {
this.hashTable = new int[TABLE_SIZE];
this.curr_size = 0;
for (int i = 0; i < TABLE_SIZE; i++)
hashTable[i] = -1;
}
private boolean isFull() {
return curr_size == TABLE_SIZE;
}
/**
* 计算首次的Hash值
*
* @param key
* @return
*/
private int hash1(int key) {
return (key % TABLE_SIZE);
}
/**
* 发生碰撞是时继续计算Hash值
*
* @param key
* @return
*/
private int hash2(int key) {
return (PRIME - (key % PRIME));
}
/**
* 向Hash表中存值
*
* @param key
*/
private void insertHash(int key) {
/* 表是否已满 */
if (isFull()) {
return;
}
/* 获取首次的Hash值 */
int index = hash1(key);
// 如果发生碰撞
if (hashTable[index] != -1) {
/* 计算第二次的Hash值 */
int index2 = hash2(key);
int i = 1;
while (true) {
/* 再次合成新的地址 */
int newIndex = (index + i * index2) % TABLE_SIZE;
// 如果再次寻找时没有发生碰撞,把key存入表中的对应位置
if (hashTable[newIndex] == -1) {
hashTable[newIndex] = key;
break;
}
i++;
}
} else {
// 一开始没有发生碰撞
hashTable[index] = key;
}
curr_size++; // Hash表中当前所存元素数量加1
}
/**
* 打印Hash表
*/
private void displayHash() {
for (int i = 0; i < TABLE_SIZE; i++) {
if (hashTable[i] != -1)
System.out.println(i + " --> " + hashTable[i]);
else
System.out.println(i);
}
}
public static void main(String[] args) {
int[] a = {19, 27, 36, 10, 64};
DoubleHash doubleHash = new DoubleHash();
for (int i = 0; i < a.length; i++)
doubleHash.insertHash(a[i]);
doubleHash.displayHash();
}
}