zoukankan      html  css  js  c++  java
  • 沉淀之log4c的hash

        上回书说到,log4c的list模块,咱们书接上回,说一说他的hash模块,仍然用以模块代码进行注释的形式进行。
    头文件如下:
    hash.h:
    1. /* $Id: hash.h,v 1.4 2005/05/24 15:33:18 legoater Exp $
    2. *
    3. * Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
    4. * Author: Marc Vertes <mvertes@meiosys.com>
    5. * See the COPYING file for the terms of usage and distribution.
    6. */
    7. #ifndef __sd_hash_h
    8. #define __sd_hash_h
    9. /**
    10. * @file hash.h
    11. *
    12. * @brief Generic hash table. It is implemented as an array of doubly-linked
    13. * lists of iterators. The index within the array is computed by a efficient
    14. * hash function.
    15. */
    16. #include <stddef.h>
    17. #include <sd/defs.h>
    18. __SD_BEGIN_DECLS
    19. struct __sd_hash_ops {
    20. unsigned int (*hash) (const void*);
    21. int (*compare) (const void*, const void*);
    22. void* (*key_dup) (const void*);
    23. void (*key_free) (void*);
    24. void* (*data_dup) (const void*);
    25. void (*data_free) (void*);
    26. };
    27. /**
    28. * 这个结构体保存hash表的操作信息
    29. */
    30. typedef struct __sd_hash_ops sd_hash_ops_t;
    31. /**
    32. * hash表的结构体类型
    33. */
    34. typedef struct __sd_hash sd_hash_t;
    35. struct __sd_hash_iter {
    36. void* key;
    37. void* data;
    38. struct __sd_hash* hash;
    39. unsigned int __hkey;
    40. struct __sd_hash_iter* __next;
    41. struct __sd_hash_iter* __prev;
    42. int __foreach;
    43. };
    44. /**
    45. * hash表元素的容器,用来存放用户数据
    46. */
    47. typedef struct __sd_hash_iter sd_hash_iter_t;
    48. /**
    49. * 遍历的回调函数类型
    50. */
    51. typedef unsigned int (*sd_hash_func_t)(void* a_key, void* a_data,
    52. void* a_userdata);
    53. /**
    54. * 新建一个hash表,用户可以指定内存的分配方式以及key值计算和数据存储方式
    55. * @param a_size 初始化数组的大小
    56. * @param a_ops hash操作函数,如果是NULL,默认字符串key值算法,另外没有为
    57. * key值计算和用户数据存储方式
    58. * @return hash表结构
    59. */
    60. extern sd_hash_t* sd_hash_new(size_t a_size, const sd_hash_ops_t* a_ops);
    61. /**
    62. * 销毁一个hash表
    63. */
    64. extern void sd_hash_delete(sd_hash_t* a_this);
    65. /**
    66. * 清空一个hash表
    67. */
    68. extern void sd_hash_clear(sd_hash_t* a_this);
    69. /**
    70. * 根据key值在hash表里查找元素容器
    71. * @param a_key key值
    72. * @return 指向找到的结构体地址或者NULL
    73. */
    74. extern sd_hash_iter_t* sd_hash_lookup(sd_hash_t* a_this, const void* a_key);
    75. /**
    76. * 根据key值在hash表里查找元素容器,如果不存在就新建一个。
    77. * @param a_key 与待查找容器相关联的key值
    78. * @return 返回查找到的容器或者NULL.
    79. */
    80. extern sd_hash_iter_t* sd_hash_lookadd(sd_hash_t* a_this, const void* a_key);
    81. /**
    82. * 通过给定的数据key值添加用户数据到hash表,如果已经存在那么就通过hash操作中的
    83. * 释放接口进行释放之前的,并将当前数据插入
    84. * @param a_key 容器的键值key值
    85. * @param a_data 数据
    86. * @return 返回指向数据容器的指针.
    87. */
    88. extern sd_hash_iter_t* sd_hash_add(sd_hash_t* a_this, const void* a_key,
    89. void* a_data);
    90. /**
    91. * 从hash表中移除一个容器
    92. * @param 容器的key值
    93. */
    94. extern void sd_hash_del(sd_hash_t* a_this, const void* a_key);
    95. /**
    96. * 调用回调函数a_fun遍历整个hash,直到该回调返回非0
    97. * @param a_func 回调函数
    98. * @param a_data 用户数据传如到a_func
    99. */
    100. extern void sd_hash_foreach(sd_hash_t* a_this, sd_hash_func_t a_func,
    101. void* a_data);
    102. /**
    103. * 获得hash表中所有的容器个数
    104. */
    105. extern unsigned int sd_hash_get_nelem(sd_hash_t* a_this);
    106. /**
    107. * 获得hash表的大小
    108. */
    109. extern unsigned int sd_hash_get_size(sd_hash_t* a_this);
    110. /**
    111. * 获取hash表的第一个元素容器
    112. */
    113. extern sd_hash_iter_t* sd_hash_begin(sd_hash_t* a_this);
    114. /**
    115. * 获取hash表的最后一个元素容器
    116. */
    117. extern sd_hash_iter_t* sd_hash_end(sd_hash_t* a_this);
    118. /**
    119. * 获取当前容器的下一个容器
    120. */
    121. extern sd_hash_iter_t* sd_hash_iter_next(sd_hash_iter_t* a_this);
    122. /**
    123. * 获取当前容器的上一个容器
    124. */
    125. extern sd_hash_iter_t* sd_hash_iter_prev(sd_hash_iter_t* a_this);
    126. /**
    127. * 删除一个容器,根据容器地址
    128. */
    129. extern void sd_hash_iter_del(sd_hash_iter_t* a_this);
    130. /**
    131. * Hashes strings.计算key值
    132. */
    133. extern unsigned int sd_hash_hash_string(const char* a_string);
    134. __SD_END_DECLS
    135. #endif
        头文件里面定义了hash操作的结构体,hash表元素容器的结构体,以及hash表的类型,其中hash表的类型是在hash.c中进行定义的,这样很好的屏蔽了hash结构。
        对于hash表的结构体定义如下:
    1. #define SD_HASH_FULLTAB 2 /* rehash when table gets this x full */
    2. #define SD_HASH_GROWTAB 4 /* grow table by this factor */
    3. #define SD_HASH_DEFAULT_SIZE 10 /* self explenatory */
    4. struct __sd_hash {
    5. size_t nelem; //hash表中元素个数
    6. size_t size; //hash大小
    7. sd_hash_iter_t** tab; //元素容器的表
    8. const sd_hash_ops_t* ops; //hash操作
    9. };
    10. #define hindex(h, n) ((h)%(n)) //计算hashkey

    通过以上各个结构体的定义可以先给出整个hash表的总体结构,然后后续参考sd_hash_new进一步进行理解。

    图一:hash结构图

    具体代码以及分析如下:
    sd_hash_new:
    1. /******************************************************************************/
    2. //创建一个hash表
    3. //a_size hash表能够容纳元素的数量
    4. //a_ops hash操作集合
    5. extern sd_hash_t* sd_hash_new(size_t a_size, const sd_hash_ops_t* a_ops)
    6. {
    7. //一个默认的hash操作集合、hash值计算,比较等
    8. const static sd_hash_ops_t default_ops = {
    9. (void*) &sd_hash_hash_string,
    10. (void*) &strcmp,
    11. 0, 0, 0, 0
    12. };
    13. //分配hash表和容器表内存并进行检查
    14. sd_hash_t* hash;
    15. sd_hash_iter_t** tab;
    16. if (a_size == 0) a_size = SD_HASH_DEFAULT_SIZE;
    17. hash = sd_calloc(1, sizeof(*hash));
    18. tab = sd_calloc(a_size, sizeof(*tab));
    19. if (hash == 0 || tab == 0) {
    20. free(hash);
    21. free(tab);
    22. return 0;
    23. }
    24. //初始化元素个数,大小,容器表地址以及操作集合
    25. hash->nelem = 0;
    26. hash->size = a_size;
    27. hash->tab = tab;
    28. hash->ops = a_ops != 0 ? a_ops : &default_ops;
    29. return hash;
    30. }

    sd_hash_delete:
    1. /******************************************************************************/
    2. //销毁一个hash表,先将hash表清空,然后将hash进行回收
    3. //a_this 待清空的hash表
    4. extern void sd_hash_delete(sd_hash_t* a_this)
    5. {
    6. //将hash表中的元素进行清空
    7. sd_hash_clear(a_this);
    8. //释放hash的容器表和hash表
    9. free(a_this->tab);
    10. free(a_this);
    11. }

    sd_hash_clear:
    1. /******************************************************************************/
    2. //清空一个hash表中的元素
    3. //a_this 待清空的hash表
    4. extern void sd_hash_clear(sd_hash_t* a_this)
    5. {
    6. size_t h;
    7. sd_hash_iter_t* p;
    8. sd_hash_iter_t* q;
    9. if (a_this == 0) return;
    10. //遍历一个hash的所有容器指针的下挂的所有容器,进行释放
    11. for (h = 0; h < a_this->size; h++) {
    12. for (p = a_this->tab[h]; p; p = q) {
    13. q = p->__next;
    14. if (a_this->ops->key_free) a_this->ops->key_free(p->key);
    15. if (a_this->ops->data_free) a_this->ops->data_free(p->data);
    16. free(p);
    17. }
    18. a_this->tab[h] = 0;
    19. }
    20. a_this->nelem = 0;
    21. }

    sd_hash_lookup:
    1. /**
    2. * 根据key值在hash表里查找元素容器
    3. * @param a_key key值
    4. * @return 指向找到的结构体地址或者NULL
    5. */
    6. extern sd_hash_iter_t* sd_hash_lookup(sd_hash_t* a_this, const void* a_key)
    7. {
    8. int h;
    9. sd_hash_iter_t* p;
    10. //参数判断
    11. if (a_this == 0 || a_key == 0) return 0;
    12. //计算hash值
    13. h = hindex(a_this->ops->hash(a_key), a_this->size);
    14. //遍历该hash值所对应的容器指针下挂的所有容器并进行比较验证
    15. for (p = a_this->tab[h]; p != 0; p = p->__next)
    16. if (a_this->ops->compare(a_key, p->key) == 0) {
    17. return p;
    18. }
    19. return 0;
    20. }

    sd_hash_lookadd:
    1. /**
    2. * 根据key值在hash表里查找元素容器,如果不存在就新建一个。
    3. * @param a_key 与待查找容器相关联的key值
    4. * @return 返回查找到的容器或者NULL.
    5. */
    6. extern sd_hash_iter_t* sd_hash_lookadd(sd_hash_t* a_this, const void* a_key)
    7. {
    8. int h;
    9. sd_hash_iter_t* p;
    10. if (a_this == 0 || a_key == 0) return 0;
    11. //先查找一遍,已经存在就进行返回,否则就分配空间然后进行初始化
    12. if ((p = sd_hash_lookup(a_this, a_key)) != 0) return p;
    13. if ((p = sd_calloc(1, sizeof(*p))) == 0) return 0;
    14. //如果有复制数据功能那么就复制一份否则就用原始数据
    15. if (a_this->ops->key_dup != 0)
    16. p->key = a_this->ops->key_dup(a_key);
    17. else
    18. p->key = (void*) a_key;
    19. //初始化容器一些参数
    20. p->hash = a_this;
    21. p->__hkey = a_this->ops->hash(a_key);
    22. //如果超过当前hash最大容量那么就进行扩张
    23. if (a_this->nelem > SD_HASH_FULLTAB * a_this->size) rehash(a_this);
    24. h = hindex(p->__hkey,
    25. a_this->size);
    26. //将当前容器挂到对应key值的容器指针下挂链表中。
    27. p->__next = a_this->tab[h];
    28. a_this->tab[h] = p;
    29. if (p->__next != 0) p->__next->__prev = p;
    30. //计数
    31. a_this->nelem++;
    32. return p;
    33. }

    sd_hash_add:
    1. /**
    2. * 通过给定的数据key值添加用户数据到hash表,如果已经存在那么就通过hash操作中的
    3. * 释放接口进行释放之前的,并将当前数据插入
    4. * @param a_key 容器的键值key值
    5. * @param a_data 数据
    6. * @return 返回指向数据容器的指针.
    7. */
    8. extern sd_hash_iter_t* sd_hash_add(sd_hash_t* a_this, const void* a_key,
    9. void* a_data)
    10. {
    11. sd_hash_iter_t* p;
    12. //调用lookadd进行插入
    13. if ((p = sd_hash_lookadd(a_this, a_key)) == 0) return 0;
    14. //如果这个值已经存在,那么就释放了然后重新进行赋值当前值
    15. if (a_this->ops->data_free != 0) a_this->ops->data_free(p->data);
    16. //判断释放需要进行备份并进行赋值
    17. if (a_this->ops->data_dup != 0)
    18. p->data = a_this->ops->data_dup(a_data);
    19. else
    20. p->data = a_data;
    21. return p;
    22. }

    sd_hash_del:
    1. /**
    2. * 从hash表中移除一个容器
    3. * @param 容器的key值
    4. */
    5. extern void sd_hash_del(sd_hash_t* a_this, const void* a_key)
    6. {
    7. int h;
    8. sd_hash_iter_t* p;
    9. //定位容器的容器指针
    10. h = hindex(a_this->ops->hash(a_key), a_this->size);
    11. //循环遍历容器指针下挂的链表找到待删除容器进行删除
    12. for (p = a_this->tab[h]; p != 0; p = p->__next)
    13. if (a_this->ops->compare(a_key, p->key) == 0) break;
    14. if (p == 0) return;
    15. //进行删除
    16. sd_hash_iter_del(p);
    17. }

    sd_hash_foreach:
    1. /**
    2. * 调用回调函数a_fun遍历整个hash,直到该回调返回非0
    3. * @param a_func 回调函数
    4. * @param a_data 用户数据传如到a_func
    5. */
    6. extern void sd_hash_foreach(sd_hash_t* a_this, sd_hash_func_t a_func,
    7. void* a_data)
    8. {
    9. size_t h, ret;
    10. sd_hash_iter_t* p;
    11. sd_hash_iter_t* q;
    12. //参数验证
    13. if (a_this == 0 || a_func == 0) return;
    14. //定位容器指针,找到容器
    15. for (h = 0; h < a_this->size; h++)
    16. for (p = a_this->tab[h]; p != 0; p = q) {
    17. p->__foreach = 1;
    18. //调用遍历回调函数进行操作
    19. ret = (*a_func)(p->key, p->data, a_data);
    20. q = p->__next;
    21. //删除重复表项
    22. if (p->__foreach == 0)
    23. sd_hash_iter_del(p);
    24. else
    25. p->__foreach = 0;
    26. if (ret != 0) return;
    27. }
    28. }

    sd_hash_get_nelem:
    1. /**
    2. * 获得hash表中所有的容器个数
    3. */
    4. extern unsigned int sd_hash_get_nelem(sd_hash_t* a_this)
    5. {
    6. if (a_this == 0) return 0;
    7. return a_this->nelem;
    8. }

    sd_hash_get_size:
    1. /**
    2. * 获得hash表的大小
    3. */
    4. extern unsigned int sd_hash_get_size(sd_hash_t* a_this)
    5. {
    6. if (a_this == 0) return 0;
    7. return a_this->size;
    8. }

    sd_hash_begin:
    1. /**
    2. * 获取hash表的第一个元素容器
    3. */
    4. extern sd_hash_iter_t* sd_hash_begin(sd_hash_t* a_this)
    5. {
    6. size_t h;
    7. if (a_this == 0) return 0;
    8. for (h = 0; h < a_this->size; h++)
    9. if (a_this->tab[h])
    10. return a_this->tab[h];
    11. return 0;
    12. }

    sd_hash_end:未实现
    1. /**
    2. * 获取hash表的最后一个元素容器
    3. */
    4. extern sd_hash_iter_t* sd_hash_end(sd_hash_t* a_this)
    5. {
    6. return 0;
    7. }

    sd_hash_iter_next:
    1. /**
    2. * 获取当前容器的下一个容器
    3. */
    4. extern sd_hash_iter_t* sd_hash_iter_next(sd_hash_iter_t* a_this)
    5. {
    6. int h;
    7. size_t i;
    8. //参数检查并进行链表递进后返回
    9. if (a_this == 0) return 0;
    10. if (a_this->__next != 0) return a_this->__next;
    11. //如果当前容器就是其容器指针的最后一个,那么要寻找到下一个容器指针的
    12. //第一个容器进行返回
    13. h = hindex(a_this->__hkey, a_this->hash->size);
    14. for (i = h + 1; i < a_this->hash->size; i++)
    15. if (a_this->hash->tab[i])
    16. return a_this->hash->tab[i];
    17. return 0;
    18. }

    sd_hash_iter_prev:
    1. /**
    2. * 获取当前容器的上一个容器
    3. */
    4. extern sd_hash_iter_t* sd_hash_iter_prev(sd_hash_iter_t* a_this)
    5. {
    6. int h, i;
    7. sd_hash_iter_t* p;
    8. //参数验证,然后如果在当前容器指针的链表下存在前一个指针那么进行返回
    9. if (a_this == 0) return 0;
    10. if (a_this->__prev != 0) return a_this->__prev;
    11. //如果当前容器就是该链表下的第一个,那么返回前一个容器指针的第一个有效容器
    12. h = hindex(a_this->__hkey, a_this->hash->size);
    13. for (i = h - 1; i > 0; i--)
    14. for (p = a_this->hash->tab[i]; p; p = p->__next)
    15. if (p->__next == 0)
    16. return p;
    17. return 0;
    18. }

    sd_hash_iter_del:
    1. /**
    2. * 删除一个容器,根据容器地址
    3. */
    4. extern void sd_hash_iter_del(sd_hash_iter_t* a_this)
    5. {
    6. if (a_this == 0) return;
    7. //释放容器存放的数据
    8. if (a_this->hash->ops->data_free != 0)
    9. a_this->hash->ops->data_free(a_this->data);
    10. a_this->data = 0;
    11. //释放容器的key值内存
    12. if (a_this->hash->ops->key_free != 0)
    13. a_this->hash->ops->key_free(a_this->key);
    14. a_this->key = 0;
    15. //已经删除的即不再进行遍历了。
    16. if (a_this->__foreach == 1) {
    17. a_this->__foreach = 0;
    18. return;
    19. }
    20. //从链表中摘除
    21. if (a_this->__next != 0) a_this->__next->__prev = a_this->__prev;
    22. if (a_this->__prev != 0)
    23. a_this->__prev->__next = a_this->__next;
    24. else
    25. a_this->hash->tab[hindex(a_this->__hkey, a_this->hash->size)] =
    26. a_this->__next;
    27. //减一数目
    28. a_this->hash->nelem--;
    29. //释放
    30. free(a_this);
    31. }

    sd_hash_hash_string:
    1. /**
    2. * Hashes strings.计算key值
    3. */
    4. extern unsigned int sd_hash_hash_string(const char* a_string)
    5. {
    6. register unsigned int h;
    7. //一个hash计算方法
    8. for (h = 0; *a_string != ''; a_string++)
    9. h = *a_string + 31 * h;
    10. return h;
    11. }

    一个示例程序
    main.c
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include "stack.h"
    5. #include "hash.h"
    6. #include "list.h"
    7. typedef struct test
    8. {
    9. char a[20];
    10. int b;
    11. int c;
    12. }test_t;
    13. static unsigned int print(void *data, void *p)
    14. {
    15. test_t *t = (test_t *)data;
    16. printf("a:%s b:%d c:%d ",t->a, t->b, t->c);
    17. return 0;
    18. }
    19. unsigned int print_hash(void *a_key, void *a_data, void *a_userdata)
    20. {
    21. print(a_data, NULL);
    22. return 0;
    23. }
    24. int main()
    25. {
    26. sd_hash_ops_t ops = {
    27. (void*) &sd_hash_hash_string,
    28. (void*) &strcmp,
    29. 0, 0, 0, free
    30. };
    31. sd_hash_t*hash = sd_hash_new(20, &ops);
    32. test_t *fir = malloc(sizeof(test_t));
    33. strcpy(fir->a,"zhang");
    34. fir->b = 10;
    35. fir->c = 20;
    36. sd_hash_add(hash, fir->a,fir);
    37. test_t *sec = malloc(sizeof(test_t));
    38. strcpy(sec->a,"wang");
    39. sec->b = 20;
    40. sec->c = 30;
    41. sd_hash_add(hash, sec->a,sec);
    42. test_t *third = malloc(sizeof(test_t));
    43. strcpy(third->a,"zhongguo");
    44. third->b = 30;
    45. third->c = 40;
    46. sd_hash_iter_t *iter = sd_hash_lookadd(hash, "zhongguo");
    47. iter->data = third;
    48. int cnt = sd_hash_get_nelem(hash);
    49. printf("hash items is : %d ",cnt);
    50. sd_hash_foreach(hash, print_hash, NULL);
    51. sd_hash_clear(hash);
    52. sd_hash_delete(hash);
    53. return 0;
    54. }








  • 相关阅读:
    【例题 6-12 UVA
    【例题 6-11 UVA-297】Quadtrees
    【例题 6-10 UVA
    SpringMVC表单验证器
    Spring MVC常用注解
    什么是Spring Boot?
    什么是Kotlin?Java的替代语言?
    阿里Druid连接池的坑。。
    常见的3种Class级别的错误
    阿里巴巴,排行前10的开源项目
  • 原文地址:https://www.cnblogs.com/cfzhang/p/12a02b43f08412c685a32aa489b59579.html
Copyright © 2011-2022 走看看