c语言实现带LRU机制的哈希表

 

 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #define HASH_BUCKET_MAX (1024)
 #define HASH_BUCKET_CAPACITY_MAX (256)
 #define HASHTABLE_DEBUG
 #define TRUE  1
 #define FALSE 0
 
 #ifdef HASHTABLE_DEBUG
 #define DEBUG(format, ...) printf("[%s] [%d] : "format"\n", __FUNCTION__, __LINE__, __VA_ARGS__)
 #else
 #define DEBUG(format, ...)
 #endif
 
 struct hash_bucket {
     int                capacity;  /* 桶的容量 */
     void               *hkey;     /* hashtable的key */
     void               *hdata;    /* hashtable的data */
     struct hash_bucket *prev;
     struct hash_bucket *next;
     struct hash_bucket *tail;
 };
 
 struct hash {
     uint32_t            (*hash_key)(void *);
     int                 (*hash_cmp)(const void *, const void*, int len);
     struct hash_bucket* bucket[HASH_BUCKET_MAX];
 };
 
 uint32_t string_hash_key(void* str);
 int string_hash_cmp(const void* src, const void* dst);
 
 static struct hash *g_htable = NULL;
 
 void hash_create();
 void *hash_lookup(void *key);
 int  hash_add(void *key, void* data);
 int  hash_delete(void *key);
 void hash_destroy();
 void hash_iter_print();
 
 #define  bucket_free(bucket) \
     free(bucket->hkey);      \
     free(bucket->hdata);     \
     free(bucket);            \
     bucket = NULL;
 
 uint32_t string_hash_key(void* str) {
     char *tmp = (char *)str;
     uint32_t key = 0;
     while(*tmp)
         key = (key * 33) ^ (uint32_t)(tmp++);
 
     DEBUG("string key : %u, index : %d", key, key%HASH_BUCKET_MAX);
 
     return key%HASH_BUCKET_MAX;
 }
 
 int string_hash_cmp(const void* src, const void* dst, int len) {
     if (!src || !dst) {
         DEBUG("src addr: %p, dst addr: %p", src, dst);
         return -1;
     }
     return strncmp((char *)src, (char *)dst, len);
 }
 
 void hash_create() {
     if (g_htable) {
         DEBUG("the default hashtable is already created");
         return;
     }
     
     g_htable = (struct hash *)malloc(sizeof(struct hash));
     if (!g_htable) {
         DEBUG("memory alloc failed.");
         return;
     }
 
     memset(g_htable, 0, sizeof(struct hash));
 
     g_htable->hash_key = string_hash_key;
     g_htable->hash_cmp = string_hash_cmp;
 
     return;
 }
 
 static void bucket_delete(struct hash_bucket** ptr) {
     struct hash_bucket *bucket = *ptr;
     struct hash_bucket *tmp;
 
     while(bucket) {
         tmp = bucket;
         bucket = bucket->next;
         bucket_free(tmp);
     }
 }
 
 void hash_destroy() {
     if (g_htable) {
         for(int i=0; i<HASH_BUCKET_MAX; i++) {
             if (g_htable->bucket[i]) {
                 bucket_delete(&g_htable->bucket[i]);
             }
         }
         
         free(g_htable);
         g_htable = NULL;
     }
     return;
 }
 
 #define  lru_bucket_move(bucket,  head)   \
     bucket->next = head;                  \
     bucket->prev = NULL;                  \
     bucket->capacity = head->capacity;    \
                                           \
     head->prev = bucket;                  \
     head->tail = NULL;    
 
 void *hash_lookup(void *key) {
     if (!key) {
         DEBUG("input para is NULL\n");
         return NULL;
     }
 
     uint32_t index = g_htable->hash_key(key);
     struct hash_bucket* head = g_htable->bucket[index];
     struct hash_bucket* bucket = head;
 
     while(bucket) {
         if (0 == g_htable->hash_cmp(key, bucket->hkey, strlen((char*)key))) {
             if (head != bucket && bucket != head->tail) {
                 bucket->prev->next = bucket->next;
                 bucket->next->prev = bucket->prev;
                 bucket->tail = head->tail;
 
                 lru_bucket_move(bucket, head);
             } else if (bucket == head->tail && head->capacity>1) {
                 bucket->prev->next = NULL;
                 bucket->tail = bucket->prev;
 
                 lru_bucket_move(bucket, head);
             }
             g_htable->bucket[index] = bucket;
             return bucket->hdata;
         }
         bucket = bucket->next;
     }
     return NULL;
 }
 
 int hash_add(void *key, void* data) {
     if (!key || !data) {
         DEBUG("input para is NULL\n");
         return FALSE;
     }
 
     uint32_t index = g_htable->hash_key(key);
     struct hash_bucket* head = g_htable->bucket[index];
 
     if (!head) {
         head = (struct hash_bucket*)malloc(sizeof(struct hash_bucket));
         if (!head) {
             DEBUG("no memory for more hash_bucket\n");
             return FALSE;
         }
 
         memset(head, 0, sizeof(*head));
         head->capacity++;
         
         head->hkey  = strdup((char *)key);
         head->hdata = strdup((char *)data);        
         head->tail  = head;
         g_htable->bucket[index] = head;
         return TRUE;
     }
 
     int capacity = head->capacity;
     struct hash_bucket *new_bucket = 
         (struct hash_bucket *)malloc(sizeof(struct hash_bucket)); 
 
     if (!new_bucket) {
         DEBUG("no memory for more hash_bucket\n");
         return FALSE;
     }
 
     if (capacity >= HASH_BUCKET_CAPACITY_MAX) {
         struct hash_bucket *tail = head->tail;
         head->tail = tail->prev;
 
         tail->prev->next = NULL;
         bucket_free(tail);
     } 
     
     head->prev = new_bucket;
     new_bucket->next = head;
     new_bucket->capacity = capacity + 1;
     new_bucket->tail = head->tail;
     head->tail = NULL;
 
     head->hkey  = strdup((char *)key);
     head->hdata = strdup((char *)data);
     
     g_htable->bucket[index] = new_bucket;
     
     return TRUE;
 }
 
 int hash_delete(void *key) {
     if (!key) {
         DEBUG("input para is NULL\n");
         return FALSE;
     }
 
     uint32_t index = g_htable->hash_key(key);
     struct hash_bucket* head = g_htable->bucket[index];
     struct hash_bucket* bkt = head;
 
     while(bkt) {
         if (0 == g_htable->hash_cmp(key, bkt->hkey, strlen((char*)key))) {
             if (head != bkt && bkt != head->tail) {
                 bkt->prev->next = bkt->next;
                 bkt->next->prev = bkt->prev;
 
             } else if (bkt == head->tail && head->capacity>1) {
                 bkt->prev->next = NULL;
                 bkt->tail = bkt->prev;
 
             } else {
                 if (bkt->next) {
                     bkt->next->tail = bkt->tail;
                     bkt->next->capacity = bkt->capacity;
                     bkt->next->prev = NULL;
                     g_htable->bucket[index] = bkt->next;
                 } else {
                     g_htable->bucket[index] = NULL;
                 }
             }
 
             bucket_free(bkt);
             if (g_htable->bucket[index]) {
                 g_htable->bucket[index]->capacity--;
             }
             
             return TRUE;
         }
         bkt = bkt->next;
     }
     return FALSE;
 }
 
 static void bucket_print(struct hash_bucket** ptr) {
     struct hash_bucket *bkt = *ptr;
     struct hash_bucket *tmp;
 
     while(bkt) {
         printf("key=[%s],data=[%s]\n", (char*)bkt->hkey, (char*)bkt->hdata);
         bkt = bkt->next;
     }
 }
 
 void hash_iter_print() {
     if (g_htable) {
         for(int i=0; i<HASH_BUCKET_MAX; i++) {
             if (g_htable->bucket[i]) {
                 bucket_print(&g_htable->bucket[i]);
             }
         }
     }
 }
 
 int main(int argc, char* argv[]) {
     hash_create();
 
     hash_add("first", "danxi");
     hash_add("second", "test");
     hash_add("three", "sad code");
     hash_add("four", "let's go");
 
     hash_iter_print();
 
     char * t1 = (char *)hash_lookup("first");
     char * t2 = (char *)hash_lookup("second");
 
     printf("%s  %s \n", t1, t2);
     printf("%s \n", (char*)hash_lookup("four"));
 
     hash_delete("four");
     hash_iter_print();
     hash_destroy();
 
     return 0;
 }

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值