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

  1 #include <stdint.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 
  6 #define HASH_BUCKET_MAX (1024)
  7 #define HASH_BUCKET_CAPACITY_MAX (256)
  8 #define HASHTABLE_DEBUG
  9 #define TRUE  1
 10 #define FALSE 0
 11 
 12 #ifdef HASHTABLE_DEBUG
 13 #define DEBUG(format, ...) printf("[%s] [%d] : "format"\n", __FUNCTION__, __LINE__, __VA_ARGS__)
 14 #else
 15 #define DEBUG(format, ...)
 16 #endif
 17 
 18 struct hash_bucket {
 19     int                capacity;  /* 桶的容量 */
 20     void               *hkey;     /* hashtable的key */
 21     void               *hdata;    /* hashtable的data */
 22     struct hash_bucket *prev;
 23     struct hash_bucket *next;
 24     struct hash_bucket *tail;
 25 };
 26 
 27 struct hash {
 28     uint32_t            (*hash_key)(void *);
 29     int                 (*hash_cmp)(const void *, const void*, int len);
 30     struct hash_bucket* bucket[HASH_BUCKET_MAX];
 31 };
 32 
 33 uint32_t string_hash_key(void* str);
 34 int string_hash_cmp(const void* src, const void* dst);
 35 
 36 static struct hash *g_htable = NULL;
 37 
 38 void hash_create();
 39 void *hash_lookup(void *key);
 40 int  hash_add(void *key, void* data);
 41 int  hash_delete(void *key);
 42 void hash_destroy();
 43 void hash_iter_print();
 44 
 45 #define  bucket_free(bucket) \
 46     free(bucket->hkey);      \
 47     free(bucket->hdata);     \
 48     free(bucket);            \
 49     bucket = NULL;
 50 
 51 uint32_t string_hash_key(void* str) {
 52     char *tmp = (char *)str;
 53     uint32_t key = 0;
 54     while(*tmp)
 55         key = (key * 33) ^ (uint32_t)(tmp++);
 56 
 57     DEBUG("string key : %u, index : %d", key, key%HASH_BUCKET_MAX);
 58 
 59     return key%HASH_BUCKET_MAX;
 60 }
 61 
 62 int string_hash_cmp(const void* src, const void* dst, int len) {
 63     if (!src || !dst) {
 64         DEBUG("src addr: %p, dst addr: %p", src, dst);
 65         return -1;
 66     }
 67     return strncmp((char *)src, (char *)dst, len);
 68 }
 69 
 70 void hash_create() {
 71     if (g_htable) {
 72         DEBUG("the default hashtable is already created");
 73         return;
 74     }
 75     
 76     g_htable = (struct hash *)malloc(sizeof(struct hash));
 77     if (!g_htable) {
 78         DEBUG("memory alloc failed.");
 79         return;
 80     }
 81 
 82     memset(g_htable, 0, sizeof(struct hash));
 83 
 84     g_htable->hash_key = string_hash_key;
 85     g_htable->hash_cmp = string_hash_cmp;
 86 
 87     return;
 88 }
 89 
 90 static void bucket_delete(struct hash_bucket** ptr) {
 91     struct hash_bucket *bucket = *ptr;
 92     struct hash_bucket *tmp;
 93 
 94     while(bucket) {
 95         tmp = bucket;
 96         bucket = bucket->next;
 97         bucket_free(tmp);
 98     }
 99 }
