上篇博客我们以闭散列解决哈希冲突的方式实现了哈希搜索结构。闭散列在实际操作时需要考虑一个问题就是如果插入时发现超过了负载因子,那么这个时候就不能插入了,需要扩容。扩容时,则需要创建更大的空间,并且由于空间变大,导致的可放个数变多,进而导致哈希函数所计算出关键值与对应存储位置发生改变。所以在扩容后拷贝的时候更加的麻烦。
开散列解决哈希冲突
同样再提出开散列之前定义哈希函数,方便查看。
int HashFun(int key)
{
return key % 1000;
}
同样在插入1001时,遇到了哈希冲突,这时候利用开散列解决哈希冲突。
这里相当于在每个下标下存储着一个头指针,这个头指针指向一条单链表。而链表内部存储的元素就是关键码。
实现
//hash.h
#pragma once
#include <stddef.h>
#define HASHMAXSIZE 1000
typedef int Keytype;
typedef int Valtype;
typedef size_t (*HashFun)(Keytype key);
typedef struct HashElem {
Keytype key;
Valtype val;
struct HashElem* next;//尾指针
} HashElem;
typedef struct HashTable {
HashElem* data[HASHMAXSIZE];
size_t size;
HashFun fun;//哈希函数
} HashTable;
void HashInit(HashTable* ht, HashFun fun);//初始化哈希表
void HashInsert(HashTable* ht, Keytype key, Valtype val);//插入哈希表
void HashDestroy(HashTable* ht);//销毁哈希表
void HashRemove(HashTable* ht, Keytype key);//删除哈希表指定元素
int HashFind(HashTable* ht, Keytype key, Valtype* val);//查找哈希表内元素
#include "hash.h"
#include <stdio.h>
#include <stdlib.h>
size_t Function(Keytype key) {
return key % HASHMAXSIZE;
}
void HashInit(HashTable* ht, HashFun fun)//初始化哈希表
{
if(ht == NULL) {
return;
}
ht->size = 0;
ht->fun = fun;
size_t i = 0;
for(; i < HASHMAXSIZE; ++i) {
ht->data[i] = NULL;
}
return;
}
HashElem* CreateElem(Keytype key, Valtype val)
{
HashElem* new_elem = (HashElem*)malloc(sizeof(HashElem));
new_elem->key = key;
new_elem->val = val;
new_elem->next = NULL;
return new_elem;
}
void HashInsert(HashTable* ht, Keytype key, Valtype val)//插入哈希表
{
if(ht == NULL) {
return;
}
size_t offset = ht->fun(key);
HashElem* cur = ht->data[offset];
while(cur != NULL) {
if(cur->key == key) {//关键码一样就不插入
return;
}
cur = cur->next;
}
HashElem* new_elem = CreateElem(key, val);//链表头插
new_elem->next = ht->data[offset];
ht->data[offset] = new_elem;
++ht->size;
return;
}
void Destroy(HashElem* cur)
{
free(cur);
cur = NULL;
}
void HashDestroy(HashTable* ht)//销毁哈希表
{
if(ht == NULL) {
return;
}
if(ht->size == 0) {
return;
}
size_t i = 0;
for(; i < HASHMAXSIZE; ++i) {
HashElem* cur = ht->data[i];
if(cur == NULL) {
continue;
}
while(cur != NULL) {
HashElem* pre = cur;
Destroy(cur);
cur = pre->next;
}
}
ht->size = 0;
ht->fun = NULL;
return;
}
void HashRemove(HashTable* ht, Keytype key)//删除哈希表指定元素
{
if(ht == NULL) {
return;
}
size_t offset = ht->fun(key);
HashElem* cur = ht->data[offset];
HashElem* pre = NULL;
while(cur != NULL) {
if(cur->key == key) {
break;
}
pre = cur;
cur = cur->next;
}
if(cur == NULL) {
return;
}
if(pre == NULL) {
HashElem* tmp = ht->data[offset];
ht->data[offset] = tmp->next;
Destroy(tmp);
} else {
pre->next = cur->next;
Destroy(cur);
}
return;
}
int HashFind(HashTable* ht, Keytype key, Valtype* val)//查找哈希表内元素
{
if(ht == NULL) {
return 0;
}
if(ht->size == 0) {
return 0;
}
size_t offset = ht->fun(key);
HashElem* cur = ht->data[offset];
while(cur != NULL) {
if(cur->key == key) {
*val = cur->val;
return 1;
}
cur = cur->next;
}
return 0;
}
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!