哈希表的开散列
开散列法又叫链地址法
开散列法:首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一个集合,每一个子集称为一个桶,个桶中元素通过单链表链接起来,各链表的头节点存储在哈希表中。
bucket.h
1 #pragma once
2
3 #include<stdio.h>
4 #include<stdlib.h>
5 #include<stddef.h>
6
7 #define max_size 1000
8
9 typedef enum Stat
10 {
11 Empty,
12 Valid,
13 Deleted,
14 }Stat;
15
16 typedef int KeyType;
17 typedef int HashType;
18 typedef int ValType;
19
20 typedef size_t (*HashFunc)(KeyType key);
21
22 //定义哈希链表中的元素
23 typedef struct HashElem
24 {
25 KeyType key;
26 ValType value;
27 struct HashElem* next;
28 }HashElem;
29
30 //定义哈希表
31 typedef struct HashTable
32 {
33 //如果hash桶中的链表不带头节点,就用HashElem*
34 //如果hash桶中的链表带头节点,直接用HashElem
35 HashElem* data[max_size]; //哈希表中的数组元素定义
36 size_t size; //哈希表中的元素个数
37 HashFunc func; //哈希函数
38 }HashTable;
39
40
41 //哈希表初始化
42 void HashInit(HashTable* ht, HashFunc hash_func);
43 //哈希表销毁
44 void HashDestroyNode(HashElem* p);
45 //哈希表中插入元素
46 void HashInsert(HashTable*ht, KeyType key, ValType value);
47 //哈希表中查找元素
48 int HashFind(HashTable* ht, KeyType key, ValType* value);
49 //哈希表中删除元素
50 void HashRemove(HashTable*ht, KeyType key);
51
52 size_t hash_func(keyType key);
bucket.c
1 #include"bucket.h"
2 //哈希函数
3 size_t hash_func(keyType key)
4 {
5 return (key%max_size);
6 }
7 //===========================
8 //哈希表的初始化
9 void HashInit(HashTable* ht, HashFunc hash_func)
10 {
11 if(ht==NULL)
12 {
13 return ;
14 }
15
16 ht->size=0;
17 ht->func=hash_func;
18 size_t i=0;
19 //采用不带头节点的链表
20 //将所有数组元素即链表头指针置为NULL;
21 for(;i<max_size;i++)
22 {
23 ht->data[i]=NULL;
24 }
25 return;
26 }
27 //==============================
28 //哈希表的销毁
29
30
31 void HashDestroyNode(HashElem* p)
32 {
33 free(p);
34 p=NULL;
35 }
36 void HashDestroy(HashTable* ht)
37 {
38 if(ht==NULL)
39 {
40 return ;
41 }
42 ht->size=0;
43 ht->func=NULL;
44 //遍历所有链表进行释放
45 size_t i=0;
46 for(;i<max_size;i++)
47 {
48 HashElem* cur=ht->data[i];
49 if(cur==NULL)
50 {
51 continue;
52 }
53 while(cur!=NULL)
54 {
55 HashElem* pre=cur;
56 HashDestroyNode(cur);
57 cur=pre->next;
58 }
59 return ;
60 }
61 }
62 //=========================================
63 //哈希表的插入
64
65
66 //在哈希桶中查找
67 HashElem* HashBucketFind(HashElem*head, keyType to_find)
68 {
69 HashElem* cur=head;
70 while(cur!=NULL)
71 {
72 if(cur->key==to_find)
73 {
74 return cur;
75 }
76 cur=cur->next;
77 }
78 return NULL;
79 }
80
81 HashElem* CreateNode(KeyType key, ValType value)
82 {
83 HashElem* new_node=(HashElem*)malloc(sizeof(HashElem));
84 new_node->key=key;
85 new_node->value=value;
86 new_node->next=NULL;
87 return new_node;
88 }
89
90 void HashInsert(HashTable*ht, KeyType key, ValType value)
91 {
92 if(ht==NULL)
93 {
94 return ;
95 }
96 //约定哈希表中每个链表的平均元素个数(哈希表实际元素个数/数组长度)达到10就扩容或者插入失败
97 //为了方便处理,达到10约定插入失败
98 if(ht->size>=10*max_size)
99 {
100 return ;
101 }
102
103 size_t offset=ht->hash_func(key);
104 //在对应链表中查找当前key是否存在,如果存在认为查找失败
105 HashElem* ret=HashBucketFind(ht->data[offset],key);
106 if(ret!=NULL)
107 {
108 //插入失败
109 return ;
110 }
111 else
112 {
113 //插入元素不存在,对链表进行头插
114 HashElem* new_node=CreateNode(key,value);
115 //将新元素插入到当前的链表中
116 new_node->next=ht->data[offset];
117 //更新头节点的值为新插入的元素
118 ht->data[offset]=new_node;
119 ht->size++;
120 return 1;
121 }
122 }
123 //====================================================
124 //哈希桶的元素的查找
125 //
126 int HashFind(HashTable* ht, KeyType key, ValType* value)
127 {
128 if(ht==NULL||value==NULL)
129 {
130 //非法输入
131 return 0;
132 }
133 if(ht->size==0)
134 {
135 //空表
136 return 0;
137 }
138 size_t offset=ht->hash_func(key);
139 //找到offset的链表,遍历链表查找指定的key值
140 HashElem* ret=HashBucketFind(ht->data[offset],key);
141 if(ret==NULL)
142 {
143 return 0;
144 }
145 else
146 {
147 *value=ret->value;
148 return 1;
149 }
150 }
151 //===========================================
152 //哈希表中删除删除指定Key值
153
154 int HashBucketFindEx(HashElem* head, KetType to_find, HashElem** prenode, HashElem** curnode)
155 {
156 HashElem* cur=head;
157 HashElem* pre=NULL;
158 while(cur!=NULL)
159 {
160 pre=cur;
161 if(cur->key==to_find)
162 {
163 *prenode=pre;
164 *curnode=cur;
165 return 1;
166 }
167 cur=cur->next;
168 }
169 return 0;
170 }
171 void HashRemove(HashTable* ht, KeyType key)
172 {
173 if(ht==NULL)
174 {
175 return ;
176 }
177 if(ht->size==0)
178 {
179 return ;
180 }
181 size_t offset=ht->hash_func(key);
182 //通过offset找出相应的链表,在链表中查找指定的元素并进行删除
183 HashElem* pre=NULL;
184 HashElem* cur=NULL;
185 int ret=HashBuckFindEx(ht->data[offset],key,&pre,&cur);
186 if(ret==0)
187 {
188 return ;
189 }
190 else
191 {
192 //找到了
193 if(pre==NULL)
194 {
195 //pre是cur的前一个元素,那么要删除的就是头节点
196 //必须更新头节点的指针
197 ht->data[offset]=cur->next;
198 }
199 else
200 {
201 //cur为待删除的元素,pre指向cur->next
202 pre->next=cur->next;
203 }
204 HashDestroyNode(cur);
205 --ht->size;
206 return ;
207 }
208 }