处理哈希冲突----开散列/链地址法

哈希表的开散列
开散列法又叫链地址法
开散列法:首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一个集合,每一个子集称为一个桶,个桶中元素通过单链表链接起来,各链表的头节点存储在哈希表中。

这里写图片描述

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 }

猜你喜欢

转载自blog.csdn.net/yu876876/article/details/81177808