双重哈希的开放寻址
似乎无法正确理解。某些隐藏的情况下有错误(输入和输出都看不到),所以我想看看是否有人可以帮助发现错误。
我正在通过双重哈希实现一个开放寻址哈希表来执行插入和删除。下面给出哈希槽的结构,在main函数中创建了一个有37个哈希槽的哈希表
提供哈希函数。
hash2()
是用于双重哈希的增量哈希函数。
两个函数的返回值分别是插入和删除时进行的键比较次数。插入重复键将返回 -1。如果键比较的次数大于表的大小,则表示表已满。对于删除函数,如果删除键不存在,则返回-1。删除时的key比较次数不能超过table size
#include <stdio.h>
#include <stdlib.h>
#define TABLESIZE 37
#define PRIME 13
enum Marker {EMPTY,USED,DELETED};
typedef struct _slot{
int key;
enum Marker indicator;
} HashSlot;
int HashInsert(int key, HashSlot hashTable[]);
int HashDelete(int key, HashSlot hashTable[]);
int hash1(int key);
int hash2(int key);
int main()
{
int opt;
int i;
int key;
int comparison;
HashSlot hashTable[TABLESIZE];
for(i=0;i<TABLESIZE;i++){
hashTable[i].indicator = EMPTY;
hashTable[i].key = 0;
}
printf("============= Hash Table ============\n");
printf("|1. Insert a key to the hash table |\n");
printf("|2. Delete a key from the hash table|\n");
printf("|3. Print the hash table |\n");
printf("|4. Quit |\n");
printf("=====================================\n");
printf("Enter selection: ");
scanf("%d",&opt);
while(opt>=1 && opt <=3){
switch(opt){
case 1:
printf("Enter a key to be inserted:\n");
scanf("%d",&key);
comparison = HashInsert(key,hashTable);
if(comparison <0)
printf("Duplicate key\n");
else if(comparison < TABLESIZE)
printf("Insert: %d Key Comparisons: %d\n",key, comparison);
else
printf("Key Comparisons: %d. Table is full.\n",comparison);
break;
case 2:
printf("Enter a key to be deleted:\n");
scanf("%d",&key);
comparison = HashDelete(key,hashTable);
if(comparison <0)
printf("%d does not exist.\n", key);
else if(comparison <= TABLESIZE)
printf("Delete: %d Key Comparisons: %d\n",key, comparison);
else
printf("Error\n");
break;
case 3:
for(i=0;i<TABLESIZE;i++) printf("%d: %d %c\n",i, hashTable[i].key,hashTable[i].indicator==DELETED?'*':' ');
break;
}
printf("Enter selection: ");
scanf("%d",&opt);
}
return 0;
}
int hash1(int key)
{
return (key % TABLESIZE);
}
int hash2(int key)
{
return (key % PRIME) + 1;
}
int HashInsert(int key, HashSlot hashTable[])
{
int hash = hash1(key);
int i = 0;
int comparisons = 0;
while (hashTable[hash].indicator == USED && hashTable[hash].key != key && i < TABLESIZE) {
hash = (hash + hash2(key)) % TABLESIZE;
i++;
comparisons++;
}
if (hashTable[hash].key == key&&hashTable[hash].indicator == USED) {
return -1; // Key already exists
}
if (i >= TABLESIZE) {
return comparisons ; // Table is full, count initial comparison
}
hashTable[hash].key = key;
hashTable[hash].indicator = USED;
return comparisons ; // Count initial comparison
}
int HashDelete(int key, HashSlot hashTable[])
{
int hash = hash1(key);
int i = 0;
int comparisons = 1;
while (hashTable[hash].indicator != EMPTY && i < TABLESIZE) {
if (hashTable[hash].indicator == USED && hashTable[hash].key == key) {
hashTable[hash].indicator = DELETED;
return comparisons;
}
hash = (hash + hash2(key)) % TABLESIZE;
i++;
comparisons++;
}
return -1; // Key not found
}
标记为已删除的插槽(即墓碑)意味着“链”尚未终止并且必须继续搜索密钥,直到到达
EMPTY
插槽或用尽所有插槽。
在您的示例中删除密钥时,这是正确完成的:搜索密钥仅在到达
EMPTY
插槽而不是 DELETED
插槽时停止。
然而,插入钥匙时没有这样做。在这种情况下,插入可以分解为两部分
注意,一旦所有槽至少被使用一次,每次插入都会进行最大次数的键比较(所有键都必须被搜索)
为了防止这种情况,需要重新散列/重新定位插槽以将插槽恢复为DELETED
这似乎超出了您的练习范围。EMPTY
下面是更正后的代码,我们首先找到插入点并单独保存,然后再继续搜索重复项。
int HashInsert(int key, HashSlot hashTable[])
{
int hash = hash1(key);
int insertAt, i = 0;
int comparisons = 0;
while (hashTable[hash].indicator == USED && hashTable[hash].key != key && i < TABLESIZE) {
hash = (hash + hash2(key)) % TABLESIZE;
i++;
comparisons++;
}
if (i >= TABLESIZE) {
return comparisons ; // Table is full, count initial comparison
}
insertAt = hash; // Save the insertion point first
// We will continue probing till the end (i.e. hitting an EMPTY slot)
// to check if the key is indeed not in the hashTable
while (hashTable[hash].indicator != EMPTY && i < TABLESIZE) {
if (hashTable[hash].indicator == USED) { // Do a key compare if slot is in use
comparisons++;
if (hashTable[hash].key == key) // Key already exists
return -1;
}
hash = (hash + hash2(key)) % TABLESIZE;
i++;
}
hashTable[insertAt].key = key;
hashTable[insertAt].indicator = USED;
return comparisons ; // Count initial comparison
}
comparisons
的错误计数这是一个小错误,但是您在删除键时错误地计算了比较次数。
不应该在墓碑上进行关键比较,下面是更正后的代码。
int HashDelete(int key, HashSlot hashTable[])
{
int hash = hash1(key);
int i = 0;
int comparisons = 0; // Number of comparisons should start from 0
while (hashTable[hash].indicator != EMPTY && i < TABLESIZE) {
if (hashTable[hash].indicator == USED) {
comparisons++; // Only compare when the slot is USED
if (hashTable[hash].key == key) {
hashTable[hash].indicator = DELETED;
return comparisons;
}
}
hash = (hash + hash2(key)) % TABLESIZE;
i++;
}
return -1; // Key not found
}