参考精选博客:https://blog.csdn.net/whatday/article/details/95926766
uthash.h
/* * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: 哈希表2,提供哈希表的常用简化接口 * Create: 2020-06-01 * Version: V1.4 * Contact: 有任何问题或建议,请前往 * http://rnd-isource.huawei.com/bugs/hw-cstl */ #ifndef HHASH2_H #define HHASH2_H #include <stdint.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include "hhash.h" struct SimpHash; /* key 为 int, value 为 uintptr_t 的哈希表接口 */ typedef struct SimpHash IntHash; static inline IntHash *IntHashCreate(void); static inline void IntHashDestroy(IntHash *ht); static inline bool IntHashEmpty(const IntHash *ht); static inline size_t IntHashSize(const IntHash *ht); /* 增加 k-v 对,已经存在则刷新 v;成功返回 0,内存错误返回 -1 */ static inline int IntHashSet(IntHash *ht, int k, uintptr_t v); /* 由 k 查 v;出参 exist 可选,指示是否存在 */ static inline uintptr_t IntHashGet(const IntHash *ht, int k, bool *exist); /* 指定 k 删除 k-v 对 */ static inline void IntHashDel(IntHash *ht, int k); /* 指定 k 查询是否存在 */ static inline bool IntHashExist(const IntHash *ht, int k); /* 迭代处理所有节点 k-v */ typedef void (*IntHashIterFunc)(int k, uintptr_t v, void *arg); static inline void IntHashIterate(const IntHash *ht, IntHashIterFunc fn, void *arg); /* key 为 str(const char*), value 为 uintptr_t 的哈希表接口 */ typedef struct SimpHash StrHash; static inline StrHash *StrHashCreate(void); static inline void StrHashDestroy(StrHash *ht); static inline bool StrHashEmpty(const StrHash *ht); static inline size_t StrHashSize(const StrHash *ht); /* 增加 k-v 对,已经存在则刷新 v;成功返回 0,内存错误返回 -1 */ static inline int StrHashSet(StrHash *ht, const char *k, uintptr_t v); /* 由 k 查 v;出参 *exist 指示是否存在 */ static inline uintptr_t StrHashGet(const StrHash *ht, const char *k, bool *exist); /* 指定 k 删除 k-v 对 */ static inline void StrHashDel(StrHash *ht, const char *k); /* 指定 k 查询是否存在 */ static inline bool StrHashExist(const StrHash *ht, const char *k); /* 迭代处理所有节点 k-v */ typedef void StrHashIterFunc(const char *k, uintptr_t v, void *arg); static inline void StrHashIterate(const StrHash *ht, StrHashIterFunc fn, void *arg); /* IntHash, StrHash 复用相同的节点类型 */ struct SimpHashNode { struct Node node; int intk; const char *strk; uintptr_t value; }; static bool IntNodeEqual(const struct Node *a, const struct Node *b) { struct SimpHashNode *na = NODE_ENTRY(a, struct SimpHashNode, node); struct SimpHashNode *nb = NODE_ENTRY(b, struct SimpHashNode, node); return na->intk == nb->intk; } static bool StrNodeEqual(const struct Node *a, const struct Node *b) { struct SimpHashNode *na = NODE_ENTRY(a, struct SimpHashNode, node); struct SimpHashNode *nb = NODE_ENTRY(b, struct SimpHashNode, node); return strcmp(na->strk, nb->strk) == 0; } static size_t IntNodeKey(const struct Node *node, size_t bktSize) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); size_t k = TwIntHash((unsigned int)n->intk); return k % bktSize; } static size_t StrNodeKey(const struct Node *node, size_t bktSize) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); size_t k = BkdrHash(n->strk); return k % bktSize; } static void SimpHashNodeFree(struct Node *node) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); free(n); } #define SIMPLE_HASH_INIT_BKT_SIZE 16 /* * 每个 hash 桶中节点个数平均值上限 * 当节点增多,导致超过这个值时,hash 桶自动扩充一倍 * 如果有内存空间限制,可以增大该值,对应的搜索时间会增加 */ #define SIMPLE_HASH_NODE_PER_BKT 1 struct SimpHash { struct HashTable raw; size_t nodeCnt; }; static inline IntHash *IntHashCreate(void) { struct SimpHash *ht = (struct SimpHash*)malloc(sizeof(struct SimpHash)); if (ht == NULL) { return NULL; } ht->nodeCnt = 0; int ret = HashInit(&ht->raw, SIMPLE_HASH_INIT_BKT_SIZE, IntNodeEqual, IntNodeKey); if (ret != 0) { free(ht); return NULL; } return ht; } static inline StrHash *StrHashCreate(void) { struct SimpHash *ht = (struct SimpHash*)malloc(sizeof(struct SimpHash)); if (ht == NULL) { return NULL; } ht->nodeCnt = 0; int ret = HashInit(&ht->raw, SIMPLE_HASH_INIT_BKT_SIZE, StrNodeEqual, StrNodeKey); if (ret != 0) { free(ht); return NULL; } return ht; } static inline void IntHashDestroy(IntHash *ht) { HashDeinit(&ht->raw, SimpHashNodeFree); free(ht); } static inline void StrHashDestroy(StrHash *ht) { HashDeinit(&ht->raw, SimpHashNodeFree); free(ht); } static inline bool IntHashEmpty(const IntHash *ht) { return ht->nodeCnt == 0; } static inline bool StrHashEmpty(const StrHash *ht) { return ht->nodeCnt == 0; } static inline size_t IntHashSize(const IntHash *ht) { return ht->nodeCnt; } static inline size_t StrHashSize(const StrHash *ht) { return ht->nodeCnt; } static inline int IntHashSet(IntHash *ht, int k, uintptr_t v) { struct SimpHashNode cmp = { .intk = k }; struct SimpHashNode *n; struct Node *node = HashFind(&ht->raw, &cmp.node); if (node != NULL) { n = NODE_ENTRY(node, struct SimpHashNode, node); n->value = v; return 0; } n = (struct SimpHashNode*)malloc(sizeof(struct SimpHashNode)); if (n == NULL) { return -1; } n->intk = k; n->value = v; HashAdd(&ht->raw, &n->node); ht->nodeCnt++; if (ht->nodeCnt > ht->raw.bktSize * SIMPLE_HASH_NODE_PER_BKT) { (void)HashReset(&ht->raw, ht->raw.bktSize * 2, NULL, NULL); } return 0; } static inline int StrHashSet(StrHash *ht, const char *k, uintptr_t v) { struct SimpHashNode cmp = { .strk = k }; struct SimpHashNode *n; struct Node *node = HashFind(&ht->raw, &cmp.node); if (node != NULL) { n = NODE_ENTRY(node, struct SimpHashNode, node); n->value = v; return 0; } size_t len = sizeof(struct SimpHashNode) + strlen(k) + 1; n = (struct SimpHashNode*)malloc(len); if (n == NULL) { return -1; } (void)strcpy((char*)(n + 1), k); n->strk = (const char*)(n + 1); n->value = v; HashAdd(&ht->raw, &n->node); ht->nodeCnt++; if (ht->nodeCnt > ht->raw.bktSize * SIMPLE_HASH_NODE_PER_BKT) { (void)HashReset(&ht->raw, ht->raw.bktSize * 2, NULL, NULL); } return 0; } static inline uintptr_t IntHashGet(const IntHash *ht, int k, bool *exist) { struct SimpHashNode cmp = { .intk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); if (exist != NULL) { *exist = node != NULL; } if (node != NULL) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); return n->value; } return 0; } static inline uintptr_t StrHashGet(const StrHash *ht, const char *k, bool *exist) { struct SimpHashNode cmp = { .strk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); if (exist != NULL) { *exist = node != NULL; } if (node != NULL) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); return n->value; } return 0; } static inline void IntHashDel(IntHash *ht, int k) { struct SimpHashNode cmp = { .intk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); if (node == NULL) { return; } HashRemove(node); ht->nodeCnt--; struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); free(n); } static inline void StrHashDel(StrHash *ht, const char *k) { struct SimpHashNode cmp = { .strk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); if (node == NULL) { return; } HashRemove(node); ht->nodeCnt--; struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); free(n); } static inline bool IntHashExist(const IntHash *ht, int k) { struct SimpHashNode cmp = { .intk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); return node != NULL; } static inline bool StrHashExist(const StrHash *ht, const char *k) { struct SimpHashNode cmp = { .strk = k }; struct Node *node = HashFind(&ht->raw, &cmp.node); return node != NULL; } static inline void IntHashIterate(const IntHash *ht, IntHashIterFunc fn, void *arg) { for (size_t i = 0; i < ht->raw.bktSize; i++) { struct Node *node; LIST_FOR_EACH(node, &ht->raw.bkts[i]) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); fn(n->intk, n->value, arg); } } } static inline void StrHashIterate(const StrHash *ht, StrHashIterFunc fn, void *arg) { for (size_t i = 0; i < ht->raw.bktSize; i++) { struct Node *node; LIST_FOR_EACH(node, &ht->raw.bkts[i]) { struct SimpHashNode *n = NODE_ENTRY(node, struct SimpHashNode, node); fn(n->strk, n->value, arg); } } } #endif /* HHASH2_H */
字符串数组作为key示例:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <limits.h> 4 #include <string.h> 5 #include "utlist.h" 6 #include "uthash.h" 7 8 #define LEN 10 9 10 typedef struct _node { 11 char key[LEN]; 12 int num; 13 UT_hash_handle hh; 14 } node; 15 16 node *bucket = NULL; 17 18 void Show() 19 { 20 node *cur = NULL; 21 node *tmp = NULL; 22 23 printf("=========== "); 24 HASH_ITER(hh, bucket, cur, tmp) { 25 printf("%d %s ", cur->num, cur->key); 26 } 27 } 28 29 int Cmp(node *a, node *b) 30 { 31 return strcmp(a->key, b->key); 32 } 33 34 int Cmp1(node *a, node *b) 35 { 36 return a->num - b->num; 37 } 38 39 int main() 40 { 41 char strs[LEN * LEN] = "o..g..d.r.h.zs.f.h.r.dz.f.r.fh."; 42 char dlip[LEN] = "."; 43 char *token = strtok(strs, dlip); 44 node *cur = NULL; 45 node *tmp = NULL; 46 47 while (token != NULL) { 48 HASH_FIND_STR(bucket, token, tmp); 49 if (tmp) { 50 tmp->num++; 51 } else { 52 tmp = (node *)malloc(sizeof(node)); 53 memset(tmp, 0, sizeof(tmp)); 54 tmp->num = 1; 55 strcpy(tmp->key, token); 56 HASH_ADD_STR(bucket, key, tmp); 57 } 58 59 token = strtok(NULL, dlip); 60 } 61 Show(); 62 63 HASH_SORT(bucket, Cmp); 64 Show(); 65 HASH_SORT(bucket, Cmp1); 66 Show(); 67 68 HASH_ITER(hh, bucket, cur, tmp) { 69 HASH_DEL(bucket, cur); 70 free(cur); 71 } 72 Show(); 73 74 return 0; 75 }