当前位置:   article > 正文

哈希表C语言实现详解_c语言哈希表实现

c语言哈希表实现

目录

1、数据结构

2、操作函数声明

3、具体实现


1、数据结构

  1. #define HASH_TABLE_MALLOC(size) rt_malloc(size);
  2. #define HASH_TABLE_REALLOC(p,size) rt_realloc(p,size);
  3. #define HASH_TABLE_CALLOC(n,size) rt_calloc(n,size);
  4. #define HASH_TABLE_FREE(p) rt_free(p);
  5. struct hash_table_node;
  6. struct hash_table;
  7. /* 哈希函数,根据key计算哈希值 */
  8. typedef int (*hash_fun)(struct hash_table *table, const void *key);
  9. /*
  10. *哈希key比较, key_cmp:传入的要比较的key, key_becmp:哈希表中被比较的key
  11. * hash桶中的元素是从小到大排列的,
  12. * 返回值 > 0 : key_cmp > key_becmp
  13. * 返回值 = 0 : key_cmp = key_becmp
  14. * 返回值 < 0 : key_cmp < key_becmp
  15. */
  16. typedef int (*hash_keycmp)(struct hash_table *table, const void *key_cmp, const void *key_becmp);
  17. /* hash桶中的节点数据删除函数,如果插入节点为动态分配,则需要在该函数中释放节点空间 */
  18. typedef int (*node_value_free)(struct hash_table_node *node);
  19. struct hash_table_node
  20. {
  21. void *key;
  22. void *value;
  23. struct hash_table_node *next; /*哈希桶节点下个节点*/
  24. };
  25. struct hash_table
  26. {
  27. int size; /*哈希桶的大小,即数组的大小*/
  28. int num; /*各个哈希桶中节点个数的总和*/
  29. hash_fun hashfun; /*哈希函数*/
  30. hash_keycmp keycmp; /*哈希key比较*/
  31. node_value_free valuefree; /*哈希桶节点数据删除*/
  32. struct hash_table_node **tables; /*哈希桶,其实就是一个数组*/
  33. };
  34. /*根据当前结构体元素的地址,获取到结构体首地址*/
  35. //#define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
  36. //#define container(ptr,type,member) ({\
  37. // const typeof( ((type *)0)->member) *__mptr = (ptr);\
  38. // (type *) ((char *)__mptr - OFFSETOF(type,member));})
  39. #define OFFSETOF(TYPE,MEMBER) ((unsigned int)&((TYPE *)0)->MEMBER)
  40. #define container(ptr,type,member) ((type *) ((char *)ptr - OFFSETOF(type,member)))

2、操作函数声明

 

  1. extern struct hash_table *hash_table_creat(int size, hash_fun hashfun, hash_keycmp keycmp, node_value_free valuefree);
  2. extern struct hash_table *hash_table_creat_default(int size, node_value_free valuefree);
  3. extern int hash_table_insert(struct hash_table *hashtable, void *key, void *value);
  4. extern int hash_table_delete(struct hash_table *hashtable, void *key);
  5. extern int hash_table_modify(struct hash_table *hashtable, void *key, void *value);
  6. extern void * hash_table_search(struct hash_table *hashtable, void *key);
  7. extern void hash_table_sample(void);

