哈希表算法實現(轉)

轉自:http://blog.csdn.net/jdh99node

源碼:程序員

  1 /*********************************************************************
  2 *                           哈希表算法實現
  3 *                        (c)copyright 2013,jdh
  4 *                          All Right Reserved
  5 *文件名:main.c
  6 *程序員:jdh
  7 **********************************************************************/
  8 
  9 #include <stdio.h>
 10 #include <stdlib.h>
 11 
 12 /*********************************************************************
 13 *                            宏定義
 14 **********************************************************************/
 15 
 16 /*********************************************************************
 17 *                            數據類型重定義
 18 **********************************************************************/
 19 
 20 #define uint8_t unsigned char
 21 #define uint16_t unsigned short
 22 #define uint32_t unsigned long
 23 
 24 /*********************************************************************
 25 *                            哈希表長度
 26 **********************************************************************/
 27 
 28 #define HASH_TABLE_LEN    100
 29 
 30 /*********************************************************************
 31 *                            數據結構
 32 **********************************************************************/
 33 //鏈表節點
 34 typedef struct _Link_Node  
 35 {  
 36     uint16_t id;
 37     uint16_t data;
 38     struct _Link_Node *next;  
 39 }Link_Node,*Link_Node_Ptr; 
 40 
 41 //哈希表頭
 42 typedef struct _Hash_Header  
 43 {  
 44     struct _Link_Node *next;  
 45 }Hash_Header,*Hash_Header_Ptr;
 46 
 47 /*********************************************************************
 48 *                            全局變量
 49 **********************************************************************/
 50 
 51 //哈希表
 52 Hash_Header_Ptr Hash_Table[HASH_TABLE_LEN];
 53 
 54 /*********************************************************************
 55 *                            函數
 56 **********************************************************************/
 57 
 58 /*********************************************************************
 59 *                            哈希表函數
 60 *說明:
 61 *1.用哈希函數生成id對應的哈希表中的位置
 62 輸入:id
 63 返回:位置
 64 **********************************************************************/
 65 
 66 uint8_t hash_func(uint16_t id)
 67 {
 68     uint8_t pos = 0;
 69     
 70     pos = id % HASH_TABLE_LEN;
 71 
 72     return pos;
 73 }
 74 
 75 /*********************************************************************
 76 *                            初始化節點
 77 *返回:結點指針
 78 **********************************************************************/
 79 
 80 Link_Node_Ptr init_link_node(void)
 81 {
 82     Link_Node_Ptr node;
 83     
 84     //申請節點
 85     node = (Link_Node_Ptr) malloc(sizeof(Link_Node));
 86     //初始化長度爲0
 87     node->next = NULL;
 88     
 89     return node;
 90 }
 91 
 92 /*********************************************************************
 93 *                            初始化哈希表頭結點
 94 *返回哈希表頭結點指針
 95 **********************************************************************/
 96 
 97 Hash_Header_Ptr init_hash_header_node(void)
 98 {
 99     Hash_Header_Ptr node;
100     
101     //申請節點
102     node = (Hash_Header_Ptr) malloc(sizeof(Hash_Header));
103     //初始化長度爲0
104     node->next = NULL;
105     
106     return node;
107 }
108 
109 
110 /*********************************************************************
111 *                            哈希表初始化
112 *說明:
113 *1.初始化哈希表Hash_Table
114 *2.哈希表長度最大不能超過256
115 **********************************************************************/
116 
117 void init_hash_table(void)
118 {
119     uint8_t i = 0;
120     
121     for (i = 0;i < HASH_TABLE_LEN;i++)
122     {
123         Hash_Table[i] = init_hash_header_node();
124         Hash_Table[i]->next = NULL;
125     }
126 }
127 
128 /*********************************************************************
129 *                            在哈希表增長節點
130 *說明:
131 *1.在哈希表的某個鏈表末增長數據
132 輸入:new_node:新節點
133 **********************************************************************/
134 
135 void append_link_node(Link_Node_Ptr new_node)
136 {
137     Link_Node_Ptr node;
138     uint8_t pos = 0;
139     
140     //新節點下一個指向爲空
141     new_node->next = NULL;
142     
143     //用哈希函數得到位置
144     pos = hash_func(new_node->id);
145     
146     //判斷是否爲空鏈表
147     if (Hash_Table[pos]->next == NULL)
148     {
149         //空鏈表
150         Hash_Table[pos]->next = new_node;
151     }
152     else
153     {
154         //不是空鏈表
155         //獲取根節點
156         node = Hash_Table[pos]->next;
157     
158         //遍歷
159         while (node->next != NULL)
160         {
161             node = node->next;
162         }
163         
164         //插入
165         node->next = new_node;
166     }
167 }
168 
169 /*********************************************************************
170 *                            在哈希表查詢節點
171 *說明:
172 *1.知道在哈希表某處的單鏈表中,並開始遍歷.
173 *2.返回的是查詢節點的前一個節點指針.這麼作是爲了作刪除操做.
174 輸入:pos:哈希表數組位置,從0開始計數
175      id:所須要查詢節點的id
176      root:若是是根節點,則*root = 1,不然爲0
177 返回:所需查詢的節點的前一個節點指針,若是是根節點則返回根節點,失敗返回0
178 **********************************************************************/
179 
180 Link_Node_Ptr search_link_node(uint16_t id,uint8_t *root)
181 {
182     Link_Node_Ptr node;
183     uint8_t pos = 0;
184     
185     //用哈希函數得到位置
186     pos = hash_func(id);
187     
188     //獲取根節點
189     node = Hash_Table[pos]->next;
190     
191     //判斷單鏈表是否存在
192     if (node == NULL)
193     {
194         return 0;
195     }
196     
197     //判斷是不是根節點
198     if (node->id == id)
199     {
200         //是根節點
201         *root = 1;
202         return node;
203     }
204     else
205     {
206         //不是根節點
207         *root = 0;
208         //遍歷
209         while (node->next != NULL)
210         {
211             if (node->next->id == id)
212             {
213                 return node;
214             }
215             else
216             {
217                 node = node->next;
218             }
219         }
220         
221         return 0;
222     }
223 }
224 
225 /*********************************************************************
226 *                            在哈希表刪除節點
227 *說明:
228 *1.刪除的不是當前節點,而是當前節點後的一個節點
229 輸入:node:刪除此節點後面的一個節點
230      new_node:新節點
231 **********************************************************************/
232 
233 void delete_link_node(Link_Node_Ptr node)
234 {
235     Link_Node_Ptr delete_node;
236     
237     //重定向須要刪除的前一個節點
238     delete_node = node->next;
239     node->next = delete_node->next;
240     
241     //刪除節點
242     free(delete_node);
243     delete_node = NULL;
244 }
245 
246 /*********************************************************************
247 *                            在哈希表刪除根節點
248 輸入:node:根節點
249 **********************************************************************/
250 
251 void delete_link_root_node(Link_Node_Ptr node)
252 {
253     uint8_t pos = 0;
254     
255     //用哈希函數得到位置
256     pos = hash_func(node->id);
257     
258     //哈希表頭清空
259     if (node != NULL)
260     {
261         Hash_Table[pos]->next = node->next;
262         //刪除節點
263         free(node);
264         node = NULL;
265     }
266 }
267 
268 /*********************************************************************
269 *                            得到哈希表中全部節點數
270 輸入:node:根節點
271 **********************************************************************/
272 
273 uint16_t get_node_num(void)
274 {
275     Link_Node_Ptr node;
276     uint16_t i = 0;
277     uint16_t num = 0;
278     
279     //遍歷
280     for (i = 0;i < HASH_TABLE_LEN;i++)
281     {
282         //獲取根節點
283         node = Hash_Table[i]->next;
284         //遍歷
285         while (node != NULL)
286         {
287             num++;
288             node = node->next;
289         }
290     }
291     
292     return num;
293 }
294 
295 /*********************************************************************
296 *                            從哈希表中得到對應序號的節點
297 *參數:index:序號.從1開始,最大值爲節點總數值
298 *     root:若是是根節點,則*root = 1,不然爲0
299 返回:所需查詢的節點的前一個節點指針,若是是根節點則返回根節點,失敗返回0
300 **********************************************************************/
301 
302 Link_Node_Ptr get_node_from_index(uint16_t index,uint8_t *root)
303 {   
304     Link_Node_Ptr node;
305     uint16_t i = 0;
306     uint16_t num = 0;
307     
308     //遍歷
309     for (i = 0;i < HASH_TABLE_LEN;i++)
310     {
311         //獲取根節點
312         node = Hash_Table[i]->next;
313         //判斷單鏈表是否存在
314         if (node == NULL)
315         {
316             continue;
317         }
318         
319         //根節點
320         num++;
321         if (num == index)
322         {
323             //是根節點
324             *root = 1;
325             return node; 
326         }
327         
328         //遍歷
329         while (node->next != NULL)
330         {
331             num++;
332             if (num == index)
333             {
334                 //不是根節點
335                 *root = 0;
336                 return node; 
337             }
338             node = node->next;
339         }
340     }
341     
342     return 0;
343 }
344 
345 /*********************************************************************
346 *                            刪除hash表中全部節點
347 **********************************************************************/
348 
349 void drop_hash()
350 {
351     Link_Node_Ptr node;
352     uint16_t i = 0;
353     Link_Node_Ptr node_next;
354     
355     //遍歷
356     for (i = 0;i < HASH_TABLE_LEN;i++)
357     {
358         //獲取根節點
359         node = Hash_Table[i]->next;
360         
361         while (1)
362         {
363             //判斷單鏈表是否存在
364             if (node == NULL)
365             {
366                 //不存在
367                 Hash_Table[i]->next = NULL;
368                 break;
369             }
370             
371             //根節點下一個節點
372             node_next = node->next;
373             //刪除根節點
374             free(node);
375             //重指定根節點
376             node = node_next;
377         }
378     }
379 }
380 
381 /*********************************************************************
382 *                            輸出全部節點
383 **********************************************************************/
384 
385 void printf_hash()
386 {
387     Link_Node_Ptr node;
388     uint8_t root = 0;
389     uint8_t i = 0;
390     uint8_t num = 0;
391     
392     printf("-------------打印hash表-------------\n");
393     
394     num = get_node_num();
395     for (i = 1;i <= num;i++)
396     {
397         node = get_node_from_index(i,&root);
398         if (node != 0)
399         {
400             if (root)
401             {
402                 printf("根節點:節點號%d,id爲%d\n",i,node->id);
403             }
404             else
405             {
406                 printf("普通節點:節點號%d,id爲%d\n",i,node->next->id);
407             }
408         }
409     }
410 }
411 
412 /*********************************************************************
413 *                            主函數
414 *說明:實現對哈希表的新建,創建節點,查詢及增長,刪除節點的操做
415 **********************************************************************/
416 
417 int main()
418 {
419     Link_Node_Ptr node;
420     uint8_t temp = 0;
421     uint8_t root = 0;
422     uint8_t i = 0;
423     
424     init_hash_table();
425     
426     //插入數據id = 1,data = 2;
427     node = init_link_node();
428     node->id = 1;
429     node->data = 2;
430     append_link_node(node);
431     
432     //查詢節點數
433     printf("1節點數爲%d\n",get_node_num());
434     
435     node = init_link_node();
436     node->id = 100;
437     node->data = 101;
438     append_link_node(node);
439     
440     node = init_link_node();
441     node->id = 1002;
442     node->data = 1001;
443     append_link_node(node);
444     
445     node = init_link_node();
446     node->id = 10000;
447     node->data = 10001;
448     append_link_node(node);
449     
450     node = init_link_node();
451     node->id = 1000;
452     node->data = 10001;
453     append_link_node(node);
454     
455     node = init_link_node();
456     node->id = 2;
457     node->data = 10001;
458     append_link_node(node);
459     
460     //查詢節點數
461     printf("2節點數爲%d\n",get_node_num());
462     
463     //查詢id = 1000;
464     node = search_link_node(100,&temp);
465     if (node != 0)
466     {
467         if (temp == 0)
468         {
469             printf("刪除普通節點:所需查詢id的值爲%d,數據爲%d\n",node->next->id,node->next->data);
470             
471             //刪除
472             delete_link_node(node);
473         }
474         else
475         {
476             //根節點
477             printf("刪除根節點所需查詢id的值爲%d,數據爲%d\n",node->id,node->data);
478             
479             //刪除
480             delete_link_root_node(node);
481         }
482     }
483     else
484     {
485         printf("查詢失敗\n");
486     }
487     
488     //查詢id = 1000;
489     node = search_link_node(1001,&temp);
490     if (node != 0)
491     {
492         if (temp == 0)
493         {
494             printf("所需查詢id的值爲%d\n",node->next->data);
495         }
496         else
497         {
498             //根節點
499             printf("所需查詢id的值爲%d\n",node->data);
500         }
501     }
502     else
503     {
504         printf("查詢失敗\n");
505     }
506     
507     //查詢節點數
508     printf("節點數爲%d\n",get_node_num());
509     
510     printf_hash();
511     
512     
513     getchar();
514     return 0;
515 }
相關文章
相關標籤/搜索