c语言hash表的实现

旧街凉风 提交于 2020-04-14 17:54:05

【推荐阅读】微服务还能火多久?>>>

1. hash_db.h

 1 #ifndef _HASH_DB_H
 2 #define _HASH_DB_H
 3 
 4 #include "slist.h"
 5 
 6 typedef unsigned int (*hash_func_t) (const void *key); //哈希函数类型,返回值为整数,参数为关键字
 7 struct _hash_db
 8 {
 9     slist_head_t *p_head;   //指向数组首地址
10     unsigned int size;      //数组成员数
11     unsigned int value_len; //一条记录的长度
12     unsigned int key_len;   //关键字的长度
13     hash_func_t pfn_hash;   //哈希函数
14 };
15 typedef struct _hash_db hash_db_t; //指向哈希表对象的指针类型
16 
17 int hash_db_init(hash_db_t *p_hash, //哈希表初始化
18 unsigned int size,
19 unsigned int key_len,
20 unsigned int value_len,
21 hash_func_t pfn_hash);
22 
23 int hash_db_add(hash_db_t *p_hash, const void *key,const void *value); //添加记录
24 int hash_db_del(hash_db_t *p_hash, const void *key); //删除记录
25 int hash_db_search(hash_db_t *p_hash, const void *key, void *value); //查找记录
26 int hash_db_deinit(hash_db_t *p_hash); //解初始化
27 
28 #endif

2. hash_db.c

  1 #include "hash_db.h"
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 /* 寻找结点的上下文,仅内部使用 */
  6 struct _node_find_ctx 
  7 {
  8     const void *key; //查找关键字
  9     unsigned int key_len; //关键字长度
 10     slist_node_t *p_result; //用于存储查找到的结点
 11 };
 12 
 13 /**
 14  * @brief 遍历链表的回调函数,查找指定结点
 15  */
 16 static int __hash_db_node_find (void *p_arg, slist_node_t *p_node)
 17 {
 18     struct _node_find_ctx *p_info = (struct _node_find_ctx *)p_arg; //用户参数为寻找结点的上下文
 19     char *p_mem = (char *)p_node + sizeof(slist_node_t); //关键字存储在结点之后
 20 
 21     if (memcmp(p_mem, p_info->key, p_info->key_len) == 0) 
 22     {
 23         p_info->p_result = p_node;
 24         return -1; //找到该结点,终止遍历
 25     }
 26     return 0;
 27 }
 28 
 29 
 30 /**
 31  * @brief 哈希表初始化
 32  */
 33 int hash_db_init(hash_db_t *p_hash, 
 34                  unsigned int size,
 35                  unsigned int key_len,
 36                  unsigned int value_len,
 37                  hash_func_t pfn_hash)
 38 {
 39     int i;
 40     if ((p_hash == NULL) || (pfn_hash == NULL))
 41     {
 42         return -1;
 43     }
 44     p_hash->p_head = (slist_head_t *)malloc(size * sizeof(slist_head_t));
 45     if (p_hash->p_head == NULL) 
 46     {
 47         return -1;
 48     }
 49     for (i = 0; i < size; i++)
 50     {
 51         slist_init(&p_hash->p_head[i]);
 52     }
 53     p_hash->size = size;
 54     p_hash->key_len = key_len;
 55     p_hash->value_len = value_len;
 56     p_hash->pfn_hash = pfn_hash;
 57     return 0;
 58 }
 59 
 60 int hash_db_add(hash_db_t *p_hash, const void *key, const void *value)
 61 {
 62     int idx = p_hash -> pfn_hash(key); //使用哈希函数通过关键字得到哈希值
 63     /* 分配内存,存储链表结点+关键字+记录 */
 64     char *p_mem = (char *)malloc(sizeof(slist_node_t) + p_hash -> key_len + p_hash -> value_len);
 65     if (p_mem == NULL)
 66     {
 67         return -1;
 68     }
 69     memcpy(p_mem + sizeof(slist_node_t), key, p_hash -> key_len); //存储关键字
 70     memcpy(p_mem + sizeof(slist_node_t) + p_hash->key_len, value, p_hash->value_len); //存储记录
 71     return slist_add_head(&p_hash -> p_head[idx], (slist_node_t *)p_mem); //将结点加入链表
 72 }
 73 
 74 int hash_db_del(hash_db_t *p_hash, const void *key)
 75 {
 76     int idx = p_hash->pfn_hash(key); //得到关键字对应哈希表的索引
 77     struct _node_find_ctx info = {key, p_hash->key_len, NULL}; //设置遍历链表的上下文信息
 78     slist_foreach(&p_hash->p_head[idx], __hash_db_node_find, &info); //遍历,寻找关键字对应的结点
 79     if (info.p_result != NULL) 
 80     {
 81         slist_del(&p_hash->p_head[idx], info.p_result); //从链表中删除该结点
 82         free(info.p_result); //释放结点空间
 83         return 0;
 84     }
 85     return -1;
 86 }
 87 
 88 int hash_db_search(hash_db_t *p_hash, const void *key, void *value)
 89 {
 90     int idx = p_hash->pfn_hash(key); ////得到关键字对应哈希表的索引
 91     struct _node_find_ctx info = {key, p_hash->key_len, NULL}; //设置遍历链表的上下文信息
 92     slist_foreach(&p_hash->p_head[idx], __hash_db_node_find, &info); //遍历,寻找关键字对应的结点
 93 
 94     if (info.p_result != NULL) 
 95     {   //找到对应结点,将存储的记录值拷贝到用户提供的空间中
 96         memcpy(value, (char *)info.p_result+sizeof(slist_node_t)+p_hash->key_len, p_hash->value_len);
 97         return 0;
 98     }
 99     return -1;
100 }
101 
102 int hash_db_deinit(hash_db_t *p_hash)
103 {
104     int i;
105     slist_node_t *p_node;
106     for (i = 0; i < p_hash->size; i++) 
107     { //释放哈希表中各个表项中存储的所有结点
108 
109         while (slist_begin_get(&p_hash->p_head[i]) != slist_end_get(&p_hash->p_head[i])) 
110         {
111             p_node = slist_begin_get(&p_hash->p_head[i]);
112             slist_del(&p_hash->p_head[i], p_node); //释放第一个结点
113             free(p_node);
114         }
115     }
116     free(p_hash->p_head); //释放链表头结点数组空间
117     return 0;
118 }

