C语言实现散列(哈希)表数据结构
散列表数据结构想必大家都比较熟悉,理想状态下,搜索的时间等于O(1)。对于那些在海量数据中快速查找的场景下应用甚多。
1.本散列表实现的特点
a.结构特点
本散列表实现简单,代码量较少,只有两个头文件:
1.【hash_table_core.h】:散列表核心操作实现的头文件。
2.【hash_table_user_config.h】:用户配置头文件。
b.散列冲突解决方式
采用常见的拉链法。提供散列表存储数组扩展大小的相关函数来缓解散列冲突带来的影响。
2.本散列数据结构使用方法
例如,创建一个键值对都是【int】型的散列表。
a.散列映射函数:
代码如下(示例):
//自定义散列映射函数(采用简单的直接取值法)
//需参考hash_table_core.h的对应的函数类型:hashmap_func
/***
{void* key}:散列关键字地址
{size_t* key_index}:散列表数组索引位置
{size_t table_len}:散列表数组范围
***/
static int HashMapFunc(void* key, size_t* key_index, size_t table_len)
{
int* tmp = (int*)key;
*key_index = (size_t)(*tmp <0? -1*(*tmp) : *tmp) % table_len;
return 0; //成功
}
b.代码如下(示例):
1.为了适应用户需求,用户需要在【hash_table_user_config.h】头文件中进行配置,例如:
用户配置头文件hash_table_user_config.h中:
//散列映射函数,用户自己实现。
static int HashMapFunc(void* key, size_t* key_index, size_t table_len)
{
int* tmp = (int*)key;
*key_index = (size_t)(*tmp <0? -1*(*tmp) : *tmp) % table_len;
return 0; //成功
}
//对应配置注册
REGISTER_USER_TABLE_SIZE( 100 ) //HASHMAP存储空间大小
REGISTER_USER_CONFLICT_SIZE( 2 ) //散列表存储数组里单节点中最大冲突键值个数阈值
REGISTER_USER_KEY_TYPE( int ) //用户键类型
REGISTER_USER_VALUE_TYPE( int ) //用户值类型
REGISTER_USER_HASH_MAP( HashMapFunc ) //散列映射
2.在需要用到的地方,包含hash_table_core.h头文件,然后调用其中的相关操作函数。
#include <stdio.h>
#include "hash_table_core.h"
int main(int argc, char** argv)
{
//自定义键值对
int key;
int values;
hashmap_t* hm_hdle = NULL;
/**************创建****************/
hm_hdle = HashInit();
if (NULL == hm_hdle) {
return -1;
}
/**************插入****************/
key = 1; //插入的关键字
values = 10; //插入的值
HashInsert(&hm_hdle, &key, &values);
/**************查找****************/
key = 1; //输入的关键字
values = 0;
HashFind(&hm_hdle, &key, &values);
/**************修改**************/
key = 1;
values = 5; //修改的值
HashInsert(&hm_hdle, &key, &values);
/**************删除**************/
//删除指定关键字的数据
key = 1;
HashRemove(&hm_hdle, &key);
/**************销毁**************/
HashDestroy(&hm_hdle);
return 0;
}
5.注意事项:
1.由于只有头文件,所以,散列表的作用域只局限与当前包含该头文件的c/c++文件中,可以在配置头文件【hash_table_user_config.h】中通过宏开关定义多套不同散列表的配置,以便达到一个c/c++文件对应一套不同配置的散列表的使用。
2.如果需要多线程异步操作,则需要用户自己在包含了本散列表相关头文件下的c/c++文件中,封装一层来实现锁或者信号量相关操作,本头文件实现的散列表操作不包含任何操作同步的方式,只实现最基本的散列表的增删改查等等的功能。
3.源码下载
放在了github上:Hash_Table