散列

蹲街弑〆低调 提交于 2020-01-12 13:21:13

以下为学习笔记,来源于《数据结构与算法分析——C语言描述》

散列的插入、删除、查找时间为O(1),因为其不是像树一样通过比较来进行上面的操作,而是直接进行。

 

理想的散列表结构:一个包含有关键字的具有固定大小的数组。

  表的大小记为TableSize,index从0到TableSize-1。

 

散列函数

(1)散列函数:每个关键字通过散列函数映射到0~TableSize-1这个范围的某个数,并且关键字被放到散列表适当的单元中。

(2)理想散列函数的要求:两个不同的关键字被映射到不同的单元;在TableSize大小的散列表里均匀地分配关键字。

(3)如果输入的关键字为整数,则一般合理的方法是返回“key mod TableSize”的结果;

    通常,关键字是字符串,一种方法是把字符串中字符的ASCII码值加起来,再对TableSize求余。

 

冲突

(1)冲突:当一个元素插入散列表时,其插入的单元已经存在另一个元素时,就产生冲突,冲突需要消除。

(2)解决冲突的常用方法:分离链接法和开放定址法

分离链接法

 

其做法是将散列到同一个单元的所有元素保留到一个表中(即建立个链表保存这些冲突的元素),为了方便,这些表都有表头。

开放定址法

 

 分离链接法缺点是需要指针,且给新单元分配地址需要时间,这使得算法的速度较慢。开放定址法,在发生冲突时尝试在原来的散列表里选择空的单元(而不是建新的空间),直到找到空的单元。单元的选择依据(Hash(X)+F(i))%TableSize,i=0,1,2,3……(遇到冲突时i才加1,没冲突时则不再加),Hash(X)为散列函数,即开始时映射出的关键字在散列表的位置。根据F(i)的不同可以分为线性探测法、平方探测法、双散列。

1)线性探测法

F(i)=i。

只要表够大,总能找到一个空间,但是如此花费的时间是较多的;即使表较空,元素占据的单元也会形成一些区块,称为一次聚集,这使得散列到区块的关键字要多次选单元才能解决冲突。

2)平方探测法

F(i)=i^2。

消除线性探测的一次聚集问题

一旦散列表被填了超过一半,当表的大小不是素数时甚至在表被填满一般之前,就不能保证一次找到一个空的单元了。

定理:使用平方探测,且表的大小时素数,那么当表至少有一般是空的时候,总能插入一个新的元素。

3)双散列

F(i)=i*hash2(X)。hash2(X)是新的散列函数,一般hash2(X)=R-(X%R)

 

再散列

当散列表快要填满时,操作的运行时间会变长,且insert操作会失败,此时一种解决放啊发是建立另外一个大约两倍大的表,扫描整个原始散列表,(使用新的散列函数)映射到到新表中

可以在以下情况时开始再散列:

 

1)表满一半时即开始再散列

2)插入失败时开始

3)达到装填因子(散列表中元素个数/散列表的大小)时开始

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!