闭散列解决哈希冲突
闭散列(也称为开放地址法):一种解决哈希冲突的方法。
应用场景:
对与闭散列的应用,我们可以举一个简单的实例:以函数为除留取余法的哈希函数进行构建哈希表,将会遇到剩余值相等的情况(如:有俩个关键字分别为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; }