前言
对c简介的语法一直念念不忘;当然它还是redis、pgsql、Linux的实现语言,当然我没看过任何一个的源码;还有仍记得大学时和小美一起讨论c语言,她那渐渐升起红晕的脸....
用了一段时间之后感觉c类库真的不太多,也可能找错了方向。
简单介绍
用数组加链表的方式实现了一个简单的hashmap,没有实现缩容的部分。
除了静态方法均已mymap开头,这样命名是怕找打了更好的实现和别人的方法名起冲突。
当map中存在的元素超出MAX_CAPACITY后,或者map的数组长度超出MAX_ARR_LEN就不在扩容。刷一般的算法基本够用了。
由于个人能力的问题,实现方式肯定会存在不合理的地方,存取的效率可能也比较低下,希望您能指出。
代码
my_map.h
#pragma once
#define MAX_CAPACITY 256 // pow of 2
#define MAX_ARR_LEN 32
#define MAX_LIST_LEN 8 //
#define INIT_ARR_LEN 8
#define LOAD_FACTOR 0.75
typedef struct MapNodeStruct
{
int list_len;
void *key;
void *value;
struct MapNodeStruct *next;
} MapNodeStruct, *MapNode;
// arr + list
typedef struct MapStruct
{
//容量
int capacity;
//数组大小
int arr_len;
//compare 0 eq !0 ne
int (*compare)(void *key, void *search);
MapNode node_arr;
//如需要根据特定的条件在map中查找数据
int (*hashcode)(void *key);
} MapStruct, *Map ;
typedef void *MyMap;
static int mymap_hash_code(void *key);
static int mymap_get_index(Map mapp, void *key);
static MapNode mymap_delete_list(MapNode head , MapNode be_del);
// 对应mymap_free_map
static MapNode mymap_free_list(MapNode head);
// 对应mymap_free_atomic
static MapNode mymap_free_list_atomic(MapNode head);
static MapNode mymap_resize(Map mapp);
static void mymap_insert_list(MapNode header , MapNode be_insert);
//初始化方法,hashcode为内存地址,
MyMap mymap_init(int compare(void *key , void *search));
MyMap mymap_init_hash(int hashcode(void *key) , int compare(void *key , void *search));
// 只释放map本身,map对应的key 和 value不释放
MyMap mymap_free(MyMap map);
// 释放map本身,释放map对应的key 和 value
MyMap mymap_free_atomic(MyMap map);
void *mymap_put(MyMap , void *key , void *value);
void *mymap_get(MyMap , void *key);
void *mymap_delete(MyMap , void *key);
int mymap_size(MyMap);
//callback 0 continue , 1 break
void mymap_foreach(MyMap , int callback(void *key, void *value));
my_map.c
#include "my_map.h"
#include <stdlib.h>
static int mymap_hash_code(void *key)
{
int h = *(int*)key;
h ^= (h >> 20) ^ (h >> 12);
return h ^ (h >> 7) ^ (h >> 4);
}
static int mymap_get_index(Map map, void *key)
{
int hashcode = map->hashcode(key);
//int index = hashcode ^ (map->arr_len - 1);
int index = hashcode & (map->arr_len - 1);
return index;
}
/**
* @brief compare 为0时相等
*
* @param compare
* @return MyMap
*/
MyMap mymap_init(int compare(void *key , void *search))
{
Map map = calloc(1 , sizeof(struct MapStruct));
if(!map)
{
return NULL;
}
map->compare = compare;
map->arr_len = INIT_ARR_LEN;
map->node_arr = calloc(INIT_ARR_LEN , sizeof(struct MapNodeStruct));
if(!map->node_arr)
{
return NULL;
}
map->hashcode = mymap_hash_code;
return map;
}
MyMap mymap_init_hash(int hashcode(void *key) , int compare(void *key , void *search))
{
if(hashcode == NULL)
return NULL;
Map map = mymap_init(compare);
if(map == NULL)
return NULL;
map->hashcode = hashcode;
return map;
}
void *mymap_put(MyMap myMap, void *key , void *value)
{
if(key && myMap)
{
Map map = myMap;
//pre 最后一个节点,不为 NULL
MapNode headp = NULL , currp = NULL , pre = NULL;
//int list_len = 0;
int index = mymap_get_index(map, key);
if((headp = (map->node_arr + index)) && headp->key)
{
currp = headp;
while(currp)
{
if(key == currp->key || !map->compare(key , currp->key))
{
void *old_value = currp->value;
currp->value = value;
return old_value;
}
pre = currp;
currp = currp->next;
//++ list_len;
}
pre->next = calloc(1 , sizeof(struct MapNodeStruct));
if(!pre->next)
return (void*)-1;
pre->next->key = key;
pre->next->value = value;
++ headp->list_len;
++ map->capacity;
if (headp->list_len >= MAX_LIST_LEN)
{
//
mymap_resize(myMap);
}
}
else
{
headp->key = key;
headp->value = value;
headp->list_len = 1;
++ map->capacity;
}
if(map->arr_len * LOAD_FACTOR < map->capacity)
mymap_resize(myMap);
}
return NULL;
}
void *mymap_get(MyMap myMap, void *key)
{
if(key && myMap)
{
Map map = myMap;
int index = mymap_get_index(map, key);
MapNode node = NULL;
if(node = (map->node_arr + index))
{
while(node && node->key)
{
if(key == node->key || !map->compare(key , node->key))
{
return node->value;
}
node = node->next;
}
}
}
return NULL;
}
void *mymap_delete(MyMap myMap, void *key)
{
if(key && myMap)
{
Map map = myMap;
MapNode node = NULL , be_del = NULL;
void *old_value;
int index = mymap_get_index(map, key);
if(node = (map->node_arr + index))
{
be_del = node;
while(be_del && be_del->key)
{
if(key == be_del->key || !map->compare(key , be_del->key))
{
node = mymap_delete_list(node , be_del);
-- map->capacity;
old_value = be_del->value;
//删除后将新链表挂在数组上
// 结构体直接赋�? �? 出现表达式必须是可修改的左�?
//(map->node_arr + index) = node;
if(node)
{
(map->node_arr + index)->key = node->key;
(map->node_arr + index)->value = node->value;
(map->node_arr + index)->next = node->next;
}
else
{
(map->node_arr + index)->key = NULL;
(map->node_arr + index)->value = NULL;
(map->node_arr + index)->next = NULL;
}
return old_value;
}
be_del = be_del->next;
}
}
}
return NULL;
}
static MapNode mymap_delete_list(MapNode head , MapNode be_del)
{
MapNode pre = head , curr = head;
while(curr != be_del)
{
pre = curr;
curr = curr->next;
}
//删除节点是头节点
if(pre == curr)
{
head = curr->next;
if(head)
head->list_len = head->list_len - 1;
}
else
{
pre->next = be_del->next;
head->list_len = head->list_len - 1;
free(be_del);
}
return head;
}
static void mymap_insert_list(MapNode header , MapNode be_insert)
{
while(header && header->next)
{
header = header->next;
}
header->next = be_insert;
}
static MapNode mymap_free_list(MapNode head)
{
MapNode temp = NULL;
//头结点属于node_arr 数组的一部分,不在这里释放
while(head && (temp = head->next))
{
head = temp->next;
free(temp);
}
return NULL;
}
static MapNode mymap_free_list_atomic(MapNode head)
{
MapNode temp = NULL;
//头结点属于node_arr 数组的一部分,不在这里释放
while(head && (temp = head->next))
{
if(temp->key != temp->value)
{
free(temp->key);
free(temp->value);
}
else
{
free(temp->key);
}
head = temp->next;
free(temp);
}
return NULL;
}
MyMap mymap_free(MyMap myMap)
{
if(myMap)
{
Map map = myMap;
for(int i = 0; i < map->arr_len ; ++ i)
{
mymap_free_list(map->node_arr + i);
}
free(map->node_arr);
map->node_arr = NULL;
//arr
free(map);
map = NULL;
}
return NULL;
}
static MapNode mymap_resize(Map map)
{
if(map->capacity >= MAX_CAPACITY || map->arr_len == MAX_ARR_LEN)
return map->node_arr;
MapNode newnodep = calloc(map->arr_len << 1, sizeof(struct MapNodeStruct));
if(!newnodep)
return map->node_arr;
int new_index = 0 , new_list_len = 0 , old_list_len = 0;
MapNode temp_nodep = NULL , new_headp = NULL, old_headp = NULL;
for(int i = 0; i < map->arr_len; ++ i)
{
temp_nodep = map->node_arr + i;
//数组上的节点应该不为空,通过key判断该位置有没有元素
while(temp_nodep && temp_nodep->key)
{
//hashcode 1101 & 0111 = 0101
// 1101 & 1111 = 1101
// 1101 & 1000 = 1000
// 1000 & 0111 = 0000
// 1000 & 1000 = 1000
// 条件成立加入new_headp ,不成立加入old_headp
// new_headp = old_headp + arr_len
if(map->arr_len & mymap_hash_code(temp_nodep->key))
{
if(!new_headp)
{
new_headp = (newnodep + i + map->arr_len);
new_headp->key = temp_nodep->key;
new_headp->value = temp_nodep->value;
//new_headp ->next = temp_nodep->next;
new_headp->list_len = 0;
}
else
{
mymap_insert_list(new_headp , temp_nodep);
}
++ new_headp->list_len;
}
else
{
if(!old_headp)
{
old_headp = (newnodep + i);
old_headp->key = temp_nodep->key;
old_headp->value = temp_nodep->value;
//old_headp->next = temp_nodep->next;
old_headp->list_len = 0;
}
else
{
mymap_insert_list(old_headp , temp_nodep);
}
++ old_headp->list_len;
}
temp_nodep = temp_nodep->next;
}
new_headp = NULL, old_headp = NULL;
}
free(map->node_arr);
map->node_arr = newnodep;
map->arr_len = map->arr_len << 1;
return newnodep;
}
MyMap mymap_free_atomic(MyMap myMap)
{
if(myMap)
{
Map map = myMap;
for(int i = 0; i < map->arr_len ; ++ i)
{
mymap_free_list_atomic(map->node_arr + i);
}
free(map->node_arr);
map->node_arr = NULL;
//arr
free(map);
map = NULL;
}
return NULL;
}
int mymap_size(MyMap myMap)
{
if(myMap)
{
int size = 0;
Map map = myMap;
return map->capacity;
/*
for(int i = 0; i < map->arr_len ; ++ i)
{
size += (map->node_arr + i)->list_len;
}
return size;
*/
}
return 0;
}
void mymap_foreach(MyMap myMap , int callback(void *key, void *value))
{
if(myMap)
{
Map map = myMap;
MapNode node = NULL , temp = NULL;
for(int i = 0; i < map->arr_len ; ++ i)
{
node = (map->node_arr + i);
//printf("\n%d,%d\n" , i, node->list_len);
while(node && node->key)
{
temp = node->next;
if(callback(node->key , node->value))
{
break;
}
node = temp;
}
}
}
}
基本测试
#include <stdio.h>
#include <string.h>
#include "my_map.h"
#include "my_map.c"
typedef struct student_struct
{
int score;
char *name;
char *grade;
} strudent;
/*
void test_map_node()
{
my_nodep nodep0 = calloc(1 , sizeof(struct my_map_node));
my_nodep nodep1 = calloc(1 , sizeof(struct my_map_node));
my_nodep nodep2 = calloc(1 , sizeof(struct my_map_node));
my_nodep nodep3 = calloc(1 , sizeof(struct my_map_node));
nodep0->value = (void*)0;
//nodep0->next = nodep1;
(nodep1)->value = (void*)1;
(nodep1)->next = nodep2;
(nodep2)->value = (void*)2;
(nodep2)->next = nodep3;
(nodep3)->value = (void*)3;
my_nodep temp = mymap_delete_list(nodep0 , nodep0);
printf("%d\n" , temp->value);
}
*/
int compare(void *key , void *search)
{
int i = *(int *)key;
int j = *(int *)search;
return i-j;
}
int callback(void *key , void *value)
{
//printf("key = %d,value = %d\n" , key , value);
return 0;
}
int compare_struct(void *key , void *search)
{
strudent *keyp = key , *searchp = search;
return strcmp(keyp->name , searchp->name);
}
int compare_struct2(void *key , void *search)
{
char *keyp = key ;
char *searchp = search;
return strcmp(keyp , searchp);
}
int hashcode(void *key)
{
char *keyp = key;
return atoi(keyp) * 5 + 1;
}
void test_map_basic_struct()
{
strudent *studs = calloc(1 , sizeof(strudent));
studs->score = 99;
studs->name = "测试test";
MyMap mymap = mymap_init(compare_struct);
mymap_put(mymap , studs , studs );
void *value = mymap_get(mymap , studs);
printf("%s\n" , ((strudent*)value)->name);
value = mymap_get(mymap , studs);
printf("%s\n" , ((strudent*)value)->name);
value = mymap_delete(mymap ,studs);
printf("%s\n" , ((strudent*)value)->name);
value = mymap_get(mymap , studs);
printf("%s\n" , value ? ((strudent*)value)->name : "null");
//free(studs);
mymap_free(mymap);
mymap = mymap_init_hash(hashcode , compare_struct2);
char *name1 = calloc(16, sizeof(char));
memcpy(name1 , "hellomap" , 9);
char *name2 = calloc(16, sizeof(char));
memcpy(name2 , "hellomap" , 9);
mymap_put(mymap , name1 , studs);
value = mymap_get(mymap , name2);
printf("%s\n" , value ? ((strudent*)value)->name : "null");
mymap_free(mymap);
free(studs);
}
void test_free(void)
{
int *int_arr = malloc(10 * sizeof(int));
free(int_arr + 9);
free(int_arr + 8);
free(int_arr);
}
void test_map_basic()
{
MyMap mymap = mymap_init(compare);
mymap_put(mymap , 1 , 1);
mymap_put(mymap , 2 , 8);
mymap_put(mymap , 1 , 3);
mymap_put(mymap , 1 , 4);
void *value = mymap_get(mymap , 1);
printf("%d\n" , (int)value);
value = mymap_get(mymap , 2);
printf("%d\n" , (int)value);
value = mymap_delete(mymap , 2);
printf("%d\n" , (int)value);
value = mymap_get(mymap , 2);
printf("%d\n" , (int)value);
}
void test_map_batch()
{
MyMap mymap = mymap_init(compare);
printf("--------------put---------------\n");
for(int i = 1 ; i <= 512 ; ++ i)
{
mymap_put(mymap , i , i * 2);
}
printf("\n--------------get---------------\n");
void *value = NULL;
for(int i = 1 ; i <= 512 ; ++ i)
{
value = mymap_get(mymap , i);
if(value)
{
printf("%d\t" , value);
}
}
printf("\n--------------foreach---------------\n");
mymap_foreach(mymap , callback);
printf("\n--------------size---------------\n");
int size = mymap_size(mymap);
printf("%d\t" , size);
printf("\n--------------del---------------\n");
for(int i = 1 ; i <= 10 ; ++ i)
{
value = mymap_delete(mymap , i);
if(i << 1 != (int)value)
{
printf("%d\t" , (int)value);
}
}
printf("\n--------------get---------------\n");
for(int i = 1 ; i <= 10 ; ++ i)
{
value = mymap_get(mymap , i);
if(value)
printf("%d\t" , (int)value);
}
printf("\n--------------end---------------\n");
mymap_free(mymap);
}
int main(int argc , char *argv[])
{
test_map_basic_struct();
//test_free();
return EXIT_SUCCESS;
}
来个测试截图