3、具体实现

  1. #include "algo_hash_table.h"
  2. /**
  3. * 默认使用的哈希函数.
  4. *
  5. * @return 哈希值
  6. */
  7. static int hash_fun_default(struct hash_table *table, const void *key)
  8. {
  9. unsigned int hash = 0;
  10. unsigned int seed = 131;
  11. char *temp = NULL;
  12. temp = (char*)key;
  13. while(*temp)
  14. {
  15. hash = hash * seed + *temp++;
  16. }
  17. hash &= 0x7FFFFFFF;
  18. hash %= table->size;
  19. return hash;
  20. }
  21. /**
  22. * 哈希key比较, key_cmp:传入的要比较的key, key_becmp:哈希表中被比较的key
  23. *
  24. * @return > 0 : key_cmp > key_becmp
  25. * @return = 0 : key_cmp = key_becmp
  26. * @return < 0 : key_cmp < key_becmp
  27. *
  28. */
  29. static int hash_keycmp_default(struct hash_table *table, const void *key_cmp, const void *key_becmp)
  30. {
  31. return strcmp(key_cmp, key_becmp);
  32. }
  33. /**
  34. * 动态创建一个哈希表.
  35. *
  36. * @return NULL:创建失败
  37. * !NULL:创建成功
  38. */
  39. struct hash_table *hash_table_creat(int size, hash_fun hashfun, hash_keycmp keycmp, node_value_free valuefree)
  40. {
  41. struct hash_table *hashtable = NULL;
  42. struct hash_table_node **tables = NULL;
  43. int i = 0;
  44. if (size < 0 || hashfun == NULL || keycmp == NULL)
  45. return NULL;
  46. /*申请哈希表结构空间*/
  47. hashtable = HASH_TABLE_MALLOC(sizeof(*hashtable));
  48. if (hashtable == NULL)
  49. return NULL;
  50. /*申请哈希桶数据空间,实际就是申请size大小的数组空间*/
  51. tables = (struct hash_table_node**)HASH_TABLE_MALLOC(size * sizeof(tables));
  52. if (tables == NULL)
  53. return NULL;
  54. hashtable->num = 0;
  55. hashtable->size = size;
  56. hashtable->tables = tables;
  57. hashtable->hashfun = hashfun;
  58. hashtable->keycmp = keycmp;
  59. hashtable->valuefree = valuefree;
  60. /*清零哈希桶(数组)空间*/
  61. for (i = 0; i < size; i++)
  62. {
  63. hashtable->tables[i] = NULL;
  64. }
  65. return hashtable;
  66. }
  67. /**
  68. * 使用默认的函数函数、key比较函数、节点删除函数 动态创建一个哈希表.
  69. *
  70. * @return NULL:创建失败
  71. * !NULL:创建成功
  72. */
  73. struct hash_table *hash_table_creat_default(int size, node_value_free valuefree)
  74. {
  75. return hash_table_creat(size, hash_fun_default, hash_keycmp_default, valuefree);
  76. }
  77. /**
  78. * 向一个哈希桶插入一个节点,有3种情况:
  79. * 1、prev==NULL,插入位置是头结点 2、key小于cur->key 3、cur==NULL,链表尾插入
  80. *
  81. * @param hashtable: 散列表
  82. * @param key: 关键值
  83. * @param value: 节点数据
  84. * @param value: 节点数据大小
  85. *
  86. * @return 0:插入成功
  87. * -1:哈希表不存在 或 key为空 或 value为空
  88. * -2:节点已经存在
  89. */
  90. int hash_table_insert(struct hash_table *hashtable, void *key, void *value)
  91. {
  92. struct hash_table_node *prev = NULL;
  93. struct hash_table_node *cur = NULL;
  94. struct hash_table_node *new_node = NULL;
  95. int hvalue = 0;
  96. if (hashtable == NULL || key == NULL || value == NULL)
  97. return -1;
  98. /*根据key计算出哈希值*/
  99. hvalue = hashtable->hashfun(hashtable, key);
  100. cur = hashtable->tables[hvalue];
  101. /*hash桶中的元素是从小到大排列的,查找要插入的位置*/
  102. while((cur != NULL) && (hashtable->keycmp(hashtable, key, cur->key) > 0))
  103. {
  104. prev = cur;
  105. cur = cur->next;
  106. }
  107. /*如果key相同,表示节点以及存在,直接返回*/
  108. if ((cur != NULL) && (hashtable->keycmp(hashtable, key, cur->key) == 0))
  109. return -2;
  110. /*插入新增节点*/
  111. new_node = (struct hash_table_node*)HASH_TABLE_MALLOC(sizeof(*new_node));
  112. if (new_node == NULL)
  113. return NULL;
  114. new_node->key = key;
  115. new_node->value = value;
  116. if (prev == NULL) /*第1种情况*/
  117. {
  118. new_node->next = NULL;
  119. hashtable->tables[hvalue] = new_node;/*这里不能为cur = new_node,因为此时的cur和table[hvalue]都是无效的*/
  120. }
  121. else /*第2、3种情况*/
  122. {
  123. new_node->next = cur;
  124. prev->next = new_node;
  125. }
  126. hashtable->num ++;
  127. return 0;
  128. }
  129. /**
  130. * 删除一个节点.
  131. *
  132. * @param hashtable: 散列表
  133. * @param key: 删除节点关键值
  134. *
  135. * @return 0:删除成功
  136. * -1:哈希表不存在 或 key为空
  137. * -2:节点不存在
  138. */
  139. int hash_table_delete(struct hash_table *hashtable, void *key)
  140. {
  141. struct hash_table_node *prev = NULL;
  142. struct hash_table_node *cur = NULL;
  143. int hvalue = 0;
  144. if (hashtable == NULL || key == NULL)
  145. return -1;
  146. /*根据key计算出哈希值*/
  147. hvalue = hashtable->hashfun(hashtable, key);
  148. cur = hashtable->tables[hvalue];
  149. /*hash桶中的元素是从小到大排列的,查找要删除的位置*/
  150. while((cur != NULL) && (hashtable->keycmp(hashtable, key, cur->key) >= 0))
  151. {
  152. if (hashtable->keycmp(hashtable, key, cur->key) == 0)
  153. {
  154. if (prev == NULL)/*如果删除的是头结点*/
  155. {
  156. hashtable->tables[hvalue] = cur->next;
  157. }
  158. else
  159. {
  160. prev->next = cur->next;
  161. }
  162. /*若节点所指向的数据(包括key和value)为动态分配,则需要在这里释放*/
  163. hashtable->valuefree(cur);
  164. HASH_TABLE_FREE(cur);
  165. hashtable->num --;
  166. return 0;
  167. }
  168. else
  169. {
  170. prev = cur;
  171. cur = cur->next;
  172. }
  173. }
  174. return -2;
  175. }
  176. /**
  177. * 修改一个节点.注意事项:
  178. * 1、会先释放节点指向的就数据空间(这里如果是realloc更大的数据空间,容易造成指针泄露,且是不知道整个数据结构的大小的)
  179. * 2、修改的节点必须为新动态分配的空间
  180. *
  181. * @param hashtable: 散列表
  182. * @param key: 修改节点关键值
  183. * @param value: 修改节点数据
  184. *
  185. * @return 0:修改成功
  186. * -1:哈希表不存在 或 key为空 或value为空
  187. * -2:节点不存在
  188. */
  189. int hash_table_modify(struct hash_table *hashtable, void *key, void *value)
  190. {
  191. struct hash_table_node *cur = NULL;
  192. int hvalue = 0;
  193. if (hashtable == NULL || key == NULL || value == NULL)
  194. return -1;
  195. /*根据key计算出哈希值*/
  196. hvalue = hashtable->hashfun(hashtable, key);
  197. cur = hashtable->tables[hvalue];
  198. /*hash桶中的元素是从小到大排列的,查找要修改的位置*/
  199. while((cur != NULL) && (hashtable->keycmp(hashtable, key, cur->key) >= 0))
  200. {
  201. if (hashtable->keycmp(hashtable, key, cur->key) == 0)
  202. {
  203. hashtable->valuefree(cur);
  204. cur->key = key;
  205. cur->value = value;
  206. return 0;
  207. }
  208. else
  209. {
  210. cur = cur->next;
  211. }
  212. }
  213. return -2;
  214. }
  215. /**
  216. * 根据key查找节点数据.
  217. *
  218. * @param hashtable: 散列表
  219. * @param key: 查找节点关键值
  220. * @param value: 查找节点数据
  221. *
  222. * @return NULL:查找失败
  223. * !NULL:查找成功
  224. */
  225. void * hash_table_search(struct hash_table *hashtable, void *key)
  226. {
  227. struct hash_table_node *cur = NULL;
  228. int hvalue = 0;
  229. if (hashtable == NULL || key == NULL)
  230. return NULL;
  231. /*根据key计算出哈希值*/
  232. hvalue = hashtable->hashfun(hashtable, key);
  233. cur = hashtable->tables[hvalue];
  234. /*hash桶中的元素是从小到大排列的,查找要查找的位置*/
  235. while((cur != NULL) && (hashtable->keycmp(hashtable, key, cur->key) >= 0))
  236. {
  237. if (hashtable->keycmp(hashtable, key, cur->key) == 0)
  238. {
  239. return cur->value;
  240. }
  241. else
  242. {
  243. cur = cur->next;
  244. }
  245. }
  246. return NULL;
  247. }
  248. /*******************************************************************************************
  249. * 使用示例
  250. *******************************************************************************************/
  251. struct test_node
  252. {
  253. char key[10];
  254. char value[10];
  255. };
  256. int node_value_free_sample(struct hash_table_node *node)
  257. {
  258. struct test_node *node_temp = NULL;
  259. /*根据key在test_node结构体中的偏移地址,找到散列表节点实际指向的结构体首地址*/
  260. node_temp = container(node->key, struct test_node, key);
  261. /*如果节点所指向数据空间为动态申请的则需要释放*/
  262. HASH_TABLE_FREE(node_temp);
  263. return 0;
  264. }
  265. struct hash_table *hash_table_test;
  266. char table_node_read[5][10];
  267. void hash_table_sample(void)
  268. {
  269. int i = 0;
  270. struct test_node *node_temp = NULL;
  271. char rd_key[10] = {10}, del_key[10] = {0};
  272. char *temp = NULL;
  273. hash_table_test = hash_table_creat_default(5, node_value_free_sample);
  274. /*插入 -- 查询*/
  275. for (i=0; i<5; i++)
  276. {
  277. node_temp = HASH_TABLE_MALLOC(sizeof(*node_temp));
  278. memset(node_temp, 0, sizeof(*node_temp));
  279. sprintf(node_temp->key, "AAA%d", i);
  280. sprintf(node_temp->value, "%d", i+10);
  281. hash_table_insert(hash_table_test, node_temp->key, node_temp->value);
  282. }
  283. for (i=0; i<5; i++)
  284. {
  285. sprintf(rd_key, "AAA%d", i);
  286. temp = hash_table_search(hash_table_test, rd_key);
  287. memcpy(table_node_read[i], temp, 10);
  288. }
  289. /*修改 -- 查询*/
  290. for (i=0; i<5; i++)
  291. {
  292. node_temp = HASH_TABLE_MALLOC(sizeof(*node_temp));
  293. memset(node_temp, 0, sizeof(*node_temp));
  294. sprintf(node_temp->key, "AAA%d", i);
  295. sprintf(node_temp->value, "%d", i+20);
  296. hash_table_modify(hash_table_test, node_temp->key, node_temp->value);
  297. }
  298. for (i=0; i<5; i++)
  299. {
  300. sprintf(rd_key, "AAA%d", i);
  301. temp = hash_table_search(hash_table_test, rd_key);
  302. memcpy(table_node_read[i], temp, 10);
  303. }
  304. /*删除 -- 查询*/
  305. for (i=0; i<3; i++)
  306. {
  307. sprintf(del_key, "AAA%d", i);
  308. hash_table_delete(hash_table_test, del_key);
  309. }
  310. for (i=0; i<5; i++)
  311. {
  312. temp = NULL;
  313. memset(table_node_read[i], 0, 10);
  314. sprintf(rd_key, "AAA%d", i);
  315. temp = hash_table_search(hash_table_test, rd_key);
  316. if (temp != NULL)
  317. {
  318. memcpy(table_node_read[i], temp, 10);
  319. }
  320. }
  321. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/449855
推荐阅读
相关标签
  

闽ICP备14008679号