哈希表算法实现(转)

转自:http://blog.csdn.net/jdh99

源码:

  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表-------------
");
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
",i,node->id);
403             }
404             else
405             {
406                 printf("普通节点:节点号%d,id为%d
",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
",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
",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
",node->next->id,node->next->data);
470             
471             //删除
472             delete_link_node(node);
473         }
474         else
475         {
476             //根节点
477             printf("删除根节点所需查询id的值为%d,数据为%d
",node->id,node->data);
478             
479             //删除
480             delete_link_root_node(node);
481         }
482     }
483     else
484     {
485         printf("查询失败
");
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
",node->next->data);
495         }
496         else
497         {
498             //根节点
499             printf("所需查询id的值为%d
",node->data);
500         }
501     }
502     else
503     {
504         printf("查询失败
");
505     }
506     
507     //查询节点数
508     printf("节点数为%d
",get_node_num());
509     
510     printf_hash();
511     
512     
513     getchar();
514     return 0;
515 }
原文地址:https://www.cnblogs.com/fwst/p/4234191.html