闭散列(即开放地址法):当发生哈希冲突时,如果该哈希表还没有被填满,那么就把该元素放到哈希表的下一个空闲的位置。
代码实现思路:
- 哈希表结构的封装
- 首先我们能够知道哈希表是否冲突。我们使用状态标记来查看哈希表是否冲突。那么就有三种状态:当前位置空着,当前位置存在元素,当前元素已经被删除(这个一会会在删除的时候讲到)
- 接下来我们要对哈希表每一个存储位置空间去进行描述;哈希表每一个存储位置都有哪些元素:key、value、状态标记;
- 最后哈希表的构造。整个哈希表是由一个个存储位置构成的,包括哈希表当前有效的元素个数以及存储空间。
- 哈希表功能实现
- 测试
哈希表结构
//定义一个状态
enum state {
EMPTY,
EXIST,
DELETE
};
//定义哈希表中每一个存储位置
typedef struct HashElem {
int key;
int value;
state _state;
}hashelem;
//定义整个哈希表
typedef struct HashTable{
hashelem* arr;
int size;//哈希表中有效元素个数
}hashtable;
哈希表功能实现
- 初始化
void hash_table_init(hashtable* hash)
{
int i = 0;
if (hash->arr == NULL) {
return;
}
hash->arr = (hashelem*)malloc(sizeof(hashelem) * CAP);
if (hash->arr == NULL) {
return;
}
hash->size = 0;
for (i = 0; i < CAP; i++) {
hash->arr[i]._state = EMPTY;
}
return;
}
- 插入
//哈希函数实现
size_t hash_build_func(int data)
{
return data % CAP;
}
bool hash_insert(hashtable* hash, int data)
{
//计算哈希地址
size_t hashaddr = hash_build_func(data);
if (hash == NULL) {
return false;
}
//这个位置是否发生哈希冲突
while (hash->arr[hashaddr]._state != EMPTY) {
//表示冲突,两种情况就是重复元素/往后找空位置
if (hash->arr[hashaddr]._state == EXIST &&
hash->arr[hashaddr].value == data) {
return false;
}
//往后找空位置
++hashaddr;
if (hashaddr == CAP) {
hashaddr = 0;
}
}
//在空位置完成插入
hash->arr[hashaddr].value = data;
hash->arr[hashaddr]._state = EXIST;
++hash->size;
return true;
}
- 查找
int hash_find(hashtable* hash, int data)
{
//首先计算哈希地址
size_t hashaddr = hash_build_func(data);
while (hash->arr[hashaddr]._state != EMPTY) {
if (hash->arr[hashaddr]._state == EXIST && hash->arr[hashaddr].value == data) {
return hashaddr;
}
++hashaddr;
if (hashaddr == CAP) {
hashaddr = 0;
}
}
return -1;
}
- 删除
bool hash_erase(hashtable* hash, int data)
{
//查找要删除的元素
int hashaddr = hash_find(hash, data);
if (hashaddr == -1) {
return false;
}
hash->arr[hashaddr]._state = DELETE;
--hash->size;
return true;
}
测试
int main()
{
hashtable hash;
hash_table_init(&hash);
int hashaddr = 0;
hash_insert(&hash, 1);
hash_insert(&hash, 2);
hash_insert(&hash, 3);
hash_insert(&hash, 4);
hashaddr = hash_find(&hash, 3);
if (hashaddr == -1) {
printf("没找到!!!\n");
return -1;
}
printf("要找的元素在%d\n", hashaddr);
hash_erase(&hash, 3);
free(hash.arr);
system("pause");
return 0;
}
解答
- 为什么状态有DELETE这个标记呢?
如果我们状态标记不使用DELETE,而是简单的删除元素之后将状态标记改为EMPTY。那么我们在查找的时候是会出错的。
例子:我们在这删除key = 0的value值29,当我们删除之后我们想要去查找key = 1的value值39,这个时候找不到这个值了,所以我们要加上状态标记DELETE。