求一棵二叉树的宽度
/**
如何完成二叉树的宽度优先遍历(常见题目:求一棵二叉树的宽度)
*/
#include "../../util/my_util.h"
#include "../../util/my_util.c"
typedef struct NodeStruct
{
int value;
struct NodeStruct *left;
struct NodeStruct *right;
}
NodeStruct, *Node;
typedef struct NodeStruct *Node;
int compare(void *key , void *search)
{
return ((Node)key)->value - ((Node)search)->value;
}
int get_max_width(Node head)
{
if(!head)
return 0;
int max_width = 0;
int cur_width = 0;
int cur_level = 0;
MyMap level_map = mymap_init(compare);
mymap_put(level_map , head, 1);
MyList queue = mylist_init();
mylist_insert_head(queue , head);
Node node = NULL;
Node left = NULL;
Node right = NULL;
int curlevel = 0;
while(mylist_size(queue))
{
node = mylist_poll_tail(queue);
left = node->left;
right = node->right;
curlevel = mymap_get(level_map , node);
if(left)
{
mymap_put(level_map , left , curlevel + 1);
mylist_insert_head(queue ,left);
}
if(right)
{
mymap_put(level_map , right , curlevel + 1);
mylist_insert_head(queue ,right);
}
if(curlevel > cur_level)
{
/*
此处为0 , 感觉不对
如根节点或者每一层的最左边的节点进入,宽度需要被设置成1
*/
cur_width = 1;
cur_level = curlevel;
max_width = MAX(max_width,cur_width);
}
else
{
++ cur_width;
}
max_width = MAX(max_width,cur_width);
}
mylist_free(queue);
mymap_free(level_map);
return max_width;
}
int main(void)
{
Node tree = calloc(8 , sizeof(struct NodeStruct));
tree->left = tree + 1;
tree->right = tree + 2;
(tree + 1)->left = tree + 3;
(tree + 1)->right = tree + 4;
(tree + 2)->left = tree + 5;
(tree + 2)->right = tree + 6;
(tree + 3)->left = tree + 7;
tree->value = 20;
(tree + 1)->value = 10;
(tree + 2)->value = 30;
(tree + 3)->value = 5;
(tree + 4)->value = 15;
(tree + 5)->value = 25;
(tree + 6)->value = 40;
(tree + 7)->value = 1;
printf("%d\n" , get_max_width(tree));
free(tree);
return EXIT_SUCCESS;
}

修改记录
2024.10.13 修改结构体和指针命名,修改求二叉树宽度bug。
题外话
由于不会编写makefile,用include的方式引入相关的方法,也算的上一个不被推荐的方式。

本文介绍了一位开发者使用C语言自定义的哈希表实现,包括数组+链表的数据结构,未实现缩容功能。作者分享了关键代码片段,并探讨了其优缺点,期待读者提出改进建议。

510

被折叠的 条评论
为什么被折叠?



