Fork me on GitHub

数据结构与算法——哈希表

1. 什么是哈希表

首先有这么一种情况,有24个人编号分别为1~24,我们需要将 24 人均分成 6 个组!

编号除 6 余数为 0 的为第零组: 6、12、18、24

编号除 6 余数为 1 的为第一组: 1、7、13、19

编号除 6 余数为 2 的为第二组: 2、8、14、20

编号除 6 余数为 3 的为第三组: 3、9、15、21

编号除 6 余数为 4 的为第四组: 4、10、16、22

编号除 6 余数为 5 的为第五组: 5、11、17、23

通过这种编号方式划分队列,寻找某一个数会非常方便,比如寻找19,19 % 6 = 1,19再第一组。这种编号的方式就是高效的散列,我们俗称 “哈希”

以上过程是通过把关键码值 key(编号)映射到表中一个位置(数组的下标)来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希表 - 散列表,它是基于快速存取的角度设计的,也是一种典型的 “空间换时间” 的做法

 

键(key): 组员的编号 如, 1 、 5 、 19 。 。 。

值(value): 组员的其它信息(包含 性别、年龄和战斗力等)

索引: 数组的下标(0,1,2,3,4) ,用以快速定位和检索数据

哈希桶: 保存索引值的数组(或链表),数组(或链表)成员为每一个索引值相同的多个元素(以链表的形式链接)的首节点

哈希函数: 将组员编号映射到索引上,采用求余法 ,如: 组员编号 19

 

 下面是代码实现,先贴一张运行结果

 

 

2. 哈希表的算法实现

2.1 哈希表数据结构的定义

 1 #define DEFAULT_SIZE 16
 2 
 3 typedef struct _ListNode
 4 {
 5     struct _ListNode *next;
 6     int key;
 7     void *data;
 8 }ListNode;
 9 
10 typedef ListNode *List;
11 typedef ListNode *Element;
12 
13 typedef struct _HashTable
14 {
15     int TableSize;
16     List *Thelists;
17 }HashTable;

 

 2.2 哈希函数

1 /*根据 key 计算索引,定位 Hash 桶的位置*/
2 int Hash(int key, int TableSize)
3 {
4     //return (key % TableSize);
5     return (key % 6);
6 }

 

 

2.3 哈希链表初始化

 1 /*初始化哈希表*/
 2 HashTable* InitHash(int TableSize)
 3 {
 4     int i = 0;
 5     HashTable* hTable = NULL;
 6     if (TableSize <= 0)
 7     {
 8         TableSize = DEFAULT_SIZE;
 9     }
10     hTable = (HashTable*)malloc(sizeof(HashTable));
11     if (NULL == hTable)
12     {
13         printf("HashTable malloc error.\n");
14         return NULL;
15     }
16     hTable->TableSize = TableSize;
17 
18     //为一连窜的 Hash 桶首地址分配内存空间,其为一个指针数组
19     hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
20     if (NULL == hTable->Thelists)
21     {
22         printf("HashTable malloc error\n");
23         free(hTable);
24         return NULL;
25     }
26 
27     //为每一个 Hash 桶内对应的指针数组初始化链表节点
28     for (i = 0; i < TableSize; i++)
29     {
30         hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
31         if (NULL == hTable->Thelists[i])
32         {
33             printf("HashTable malloc error\n");
34             free(hTable->Thelists);
35             free(hTable);
36             return NULL;
37         }
38         else
39         {
40             memset(hTable->Thelists[i], 0, sizeof(ListNode));
41         }
42     }
43     return hTable;
44 }

 

 

2.4 哈希链表插入元素

 1 /*哈希表插入元素,元素为键值对*/
 2 void Insert(HashTable* HashTable, int key, void* value)
 3 {
 4     Element e = NULL, tmp = NULL;
 5     List L = NULL;
 6     e = Find(HashTable, key);
 7     if (NULL == e)
 8     {
 9         tmp = (Element)malloc(sizeof(ListNode));
10         if (NULL == tmp)
11         {
12             printf("malloc error\n");
13             return;
14         }
15         //定位哈希桶
16         L = HashTable->Thelists[Hash(key, HashTable->TableSize)];
17         tmp->data = value;
18         tmp->key = key;
19         tmp->next = L->next;        //前插法, 将新元素插到哈希桶的前部
20         L->next = tmp;
21     }
22     else
23     {
24         //如果元素存在,不做修改
25         //printf("the key already exist\n");
26 
27         //如果Key存在,修改Key的值
28         e->data = value;
29     }
30 }

 

 

