基于线性探测解决哈希冲突的哈希表

哈希概念*

 在一种数据结构中,在插入元素时,由待插入元素的值根据一个特殊函数计算出该元素的存储位置,并将该元素放置在此处。在搜索元素时,还是由搜索的元素值根据这个特殊函数计算存储位置,直接在该位置将元素取出即可。

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(散列表)。

哈希冲突

我们使用同一个哈希函数来计算不止一个的待存放的数据在表中的存放位置,总是会有一些数据通过这个转换函数计算出来的存放位置是相同的,这就是哈希冲突。也就是说,不同的关键字通过同一哈希转换函数计算出相同的哈希地址。

处理哈希冲突

闭散列和开散列
闭散列:(开放地址法或者也叫线性探测法)

当我们要往哈希表中插入一个数据时,通过哈希函数计算该值的哈希地址,
当我们找到哈希地址时却发现该位置已经被别的数据插入了,
那么此时我们就找紧跟着这一位置的下一个位置,看是否能够插入,
如果能则插入,不能则继续探测紧跟着当前位置的下一个位置。 

哈希表定义

  7 #define max_size 1000
  8 
  9 typedef int KeyType; 
 10 typedef int ValType;  
 11 typedef char DataType;
 12 typedef int (*HashFunc)(KeyType key);
 13 //哈希数组元素的状态
 14 typedef enum Stat
 15 {
 16     Empty, //未插入
 17     Valid, //插入
 18     Deleted//删除
 19 }Stat;
 20 
 21 //哈希表数组中的元素类型
 22 typedef struct HashElem
 23 {
 24     KeyType key;  //包含一个键值
 25     ValType value; //包含一个值
 26     Stat stat;   //定义哈希表中的元素状态
 27 }HashElem;
 28 //定义哈希表
 29 typedef struct HashTable
 30 {
 31     HashElem data[max_size];
 32     int size;  //有效元素个数
 33     HashFunc func; //哈希函数
 34 }HashTable;   

哈希表的初始化

 36 //哈希表的初始化
 37 void HashInit(HashTable* ht,HashFunc hash_func)
 38 {
 39     if(ht==NULL)
 40     {
 41         return ;
 42     }
 43     ht->size=0;
 44     ht->func=hash_func;
 45     int i=0;
 46     for(;i<max_size;i++)
 47     {
 48         //将哈希表的每一个位置初始化为空状态
 49         //代表相应的位置是未被使用过的
 50         ht->data[i].stat=Empty;
 51     }
 52 }

哈希表的销毁

 54 //销毁
 55 void HashDestroy(HashTable *ht)
 56 {
 57     if(ht==NULL)
 58     {
 59         return ;
 60     }
 61     //先将表中的每一个位置都置为无效状态
 62     int i=0;
 63     for(;i<max_size;i++)
 64     {
 65         ht->data[i].stat=Empty;
 66     }
 67     //再将有效元素个数清0
 68     ht->size=0;
 69     ht->func=NULL;                                                                                                                                                 
 70 }

哈希表中插入元素

