上一篇博客写了基于线性探测实现哈希表的一些方法,但若是负载因子较大时,哈希表的查找数据效率还是会很低,下面将使用开散列来实现哈希表的一些操作
例如:数据集合{10,51,14,33,18,29},哈希函数Hash(key) = key%m(m为内存单元的个数,可以自定义),在这里定义为10
3 #define HashMaxSize 1000
4 typedef int KeyType;
5 typedef int ValueType;
6 typedef size_t (*HashFunc)(KeyType key);
7
8 typedef enum
9 {
10 Empty,//空状态
11 Valid,//有效状态
12 Delete,//被删改的状态
13 }Stat;
14
15 typedef struct HashElem
16 {
17 KeyType key;
18 ValueType value;
19 struct HashElem* next;
20 }HashElem;
21
22 typedef struct HashTable
23 {
24 HashElem* data[HashMaxSize];
25 size_t size;
26 HashFunc func;
27 }HashTable;
28
27 void HashInit(HashTable* hashtable,HashFunc hash_func)
28 {
29 if(hashtable == NULL)
30 {
31 //非法操作
32 return ;
33 }
34 hashtable->size = 0;
35 hashtable->func = hash_func;
36 size_t i = 0;
37 for(;i < HashMaxSize ; ++i)
38 {
39 hashtable->data[i] = NULL;
40 }
41 return ;
42 }
44 void HashDestroy(HashTable* hashtable)
45 {
46 if(hashtable == NULL)
47 {
48 return ;
49 }
50 hashtable->size = 0;
51 hashtable->func = NULL;
52 //遍历所有链表进行释放内存
53 size_t i = 0;
54 for(;i < HashMaxSize ; ++i)
55 {
56 HashElem* cur = hashtable->data[i];
57 while(cur != NULL)
58 {
59 HashElem* next = cur->next;
60 DestroyElem(cur);
61 }
62 cur = cur->next;
63 }
64 return ;
65 }
22 void DestroyElem(HashElem* cur)
23 {
24 free(cur);
25 }
26
80 void HashInsert(HashTable* hashtable,KeyType key,ValueType value)
81 {
82 if(hashtable == NULL)
83 {
84 return ;
85 }
86 //1.根据key计算出offset
87 size_t offset = hashtable->func(key);
88 //2.在offset对应的链表中查找看当前的key是否存在,若存在就认为插入失败
89 HashElem* ret = HashBackedFind(hashtable->data[offset],key);
90 if(ret = NULL)
91 {
92 //找到了,说明找到了重复key的值,认为插入失败
93 return ;
94 }
95 //3.若不存在就可以插入,使用头插法
96 HashElem* new_node = CreateElem(key,value);
97 //头插法
98 new_node->next = hashtable->data[offset];
99 hashtable->data[offset] = new_node;
100 //4.++size
101 ++hashtable->size;
102 return;
103 }
67 HashElem* HashBackedFind(HashElem* head,KeyType to_find)
68 {
69 HashElem* cur = head;
70 for(;cur != NULL ;cur = cur->next)
71 {
72 if(cur->key == to_find)
73 {
74 return cur ;
75 }
76 }
77 return NULL;
78 }
12 HashElem* CreateElem(KeyType key,ValueType value)
13 {
14 HashElem* new_node = (HashElem*)malloc(sizeof(HashElem));
15 new_node->key = key;
16 new_node->value = value;
17 new_node->next = NULL;
18 return new_node;
19
20 }
105 int HashFind(HashTable* hashtable,KeyType key,ValueType* value)
106 {
107 if(hashtable == NULL || value == NULL)
108 {
109 return 0;
110 }
111 //1.根据key计算出offset
112 size_t offset = hashtable->func(key);
113 //2.找到对应的offset的链表,遍历链表,尝试找到其中的元素
114 HashElem* ret = HashBackedFind(hashtable->data[offset],key);
115 if(ret == NULL)
116 {
117 return 0;
118 }
119 *value = ret->value;
120 return 1;
121 }
122
5.哈希表的删除操作
143 void HashRemove(HashTable* hashtable,KeyType key)
144 {
145 if(hashtable == NULL)
146 {
147 return ;
148 }
149 if(hashtable->size == 0)
150 {
151 return ;
152 }
153 //1.根据key计算出offset
154 size_t offset = hashtable->func(key);
155 HashElem* pre = NULL;
156 HashElem* cur = NULL;
157 //2.通过 offset 找到对应的链表,在链表中找到指定的元素并进行删除
158 int ret = HashBackedFindEx(hashtable->data[offset],key,&pre,&cur);
159 if(cur == 0)
160 {
161 //没找到,删除失败
162 return ;
163 }
164 if(pre == NULL)
165 {
166 //要删除的元素为链表的头节点
167 hashtable->data[offset] = cur->next;
168 }
169 else
170 {
171 //不是头节点
172 pre->next = cur->next;
173 }
174 DestroyElem(cur);
175 //--size
176 --hashtable->size;
177 return ;
178 }
179
下面是实现在链表中查找要删除的元素的函数HashBackedFindEX
123 int HashBackedFindEx(HashElem* head,KeyType to_find,HashElem** pre_node,HashElem** cur_node)
124 {
125 HashElem* cur = head;
126 HashElem* pre = NULL;
127 for(;cur != NULL;pre = cur,cur = cur->next)
128 {
129 if(cur->key == to_find)
130 {
131 break;
132 }
133 }
134 if(cur == NULL)
135 {
136 return 0;
137 }
138 *pre_node = pre;
139 *cur_node = cur;
140 return 1;
141 }