100 
101 void hash_destroy() {
102     if (g_htable) {
103         for(int i=0; i<HASH_BUCKET_MAX; i++) {
104             if (g_htable->bucket[i]) {
105                 bucket_delete(&g_htable->bucket[i]);
106             }
107         }
108         
109         free(g_htable);
110         g_htable = NULL;
111     }
112     return;
113 }
114 
115 #define  lru_bucket_move(bucket,  head)   \
116     bucket->next = head;                  \
117     bucket->prev = NULL;                  \
118     bucket->capacity = head->capacity;    \
119                                           \
120     head->prev = bucket;                  \
121     head->tail = NULL;    
122 
123 void *hash_lookup(void *key) {
124     if (!key) {
125         DEBUG("input para is NULL\n");
126         return NULL;
127     }
128 
129     uint32_t index = g_htable->hash_key(key);
130     struct hash_bucket* head = g_htable->bucket[index];
131     struct hash_bucket* bucket = head;
132 
133     while(bucket) {
134         if (0 == g_htable->hash_cmp(key, bucket->hkey, strlen((char*)key))) {
135             if (head != bucket && bucket != head->tail) {
136                 bucket->prev->next = bucket->next;
137                 bucket->next->prev = bucket->prev;
138                 bucket->tail = head->tail;
139 
140                 lru_bucket_move(bucket, head);
141             } else if (bucket == head->tail && head->capacity>1) {
142                 bucket->prev->next = NULL;
143                 bucket->tail = bucket->prev;
144 
145                 lru_bucket_move(bucket, head);
146             }
147             g_htable->bucket[index] = bucket;
148             return bucket->hdata;
149         }
150         bucket = bucket->next;
151     }
152     return NULL;
153 }
154 
155 int hash_add(void *key, void* data) {
156     if (!key || !data) {
157         DEBUG("input para is NULL\n");
158         return FALSE;
159     }
160 
161     uint32_t index = g_htable->hash_key(key);
162     struct hash_bucket* head = g_htable->bucket[index];
163 
164     if (!head) {
165         head = (struct hash_bucket*)malloc(sizeof(struct hash_bucket));
166         if (!head) {
167             DEBUG("no memory for more hash_bucket\n");
168             return FALSE;
169         }
170 
171         memset(head, 0, sizeof(*head));
172         head->capacity++;
173         
174         head->hkey  = strdup((char *)key);
175         head->hdata = strdup((char *)data);        
176         head->tail  = head;
177         g_htable->bucket[index] = head;
178         return TRUE;
179     }
180 
181     int capacity = head->capacity;
182     struct hash_bucket *new_bucket = 
183         (struct hash_bucket *)malloc(sizeof(struct hash_bucket)); 
184 
185     if (!new_bucket) {
186         DEBUG("no memory for more hash_bucket\n");
187         return FALSE;
188     }
189 
190     if (capacity >= HASH_BUCKET_CAPACITY_MAX) {
191         struct hash_bucket *tail = head->tail;
192         head->tail = tail->prev;
193 
194         tail->prev->next = NULL;
195         bucket_free(tail);
196     } 
197     
198     head->prev = new_bucket;
199     new_bucket->next = head;
200     new_bucket->capacity = capacity + 1;
201     new_bucket->tail = head->tail;
202     head->tail = NULL;
203 
204     head->hkey  = strdup((char *)key);
205     head->hdata = strdup((char *)data);
206     
207     g_htable->bucket[index] = new_bucket;
208     
209     return TRUE;
210 }
211 
212 int hash_delete(void *key) {
213     if (!key) {
214         DEBUG("input para is NULL\n");
215         return FALSE;
216     }
217 
218     uint32_t index = g_htable->hash_key(key);
219     struct hash_bucket* head = g_htable->bucket[index];
220     struct hash_bucket* bkt = head;
221 
222     while(bkt) {
223         if (0 == g_htable->hash_cmp(key, bkt->hkey, strlen((char*)key))) {
224             if (head != bkt && bkt != head->tail) {
225                 bkt->prev->next = bkt->next;
226                 bkt->next->prev = bkt->prev;
227 
228             } else if (bkt == head->tail && head->capacity>1) {
229                 bkt->prev->next = NULL;
230                 bkt->tail = bkt->prev;
231 
232             } else {
233                 if (bkt->next) {
234                     bkt->next->tail = bkt->tail;
235                     bkt->next->capacity = bkt->capacity;
236                     bkt->next->prev = NULL;
237                     g_htable->bucket[index] = bkt->next;
238                 } else {
239                     g_htable->bucket[index] = NULL;
240                 }
241             }
242 
243             bucket_free(bkt);
244             if (g_htable->bucket[index]) {
245                 g_htable->bucket[index]->capacity--;
246             }
247             
248             return TRUE;
249         }
250         bkt = bkt->next;
251     }
252     return FALSE;
253 }
254 
255 static void bucket_print(struct hash_bucket** ptr) {
256     struct hash_bucket *bkt = *ptr;
257     struct hash_bucket *tmp;
258 
259     while(bkt) {
260         printf("key=[%s],data=[%s]\n", (char*)bkt->hkey, (char*)bkt->hdata);
261         bkt = bkt->next;
262     }
263 }
264 
265 void hash_iter_print() {
266     if (g_htable) {
267         for(int i=0; i<HASH_BUCKET_MAX; i++) {
268             if (g_htable->bucket[i]) {
269                 bucket_print(&g_htable->bucket[i]);
270             }
271         }
272     }
273 }
274 
275 int main(int argc, char* argv[]) {
276     hash_create();
277 
278     hash_add("first", "danxi");
279     hash_add("second", "test");
280     hash_add("three", "sad code");
281     hash_add("four", "let's go");
282 
283     hash_iter_print();
284 
285     char * t1 = (char *)hash_lookup("first");
286     char * t2 = (char *)hash_lookup("second");
287 
288     printf("%s  %s \n", t1, t2);
289     printf("%s \n", (char*)hash_lookup("four"));
290 
291     hash_delete("four");
292     hash_iter_print();
293     hash_destroy();
294 
295     return 0;
296 }

 

posted @ 2017-04-20 09:59  丹西  阅读(911)  评论(0编辑  收藏  举报