闭散列解决哈希冲突
闭散列(也称为开放地址法):一种解决哈希冲突的方法。
应用场景:
对与闭散列的应用,我们可以举一个简单的实例:以函数为除留取余法的哈希函数进行构建哈希表,将会遇到剩余值相等的情况(如:有俩个关键字分别为2,1002,,最大范围为1000,则进行除模取余后,剩余值皆为2,此时就相当于出现了冲突),就是哈希冲突,本次我们将讨论解决冲突方法中的闭散列。闭散列就是,在满足可插入的前提下,将出现冲突的值进行向后寻找位置,找到空位置,将值放入,完成此次插入(同时解决了所遇到的哈希冲突)。
可插入情况:就是计算插入总数量栈总数量的比率,也称为负载因子。
代码实现:
对与闭散列,我们应了解其实质,即插入的时所遇到的几种情况,有数据、无数据和已删除数据。关于有数据和无数据这俩种情况其实很好理解,那么此处主要对已删除数据进行分析。提到已删除数据,我们就应思考一下哈希表的查询,对哈希表的查询过程中,如遇到所查值对应的地址为空,就进行返回的化,那么我们之前所作的工作(闭散列处理哈希冲突)将没有意义,因为在插入过程中,我们为了避免哈希冲突,对冲突数据进行了相应的处理(如”+1“查询)。故此时我们应该引入已删除数据这一种状态,使之不影响后序的查询、删除等一系列操作。
结构体代码:
typedef enum Stat {
Empty,
Valid,
Deleted // 当前元素被删除了
} Stat;
typedef struct HashElem {
KeyType key;
ValType value;
Stat stat; // 引入一个 stat 标记来作为是否有效的标记
} HashElem;
哈希初始化:
1.判断非法输入
2.对结构体内变量进行初始化
void HashInit(HashTable* ht, HashFunc hash_func){
if(ht == NULL){
//非法输入
return;
}
ht->size = 0;
ht->func = hash_func;
int i =0;
for(;i<HashMaxSize;++i){
ht->data[i].stat = Empty;
}
return;
}
哈希插入:
1.判断非法输入,非法直接返回,反之继续;
2.判断是否为"满",满直接返回,反之继续;
3.应用哈希函数对关键字进行分析,得到哈希地址,进行地址状态检测
a)状态为非“有数据状态",直接进行插入操作
b) 状态为”有数据状态“,则对关键字进行+1处理,继续调用哈希函数,取哈希地址进行分析。
代码:
void HashInsert(HashTable* ht, KeyType key, ValType value){
if(ht ==NULL||key<0){
//非法输入
return;
}
if(ht->size> 0.8*HashMaxSize){
//哈希表已经达到上限
return;
}
size_t offset = ht->func(key);
while(1) {
if(ht->data[offset].stat != Valid){
ht->data[offset].key = key;
ht->data[offset].value = value;
ht->data[offset].stat = Valid;
++ht->size;
return;
}else if(ht->data[offset].stat == Valid&&ht->data[offset].key == key){
//约定不能出现相同的key值
return;
}else{
offset = (offset+1)%HashMaxSize;
}
}//while循环结束
}
哈希查找:
1.判断非法输入,非法直接返回,反之继续;
2.判断是否为"空",为空直接返回,反之继续;
3.调用哈希函数对关键字进行分析,得到哈希地址,进行地址状态检测
a)状态为”无数据状态”直接返回,反之继续;
b)状态为非“有数据状态“,关键字对比,查找到,返回相应的值,尾插找到进行+1操作继续。
c)状态为”已删除数据状态”,直接进行+1操作继续。
代码:
// 输入key, 查找对应key的value.
int HashFind(HashTable* ht, KeyType key, ValType* value){
if(ht == NULL){
//非法输入
return 0;
}
if(ht->size == 0){
//哈希表为空
return 0;
}
size_t offset = ht->func(key);
while(1){
if(ht->data[offset].stat == Valid && ht->data[offset].key == key){
*value = ht->data[offset].value;
return 1;
}else if(ht->data[offset].stat == Empty){
return 0;
}else{
offset = (offset+1)%HashMaxSize;
}
}//while结束
}
哈希删除:
删除操作可以 分俩步进行,一、查找(方法同哈希查找),二、删除(需改相应哈希位置上的状态值)。
代码:
void HashRemove(HashTable* ht, KeyType key){
if(ht == NULL){
//非法输入
return;
}
KeyType offset = ht->func(key);
while(1){
if(ht->data[offset].stat == Valid && ht->data[offset].key == key){
ht->data[offset].stat = Deleted;
--ht->size;
return;
}else if(ht->data[offset].stat == Empty){
return;
}else{
offset = (offset+1)%HashMaxSize;
}
}
}
哈希销毁:
1.判断非法输入;
2.修改结构体内容
代码:
void HashDestroy(HashTable* ht){
if(ht == NULL){
//非法输入
return;
}
ht->size = 0;
ht->func = NULL;
return;
}