數據結構之哈希衝突解決方法(開放地址法)

首先我們來了解一下什麼叫做哈希表
在順序搜序偶以及二叉搜索樹種,元素存儲位置和元素個關鍵碼之間沒有對應關係,因此在查找一個元素時,必須要經過關鍵碼的多次比較。
而我們理想的搜索方法:可以不經過任何比較,一次直接可以從表中得到想要的元素

當向一個結構中
*插入元素時:根據待插入元素的關鍵碼,以此桉樹計算出鈣元素的存儲位置,並按該位置存放
*搜索元素時,根據元素的關鍵碼進行同樣的計算,把求得的函數值當做元素的存儲位置,在結構中按此位置取元素,比較,若關鍵碼相等則說明搜索成功

這種方法就叫做哈希方法,其中用到的函數就是哈希函數,構建出來的結構稱爲哈希表

哈希衝突

**哈希衝突是怎麼出現的呢?
我們來舉個例子
對於兩個數據元素的關鍵字K(i),K(j).有k(i) != k(j)但是通過哈希函數計算出來相同的哈希地址,這種現象就稱爲哈希衝突。**

下面我們就來說一種哈希衝突的解決方法:閉散列,也叫開放地址法。當發生哈希衝突時,如果哈希表未被裝滿,說明哈希表中必然還有空位置,那麼就可以吧key存放到表中“下一個”空位中去

下面看具體的代碼實現

hash.h

#pragma once
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

#define HASHMAXSIZE 1000

typedef enum{
    Empty,
    Valid,
    Removed
}stat;

typedef int keytype;
typedef int valtype;

typedef int(*HashFunc)(keytype key);
typedef struct HashElem{
    keytype key;
    valtype value;
    stat stat;
}HashElem;
typedef struct HashTable{
    HashElem data[HASHMAXSIZE];
    size_t size;
    HashFunc func;
}HashTable;
void HashInit(HashTable *ht,HashFunc hash_func);
int HashFuncDefault(keytype key);
void HashInsert(HashTable *ht,keytype key,valtype value);
int HashFind(HashTable *ht,keytype key,valtype *value);
void HashRemove(HashTable *ht,keytype key);
void Hashdestroy(HashTable *ht);

hash.c

#include "hash.h"
void HashInit(HashTable *ht,HashFunc hash_func)
{
    if(ht == NULL)
    {
        return;
    }
    ht->size = 0;
    ht->func = hash_func;
    size_t i = 0;
    for(;i < HASHMAXSIZE;i++)
    {
        ht->data[i].stat = Empty;
    }
    return;
}
int HashFuncDefault(keytype key)
{
    return (key % HASHMAXSIZE);
}
void HashInsert(HashTable *ht,keytype key,valtype value)
{
    if(ht == NULL)
    {
        return;
    }
    //判斷哈希表是否可以插入

    if((ht->size) >= (0.8 * HASHMAXSIZE))
    {
        return;//滿了
    }
    size_t offset = HashFuncDefault(key);
    while(1)
    {
        if(ht->data[offset].stat != Valid)
        {
            ht->data[offset].stat = Valid;
            ht->data[offset].key = key;
            ht->data[offset].value = value;
            ++ht->size;
            return;
        }
        else if(ht->data[offset].stat == Valid && ht->data[offset].key == key)
        {
            return;
        }
        else
        {
            ++offset;
            if(offset >= HASHMAXSIZE)
            {
                offset = 0;
            }
        }
    }
}
int HashFind(HashTable *ht,keytype key,valtype *value)
{
    if(ht == NULL)
    {
        return 0;
    }
    int offset = HashFuncDefault(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;
            if(offset >= HASHMAXSIZE)
            {
                offset = 0;
            }

        }
    }
}
void HashRemove(HashTable *ht,keytype key)
{
    if(ht == NULL)
    {
        return;
    }
    valtype value;
    int offset = HashFuncDefault(key);
    int ret = HashFind(ht,key,&value);
    if(ret == 0)
    {
        return;
    }
    else if(ret == 1)
    {
        ht->data[offset].stat = Removed;
        --ht->size;
    }
    //else
    //{
    //    ++offset;
    //    if(offset >= HASHMAXSIZE)
    //    {
    //        offset = 0;
    //    }
    //}
}
void Hashdestroy(HashTable *ht)
{
    if(ht == NULL)
    {
        return;
    }
    ht->size = 0;
    size_t i = 0;
    for(;i < HASHMAXSIZE;i++)
    {
        ht->data[i].stat = Empty;
    }
    return;
}

/////////
//test
/////////
#define HEADER printf("\n==========%s==========\n",__FUNCTION__);
void Hashprint(HashTable *ht)
{
    if(ht == 0)
    {
        return;
    }
    size_t i = 0;
    for(;i < HASHMAXSIZE;i++)
    {
        if(ht->data[i].stat != Valid)
        {
            continue;
        }
        printf("%d:%d\n",ht->data[i].key,ht->data[i].value);
    }
    printf("\n");
}
void testinsert()
{
    HEADER;
    HashTable hash;
    HashInit(&hash,HashFuncDefault);
    HashInsert(&hash,1,1);
    HashInsert(&hash,2,2);
    HashInsert(&hash,2,10);
    HashInsert(&hash,11,11);
    HashInsert(&hash,12,12);
    Hashprint(&hash);
}
void testfind()
{
    HEADER;
    HashTable hash;
    HashInit(&hash,HashFuncDefault);
    HashInsert(&hash,1,1);
    HashInsert(&hash,2,2);
    HashInsert(&hash,2,10);
    HashInsert(&hash,11,11);
    HashInsert(&hash,12,12);
    Hashprint(&hash);
    valtype value;
    int ret = HashFind(&hash,2,&value);
    printf("查找key爲2的元素\n");
    printf("excpted ret is 1,actul is %d\n",ret);
    printf("excpted value is 2,actul is %d\n",value);

}
void testremove()
{
    HEADER;
    HashTable hash;
    HashInit(&hash,HashFuncDefault);
    HashInsert(&hash,1,1);
    HashInsert(&hash,2,2);
    HashInsert(&hash,2,10);
    HashInsert(&hash,11,11);
    HashInsert(&hash,12,12);
    HashInsert(&hash,1002,1002);
    Hashprint(&hash);
    valtype value;
    printf("刪除key爲2的元素\n");
    HashRemove(&hash,2);
    int ret = HashFind(&hash,1002,&value);
    printf("查找key爲1002的元素\n");
    printf("excpted ret is 1,actul is %d\n",ret);
    printf("excpted value is 1002,actul is %d\n",value);
}
int main()
{
    testinsert();
    testfind();
    testremove();
    return 0;
}

下面就是測試結果
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章