一 不同散列的计算
给定数据{4371,1323,6173,4199,4344,9679,1989}和散列函数h,给出下列结果
- 分离链接散列表
- 使用线性探测散列表
- 使用平方探测散列表
- 将上述中的散列表再散列
解答:
- 使用链接散列表。这个是使用链表解决冲突。表的长度为10. 可以看出链表法总共有三次冲突。
- 线性探测:4371%10=1,没有冲突;1323%10=3,没有冲突;6173%10=3,此时冲突了,放在index=4的位置。4199%10=9,没有冲突;4344%10=4,此时index=4的位置上有数据了,那么放在index=5的位置上。这就是线性探测法。
3. 平方探测法。
4 .再散列是因为散列表中的数据过于密集,此时扩容原来列表的2倍。原来的size=10,此时变为20.
二 双散列实现。
双散列:通过第一个hash计算,比如key%tableSize,此时出现冲突后使用如下的公式计算。
(hash1(key) + i * hash2(key)) % TABLE_SIZE 。hash2(key)=R-(key%R)。其中R为一个小于表长的素数。当发生碰撞时,我们通过重复增加 步长i 来寻找键
1 线性探测的java实现
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();
}
}
打印如下: