zoukankan      html  css  js  c++  java
  • c语言hash表的实现

    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]= '';
    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的记录已存在!
    ");
    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
    ", 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的信息
    ",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
    ", stu.name, stu.sex, stu.height, stu.weight);
    69     } 
    70     else 
    71     {
    72         printf("未找到该ID的记录
    ");
    73     }
    74     hash_db_deinit(&hash_students);
    75     return 0;    
    76 }
  • 相关阅读:
    Kali之Metasploit生成apk后门控制安卓
    迅雷后台上传?干掉迅雷后台进程和服务的一个批处理
    不用第三方软件–一键开关笔记本电脑wifi热点的批处理
    【PHP】创蓝253云通讯国际短信余额查询请求demo
    【PHP】创蓝253云通讯平台国际短信API接口demo
    创蓝253云通讯平台---短信验证码接口说明
    C++调取国际短信验证码----创蓝253云通讯平台---demo
    手机空号、停机、注销,空号检测为你去除无效号码
    上市公司都被撸垮,羊毛党就真的没有办法解决了吗?
    如何用Ruby调取创蓝253短信验证码
  • 原文地址:https://www.cnblogs.com/chenweilin/p/12692034.html
Copyright © 2011-2022 走看看