//根据Key值计算出下标offset
//如果当前位置状态不是已插入,则插入元素,修改状态,有效个数+1
//如果当前位置状态是已插入,且key值相等,默认为不处理直接返回
//其余则认为offset更新向后循环判断是否可插

 71 //插入数据
 72 void HashInsert(HashTable* ht, KeyType key, ValType value)
 73 {
 74     if(ht==NULL)
 75     {
 76         return ;
 77     }
 78     //判断当前Hash表能否继续插入
 79     //假设负载因子0.8
 80     if(ht->size>=0.8max_size)
 81     {
 82         //当前Hash表已经达到负载因子的上限,不能继续插入
 83         return;
 84     }
 85     //由key计算offset(由hash函数计算存放位置的下标)
 86     int offset=ht->func(key);
 87     //但是该位置可能之前被别的数据占据了
 88     //所以要先判断计算出的位置能否放入当前数据
 89     //如果不能就从offset位置往后查找
 90     while(1)
 91     {
 92         if(ht->data[offset].stat!=Valid)
 93         {
 94             //如果找到的第一个位置不是有效位置
 95             //可以将该数据插入
 96             ht->data[offset].key=key;
 97             ht->data[offset].value=value;
 98             //插入完成以后将该位置置成有效状态
 99             ht->data[offset].stat=Valid;
100             //哈希表有效元素个数+1
101             ++ht->size;
102             return ;
103         }
104         //走到这里说明计算出当位置不能放置待插数据
105         //判断当前位置的元素是否和待插元素一样
106         else if(ht->data[offfset].stat==Valid\
107                 &&ht->data[offset].key==key)
108         {
109             //说明存在相同元素
110             //我们约定该哈希表不存在重复元素
111             //则直接插入失败返回
112             return;
113         }
114         //则更新offset值继续下一次循环往后查找
115         else
116         {
117             ++offset;
118             if(offset>=max_size)
119             {
120                 //如果查找时offset走到了哈希表的末尾
121                 //还没有找到一个可插入的位置
122                 //则将其置为0,从头开始往后继续查找
123                 offset=0;
124             }
125         }//else结束
126     }//while结束
127 }                                                                                                                                                                  
128 //查找数据

在哈希表中查找数据
//根据Key计算出下标offset值
//如果当前位置的状态是已插入
// a.如果Key值相等,认为找到了
// b.更新offset循环继续向后查找
//如果当前位置的状态是空,则找不到

128 //查找数据
129 int HashFind(HashTable *ht, KetType key, ValType *value)
130 {
131     if(ht==NULL)
132     {
133         return 0;
134     }
135     //判断当前hash表中是否有有效元素
136     if(ht->size==0)
137     {
138         //空哈希表
139         return 0;
140     }
141     //由key值计算出offset
142     int offset=ht->func(key);
143     //从offset开始往后查找
144     while(1)
145     {
146         //在当前位置存放的是有效数据的前提下
147         if(ht->data[offset].stat==valid)
148         {
149             if(ht->data[offset].key==key)
150             {
151                 //找到了
152                 *value=ht->data[offset].value;
153                 return 1;
154             }
155             //当前位置不是待查找的元素
156             //则更新offset的值继续查找
157             else
158             {
159                 ++offset;
160                 if(offset>=max_size)
161                 {
162                     offset=0;
163                 }
164             }
165         }
166         else if(ht->data[offset].stat==empty)
167         {
168             //说明待查找的元素不存在hash表中
169             return 0;
170         }
171     }//while循环结束
172     return 0;
173 }      

哈希表中删除一个元素
//根据Key值计算出下标offset
//如果当前位置状态是已插入且key值相等,则直接进行删除,修改状态
//如果当前位置状态是已插入key值不相等,更新offset循环向后寻找
//如果当前位置状态是空,则找不到删除失败

174 //删除数据
175 void HashRemove(HashTable*ht, keyType key)
176 {
177     if(ht==NULL)
178     {
179         return ;
180     }
181     if(ht->size==0)
182     {
183         //空哈希表
184         return ;
185     }
186     //由key值计算出offset
187     int offset=ht->func(key);
188     //从offset开始往后找
189     while(1)
190     {
191         if(ht->data[offset].stat==Valid\
192                 &&ht->data[offset].key==key)
193         {
194             //找到了待删除的元素
195             //直接将该位置的状态置为被删除状态
196             ht->data[offset].stat=Deleted;
197             //将hash表中有效元素个数-1
198             --ht->size;
199             return ;
200         }
201         else if(ht->data[offset].stat==Empty)
202         {
203             //走到这里说明元素不存在
204             return ;
205         }
206         else
207         {
208             //走到这里说明当前offset位置的值不是我们想要删除的
209             //则更新Offset值继续查找
210             ++offset;
211             if(offset>=max_size)
212             {
213                 offset=0;
214             }
215         }
216     }//while 循环结束
217     return ;
218 }                                                                                                                                                                  
219 

猜你喜欢

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