首先我们来了解一下什么叫做哈希表
在顺序搜序偶以及二叉搜索树种,元素存储位置和元素个关键码之间没有对应关系,因此在查找一个元素时,必须要经过关键码的多次比较。
而我们理想的搜索方法:可以不经过任何比较,一次直接可以从表中得到想要的元素
当向一个结构中
*插入元素时:根据待插入元素的关键码,以此桉树计算出钙元素的存储位置,并按该位置存放
*搜索元素时,根据元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素,比较,若关键码相等则说明搜索成功
这种方法就叫做哈希方法,其中用到的函数就是哈希函数,构建出来的结构称为哈希表
哈希冲突
**哈希冲突是怎么出现的呢?
我们来举个例子
对于两个数据元素的关键字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;
}
下面就是测试结果