闭散列解决哈希冲突-----数据结构

闭散列解决哈希冲突

闭散列(也称为开放地址法):一种解决哈希冲突的方法。

应用场景:

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

猜你喜欢

转载自blog.csdn.net/cyd_csdn/article/details/80483151