2.5 哈希链表查找元素

 1 /*从哈希表中根据键值查找元素*/
 2 Element Find(HashTable *HashTable, int key)
 3 {
 4     int i = 0;
 5     List L = NULL;
 6     Element e = NULL;
 7     i = Hash(key, HashTable->TableSize);
 8     L = HashTable->Thelists[i];
 9     e = L->next;
10     while (e != NULL && e->key != key)
11     e = e->next;
12     return e;
13 }

 

2.6 哈希链表删除元素

 1 /*哈希表删除元素,元素为键值对*/
 2 void Delete(HashTable *HashTable, int key )
 3 {
 4     Element e=NULL, last=NULL;
 5     List L=NULL;
 6     int i = Hash(key, HashTable->TableSize);
 7     L = HashTable->Thelists[i];
 8     last = L;
 9     e = L->next;
10     
11     while (e != NULL && e->key != key)
12     {
13         last = e;
14         e = e->next;
15     }
16     if(e)    //如果键值对存在
17     {
18         last->next = e->next;
19         delete(e);
20     }
21 }

 

 

3. 完整源码实现(链式存储)

hash_table.h

 1 #pragma once
 2 
 3 #define DEFAULT_SIZE 16
 4 
 5 /*哈希表元素定义*/
 6 typedef struct _ListNode
 7 {
 8     struct _ListNode* next;
 9     int key;
10     void* data;
11 }ListNode;
12 
13 typedef ListNode* List;
14 typedef ListNode* Element;
15 
16 /*哈希表结构定义*/
17 typedef struct _HashTable
18 {
19     int TableSize;
20     List* Thelists;
21 }HashTable;
22 
23 /*哈希函数*/
24 int Hash(void* key, int TableSize);
25 
26 /*初始化哈希表*/
27 HashTable* InitHash(int TableSize);
28 
29 /*哈希表插入*/
30 void Insert(HashTable* HashTable, int key, void* value);
31 
32 /*哈希表查找*/
33 Element Find(HashTable* HashTable, int key);
34 
35 /*哈希表销毁*/
36 void Destory(HashTable* HashTable);
37 
38 /*哈希表元素中提取数据*/
39 void* Retrieve(Element e);

 

 

 