3. demo

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "hash_db.h"
 4 
 5 typedef struct _student
 6 {
 7     char name[10];
 8     char sex;
 9     float height, weight;
10 } student_t;
11 
12 int db_id_to_idx(unsigned char id[6]) //通过ID得到数组索引
13 {
14     int i;
15     int sum = 0;
16     for (i = 0; i < 6; i++)
17     {
18         sum += id[0];
19     }
20     return sum % 250;
21 }
22 
23 int student_info_generate(unsigned char *p_id, student_t *p_student)
24 {
25     int i;
26     for (i = 0; i < 6; i++) 
27     { //随机产生一个学号
28         p_id[i] = rand();
29     }
30     for (i = 0; i < 9; i++) 
31     {
32         p_student->name[i] = (rand() % ('z' - 'a')) + 'a';
33     }
34     p_student->name[i]= '\0';
35     p_student->sex = (rand() & 0x01) ? 'F' : 'M';
36     p_student->height = (float)rand() / rand();
37     p_student->weight = (float)rand() / rand();
38     return 0;
39 }
40 
41 int main(void)
42 {
43     student_t stu;
44     unsigned char id[6];
45     int i;
46     hash_db_t hash_students;
47 
48     hash_db_init(&hash_students, 250, 6, sizeof(student_t), (hash_func_t)db_id_to_idx);
49 
50     for(i = 0; i < 100; i++) 
51     {    //添加100个学生信息
52         student_info_generate(id, &stu); //设置学生的信息,当前一随机数作为测试 
53         if (hash_db_search(&hash_students, id, &stu) == 0) 
54         { //查找到该ID已存在的学生记录
55             printf("该ID的记录已存在!\n");
56             continue;
57         }
58         printf("增加记录:ID : %02x%02x%02x%02x%02x%02x    ",id[0],id[1],id[2],id[3],id[4],id[5]);
59         printf("ؑ信息:%s %c %.2f %.2f\n", stu.name, stu.sex, stu.height, stu.weight);
60         if (hash_db_add(&hash_students, id, &stu) != 0) 
61         {
62             printf("添加失败");
63         }
64     }
65     printf("查找ID为:%02x%02x%02x%02x%02x%02x的信息\n",id[0],id[1],id[2],id[3],id[4],id[5]);
66     if (hash_db_search(&hash_students, id, &stu) == 0) 
67     {
68         printf("学生信息:%s %c %.2f %.2f\n", stu.name, stu.sex, stu.height, stu.weight);
69     } 
70     else 
71     {
72         printf("未找到该ID的记录\n");
73     }
74     hash_db_deinit(&hash_students);
75     return 0;    
76 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!