哈希表之闭散列

闭散列(即开放地址法):当发生哈希冲突时,如果该哈希表还没有被填满,那么就把该元素放到哈希表的下一个空闲的位置。
代码实现思路:

  • 哈希表结构的封装
    • 首先我们能够知道哈希表是否冲突。我们使用状态标记来查看哈希表是否冲突。那么就有三种状态:当前位置空着,当前位置存在元素,当前元素已经被删除(这个一会会在删除的时候讲到)
    • 接下来我们要对哈希表每一个存储位置空间去进行描述;哈希表每一个存储位置都有哪些元素: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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值