首先我們來了解一下什麼叫做哈希表
在順序搜序偶以及二叉搜索樹種,元素存儲位置和元素個關鍵碼之間沒有對應關係,因此在查找一個元素時,必須要經過關鍵碼的多次比較。
而我們理想的搜索方法:可以不經過任何比較,一次直接可以從表中得到想要的元素
當向一個結構中
*插入元素時:根據待插入元素的關鍵碼,以此桉樹計算出鈣元素的存儲位置,並按該位置存放
*搜索元素時,根據元素的關鍵碼進行同樣的計算,把求得的函數值當做元素的存儲位置,在結構中按此位置取元素,比較,若關鍵碼相等則說明搜索成功
這種方法就叫做哈希方法,其中用到的函數就是哈希函數,構建出來的結構稱爲哈希表
哈希衝突
**哈希衝突是怎麼出現的呢?
我們來舉個例子
對於兩個數據元素的關鍵字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;
}
下面就是測試結果