C语言hashmap实现,不做线程控制
map.h
#ifndef _MAP_H
#define _MAP_H
/**
*
* 文件说明:
* 纯C实现hashmap,由于限制,map中的key采用char*,如果key为其他类型的请先转换成char*
* 文件创建时间:
* 2020-09-16 13:58
* hashmap实现原理描述:
* hashmap实现采用数组加链表,首先将key生成一个int类型的hashcode值,然后根据hashcode值进行数组的长度取余数,
* 以余数作为存储值的索引,如果产生了hash碰撞,那么将在该索引数组上的链表进行值存储
*/
#include "array_list.h"
#ifdef _MSC_VER/* only support win32 and greater. */
#define MS_WINDOWS
#endif
#ifdef __cplusplus
extern "C" {
#endif
//定义bool类型
#ifndef bool
#define bool int
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
/*define NULL */
#ifndef NULL
#define NULL 0
#endif
//定义key-value键值对
typedef struct _map_item{
char *p_key;//存放key
void *p_val;//存放val
}map_item;
//定义map节点
typedef struct _map_node{
map_item *p_cur_item;//当前节点的项
struct _map_node *p_next_item;//下一个节点项
}map_node;
//定义map
typedef struct _map{
map_node *p_nodes;//节点列表
unsigned int node_size;//表示数组的大小,并不是元素的个数
unsigned int length;//元素的个数
}map;
/**
* 函数说明:
* map初始化,初始化500个数组进行存放,如果500个数组全部使用完成,那么看链表的长度是否达到阈值进行动态扩容
* 返回值:
* 返回map指针
*/
map* map_init();
/**
* 函数说明:
* 向map中放一个key、val项
* 参数:
* p_map:map指针
* p_key:key,不能为空,并且不能重复,如果重复那么将会覆盖
* p_val:值
*/
void map_put(map* p_map,char *p_key,void *p_val);
/**
* 函数说明:
* 获取元素
* 参数:
* p_map:map指针
* p_key:key
* 返回值:
* 返回数据指针
*/
void* map_get(map* p_map,char *p_key);
/**
* 函数说明:
* 获取所有的key列表
* 参数:
* p_map:map指针
* 返回值:
* 返回map中的所有key列表
*/
Array_List* map_keys(map* p_map);
/**
* 函数说明:
* map释放,调用该函数之前,请将存储的数据项的数据手动释放
* 参数:
* p_map:map指针
*/
void map_free(map* p_map);
/**
* map测试
*/
void map_test();
#ifdef __cplusplus
}
#endif
#endif
map.c
#include "map.h"
#include <malloc.h>
#include <memory.h>
#include <time.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* 计算hashcode
*/
static unsigned int map_hash_code(char* key)
{
unsigned int h = 0;
int index = 0;
if (key == NULL)
{
return 0;
}
for (index = 0;index < strlen(key);index++)
{
h = 31 * h + key[index];
}
return h;
}
/**
* 函数说明:
* map初始化,初始化500个数组进行存放,如果500个数组全部使用完成,那么看链表的长度是否达到阈值进行动态扩容
* 返回值:
* 返回map指针
*/
map* map_init()
{
map *p_map;
unsigned int ini_size = 500;
p_map = (map*)malloc(sizeof(map));
if(p_map == NULL) return NULL;
p_map->node_size = ini_size;
p_map->p_nodes = (map_node*)malloc(sizeof(map_node) * ini_size);
p_map->length = 0;
memset(p_map->p_nodes,0,(sizeof(map_node) * ini_size));
return p_map;
}
/**
* 函数说明:
* 向map中放一个key、val项
* 参数:
* p_map:map指针
* p_key:key,不能为空,并且不能重复,如果重复那么将会覆盖
* p_val:值
*/
void map_put(map *p_map,char *p_key,void *p_val)
{
//取指针指向的第一个字节的数据的二进制的值计算hashcode,然后进行取余运算
map_item *p_map_item = NULL;
map_node* p_map_node = NULL;
unsigned int index = 0;
if (p_map == NULL || p_key == NULL)
{
return;
}
index = map_hash_code(p_key);
//进行取余
index = index % p_map->node_size;
//余数作为map数组的索引,判断该索引上面是否存在,如果存在那么存到该索引的链表上
if (p_map->p_nodes[index].p_cur_item == NULL)
{
//直接添加
p_map_item = (map_item*)malloc(sizeof(map_item));
p_map_item->p_key = p_key;
p_map_item->p_val = p_val;
p_map->p_nodes[index].p_cur_item = p_map_item;
p_map->length++;
return;
}
//如果当前索引有值,那么在链表上追加
p_map_node = &(p_map->p_nodes[index]);
while(p_map_node->p_next_item != NULL)
{
//判断key是否重复,如果重复那么直接覆盖val
if (strcmp(p_map_node->p_cur_item->p_key,p_key) == 0)
{
p_map_node->p_cur_item->p_val = p_val;
return;
}
p_map_node = p_map_node->p_next_item;
}
//创建节点
p_map_node->p_next_item = (map_node*)malloc(sizeof(map_node));
memset(p_map_node->p_next_item,0,sizeof(map_node));
p_map_item = (map_item*)malloc(sizeof(map_item));
p_map_item->p_key = p_key;
p_map_item->p_val = p_val;
p_map_node->p_cur_item = p_map_item;
p_map->length++;
}
/**
* 函数说明:
* 获取元素
* 参数:
* p_map:map指针
* p_key:key
* 返回值:
* 返回数据指针
*/
void* map_get(map* p_map,char *p_key)
{
map_item *p_map_item = NULL;
map_node* p_map_node = NULL;
int index = 0;
if (p_map == NULL || p_key == NULL)
{
return NULL;
}
//index = (int)p_key;
index = map_hash_code(p_key);
//计算索引
index = index % p_map->node_size;
p_map_node = &(p_map->p_nodes[index]);
while(p_map_node != NULL && p_map_node->p_cur_item != NULL){
if (strcmp(p_map_node->p_cur_item->p_key,p_key) == 0)
{
return p_map_node->p_cur_item->p_val;
}
//继续查找
p_map_node = p_map_node->p_next_item;
}
}
/**
* 函数说明:
* 获取所有的key列表
* 参数:
* p_map:map指针
* 返回值:
* 返回map中的所有key列表
*/
Array_List* map_keys(map* p_map)
{
int index = 0;
void *p_key = NULL;
Array_List *p_array_keys = NULL;
map_node *p_map_node = NULL;
p_array_keys = array_list_init();
//开始遍历
for (index = 0;index < p_map->node_size;index++)
{
if (p_map->p_nodes[index].p_cur_item != NULL)
{
p_map_node = &(p_map->p_nodes[index]);
while(p_map_node != NULL)
{
p_map_node->p_cur_item->p_key;
array_list_insert(p_array_keys,p_key,-1);
if (p_map_node->p_next_item == NULL)
{
break;
}
p_map_node = p_map_node->p_next_item;
}
}
}
return p_array_keys;
}
/**
* 函数说明:
* map释放
*/
void map_free(map* p_map)
{
int index = 0;
map_node *p_map_node = NULL;
map_node *p_temp_map_node = NULL;
if (p_map != NULL)
{
//释放链表节点
for (index = 0;index < p_map->node_size;index++)
{
p_map_node = &(p_map->p_nodes[index]);
while(p_map_node != NULL && p_map_node->p_next_item != NULL)
{
p_temp_map_node = p_map_node->p_next_item;
p_map_node = p_temp_map_node->p_next_item;
free(p_temp_map_node->p_cur_item);
free(p_temp_map_node);
}
}
//释放数组节点
free(p_map->p_nodes);
free(p_map);
}
}
/**
* map测试
*/
void map_test()
{
map* p_map = NULL;
Array_List *p_list = NULL;
char* find_key = NULL;
char* key = NULL;
char* val = NULL;
char* tmp_val;
int index = 0;
clock_t start, finish;
double total_time;
p_map = map_init();
start = clock();
//存储100万个元素
for (index = 0; index < 1000000;index++)
{
key = (char*)malloc(100);
val = (char*)malloc(100);
sprintf(key,"key%d",index);
sprintf(val,"val%d",index);
if (index == 234232)
{
find_key = key;
}
map_put(p_map,key,val);
}
finish = clock();
total_time = (double)(finish - start);
printf("\n插入100万个元素所需时间:%0.3f毫秒 \n", total_time);
//查找某个元素,并且计算时间
start = clock();
tmp_val = (char*)map_get(p_map,find_key);
finish = clock();
total_time = (double)(finish - start);
printf("\n查找元素%s,元素值:%s,所需时间:%0.3f毫秒 \n",find_key, tmp_val,total_time);
//遍历key
start = clock();
p_list = map_keys(p_map);
finish = clock();
total_time = (double)(finish - start);
printf("\n遍历key所需时间:%0.3f毫秒 \n", total_time);
//释放资源
for (index = 0; index < p_list->length;index++)
{
key = (char*)array_list_getAt(p_list,index);
if (key != NULL)
{
val = (char*)map_get(p_map,key);
if(val != NULL){
free(key);
free(val);
}
}
}
map_free(p_map);
}
#ifdef __cplusplus
}
#endif
测试结果如下: