哈希表

哈希表是一种使用散列函数直接访问数据结构,通过关键码值快速查找记录。本文介绍了哈希冲突的概念,并重点讲解了采用闭散列(线性探测法)处理冲突的方法,包括哈希表的初始化、插入、查找和删除操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希冲突

不同的关键字通过同一哈希转换函数计算出相同的哈希地址

处理哈希冲突
常见的两种方法是闭散列和开散列

闭散列:(开放地址法或者也叫线性探测法)
当发生冲突时,如果哈希表未被填满,说明哈希表中必然有空位置,可以把key放到列表中“下一个”空位置中。

这里写图片描述
哈希表定义

  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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值