hash_table.c

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include "hash_table.h"
  5 
  6 /*根据 key 计算索引,定位 Hash 桶的位置*/
  7 int Hash(int key, int TableSize)
  8 {
  9     //return (key % TableSize);
 10     return (key % 6);
 11 }
 12 
 13 /*初始化哈希表*/
 14 HashTable* InitHash(int TableSize)
 15 {
 16     int i = 0;
 17     HashTable* hTable = NULL;
 18     if (TableSize <= 0)
 19     {
 20         TableSize = DEFAULT_SIZE;
 21     }
 22 
 23 
 24     hTable = (HashTable*)malloc(sizeof(HashTable));
 25     if (NULL == hTable)
 26     {
 27         printf("HashTable malloc error.\n");
 28         return NULL;
 29     }
 30     hTable->TableSize = TableSize;
 31 
 32     //为一连窜的 Hash 桶首地址分配内存空间,其为一个指针数组
 33     hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
 34     if (NULL == hTable->Thelists)
 35     {
 36         printf("HashTable malloc error\n");
 37         free(hTable);
 38         return NULL;
 39     }
 40 
 41     //为每一个 Hash 桶内对应的指针数组初始化链表节点
 42     for (i = 0; i < TableSize; i++)
 43     {
 44         hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
 45         if (NULL == hTable->Thelists[i])
 46         {
 47             printf("HashTable malloc error\n");
 48             free(hTable->Thelists);
 49             free(hTable);
 50             return NULL;
 51         }
 52         else
 53         {
 54             memset(hTable->Thelists[i], 0, sizeof(ListNode));
 55         }
 56     }
 57     return hTable;
 58 }
 59 
 60 /*从哈希表中根据键值查找元素*/
 61 Element Find(HashTable* HashTable, int key)
 62 {
 63     int i = 0;
 64     List L = NULL;
 65     Element e = NULL;
 66     i = Hash(key, HashTable->TableSize);
 67     L = HashTable->Thelists[i];
 68     e = L->next;
 69 
 70     while (e != NULL && e->key != key)
 71         e = e->next;
 72 
 73     return e;
 74 }
 75 
 76 /*哈希表插入元素,元素为键值对*/
 77 void Insert(HashTable* HashTable, int key, void* value)
 78 {
 79     Element e = NULL, tmp = NULL;
 80     List L = NULL;
 81     e = Find(HashTable, key);
 82     if (NULL == e)
 83     {
 84         tmp = (Element)malloc(sizeof(ListNode));
 85         if (NULL == tmp)
 86         {
 87             printf("malloc error\n");
 88             return;
 89         }
 90         //定位哈希桶
 91         L = HashTable->Thelists[Hash(key, HashTable->TableSize)];
 92         tmp->data = value;
 93         tmp->key = key;
 94         tmp->next = L->next;        //前插法, 将新元素插到哈希桶的前部
 95         L->next = tmp;
 96     }
 97     else
 98     {
 99         //如果元素存在,不做修改
100         //printf("the key already exist\n");
101 
102         //如果Key存在,修改Key的值
103         e->data = value;
104     }
105         
106 
107 }
108 
109 /*哈希表删除元素,元素为键值对*/
110 void Delete(HashTable* HashTable, int key)
111 {
112     Element e = NULL, last = NULL;
113     List L = NULL;
114     int i = Hash(key, HashTable->TableSize);
115     L = HashTable->Thelists[i];
116     last = L;
117     e = L->next;
118 
119     while (e != NULL && e->key != key)
120     {
121         last = e;
122         e = e->next;
123     }
124     if (e)        //如果键值对存在
125     {
126         last->next = e->next;
127         free(e);
128     }
129 }
130 
131 /*哈希表元素中提取数据*/
132 void* Retrieve(Element e)
133 {
134     return e ? e->data : NULL;
135 }
136 
137 /*销毁哈希表*/
138 void Destory(HashTable* HashTable)
139 {
140     int i = 0;
141     List L = NULL;
142     Element cur = NULL, next = NULL;
143     for (i = 0; i < HashTable->TableSize; i++)
144     {
145         L = HashTable->Thelists[i];
146         cur = L->next;
147         while (cur != NULL)
148         {
149             next = cur->next;
150             free(cur);
151             cur = next;
152         }
153         free(L);
154     }
155     free(HashTable->Thelists);
156     free(HashTable);
157 }
158 
159 void main(void)
160 {
161     char* elems[] = 
162     { 
163         "字符串1","字符串2","字符串3","字符串4","字符串5","字符串6",
164         "字符串7","字符串8","字符串9","字符串10","字符串11","字符串12",
165         "字符串13","字符串14","字符串15","字符串16","字符串17","字符串18",
166         "字符串19","字符串20","字符串21","字符串22","字符串23","字符串24" 
167     };
168 
169     HashTable* HashTable;
170     HashTable = InitHash(24);
171 
172     for (int i = 0; i < HashTable->TableSize; i++)
173     {
174         Insert(HashTable, i + 1, elems[i]);
175     }
176     
177     for (int i = 1; i <= HashTable->TableSize; i++)
178     {
179         Element e = Find(HashTable, i);
180         if (e)
181         {
182             printf("K为:[%d]", i);
183             printf("所在哈希桶:[%d] ,参数:", i % 6);
184             printf("%s\n", (const char*)Retrieve(e));
185         }
186         else
187         {
188             printf("Not found [key:%d]\n", i);
189         }
190     }
191 
192     printf("\n\n删除Key能被5整除的内容\n\n");
193     for (int i = 0; i <= HashTable->TableSize; i++)
194     {
195         if (i != 0 && i % 5 == 0)
196         {
197             Delete(HashTable, i);
198         }
199     }
200 
201     for (int i = 1; i <= HashTable->TableSize; i++)
202     {
203         Element e = Find(HashTable, i);
204         if (e)
205         {
206             printf("K为:[%d]", i);
207             printf("所在哈希桶:[%d] ,参数:", i % 6);
208             printf("%s\n", (const char*)Retrieve(e));
209         }
210         else
211         {
212             printf("Not found [key:%d]\n", i);
213         }
214     }
215 
216     printf("\n\n将Key能被3整除的内容改为:888888\n\n");
217     for (int i = 0; i <= HashTable->TableSize; i++)
218     {
219         if (i != 0 && i % 3 == 0)
220         {
221             Insert(HashTable, i, "888888");
222         }
223     }
224 
225     for (int i = 1; i <= HashTable->TableSize; i++)
226     {
227         Element e = Find(HashTable, i);
228         if (e)
229         {
230             printf("K为:[%d]", i);
231             printf("所在哈希桶:[%d] ,参数:", i % 6);
232             printf("%s\n", (const char*)Retrieve(e));
233         }
234         else
235         {
236             printf("Not found [key:%d]\n", i);
237         }
238     }
239 
240     system("pause");
241 }

  

 

 

 

 

================================================================================================================================

posted @ 2021-05-02 00:25  索智源  阅读(297)  评论(0编辑  收藏  举报