第03讲 散列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第03讲 散列表相关的知识,希望对你有一定的参考价值。


【高级数据库】第二章 数据库索引

  

第03讲 散列表

1、散列表的构造

  通过对关键字与存储地址之间建立的映射结构称为散列函数(哈希函数或哈希映射),通过散列函数将关键字映射到的值称为散列地址(哈希地址),保存散列地址及对应的数据则是散列表(哈希表)
  在散列 【高级数据库】第二章 中,假设关键字为 【高级数据库】第二章,目标则是设计一个散列函数 【高级数据库】第二章 使得给定一个关键字即可获取所取数据的地址:
(1)散列函数是一个映像,其可以自由选择和设计,但必须保证映射的值在地址范围内。在数据库系统中,每个地址对应的数据集合称为,桶的地址则为散列地址,散列表中的关键字即为该桶的存储地址,因此散列函数需要保证值在地址的范围内。形式化语言描述则为:设存在 【高级数据库】第二章 个桶,则 【高级数据库】第二章
(2)对不同关键字,散列函数可能得到相同的值,这种现象被称为冲突,而这些关键字称为同义词。选择或设计散列函数不可能完全避免出现冲突,但需要尽可能减少冲突。

1.1 散列函数的构造

  数据结构中散列函数构造有包括直接定址法、数字分析法、平方取中法、折叠法、除留余数法和随机数法,也可以根据实际情况设计散列函数,不管散列函数的选择如何,都需要保证尽可能减少同义词。

(1)直接定址法。直接为关键字和散列地址构造一个函数表达式。例如线性 【高级数据库】第二章

(2)数字分析法。如果键为数字,则可以将所有键的这些数字展开。例如有一组键:“81346532”、“81372242”、“81387422”、…,每个键为8位十进制数,则将所有键每位数字拆开后列出,如图所示:

【高级数据库】第二章

可知每个键的第1、2、8位数字重复率很高,而中间4位则相对比较随机,所以可以任意取中间4位中的几位为组合作为散列地址。
(3)平分取中法。取关键字平方后的中间几位数字作为散列地址。位数则取决于关键字的个数以及相对分布。
(4)折叠法。适合关键字较长且相对分布均匀,可将关键字划分几块,根据每一块的数字进行叠加。如若是字符,则可以根据ASCII码进行数值转换。
(5)除留余数法。直接对关键字取模。
(6)随机数法。散列函数选为随机函数。

1.2 冲突的处理

  如果由于记录数量过大、关键字的结构性质因素势必会导致冲突问题。例如全世界所有地名及对应的经纬度来说,地名数量是上百万的,而地名(亦即关键字)仅由26个字母表示,使用上述的几种散列函数不能完全保证散列值唯一。

  冲突的本质就是在存储数据的过程中,一个散列地址只能存储一个数据,而当这个地址下的位置已经存储一个数据时,再来一个相同散列值的数据则无处可放。处理这种冲突的方法有:

(1)开放定址法

【高级数据库】第二章

其中 【高级数据库】第二章 为散列表表长(即桶的个数 【高级数据库】第二章),【高级数据库】第二章 为增量序列,可以是等差数列1,2,…。

例如如图(a)所示:

【高级数据库】第二章


当前散列表长度为11,已有散列地址为5、6、7位置存放了值。如果接下来有一值38的散列值为5,则发生冲突,根据增量序列可知,依次从6开始向后遍历,直到存在一个空位(即8),将38存放于此(图(b))。增量序列也可以选择其他数列。

(2)再哈希法
【高级数据库】第二章

再哈希法指当当前关键字发生冲突时,在这个基础上使用另一个散列函数继续计算,直到不发生冲突为止。

(3)链地址法

  链地址法又称拉链法,是一种特殊的数据结构,其中散列地址保存在固定长度的数组,而数组的值则保存一个链表指针。链表指针指向属于该散列地址的结点,结点包含数据域和指针域,因此这是一个由多个散列地址组成的单链表。如图所示:

【高级数据库】第二章

2、散列表的操作

2.1 查询

  step1:首先根据散列函数,计算关键字对应的散列地址;
  step2:如果散列地址对应的记录为空,则表明不存在;否则执行step3;
  step3:比较当前位置记录的关键字,如果相同则取出,否则执行step4;
  step4:根据冲突处理方法寻找下一个地址;直到记录为空或匹配到相同关键字。
  关于step4,根据设计好的处理冲突办法,逐个寻找下一个地址,如果记录为空,势必该记录不存在即可终止。

2.2 插入

  当向已设计构造好的散列表中插入新数据时,首先需要根据散列函数计算散列地址。如果我们采用链地址法,则如果当前地址没有数据,则直接存储在第一个位置,并且将数组指针指向这个记录;否则将新的记录连接到最后一个记录上。

2.3 删除

  删除操作与查询相同,只是在查询到该记录的时候执行删除操作。对于链地址法来说,即是单向链表的删除操作;若是数组,则直接取null即可。

3、动态散列表

  一般描述的散列表均为散列表长度(桶数量)固定,即为静态散列表。而在实际过程中会发现,如果每个桶只保存一个记录,则仅需要不超过2次I/O操作即可实现查询;而如果使用链地址法,每个桶则可存放无限个记录。一般情况下可能出现部分散列地址下的记录数量过大,而每次进行匹配需要进行多次I/O,因此需要对其进行改进。动态散列表包括可扩展散列表线性散列表,其构造方法及操作在此处不做具体叙述。



  博客记录着学习的脚步,分享着最新的技术,非常感谢您的阅读,本博客将不断进行更新,希望能够给您在技术上带来帮助。


以上是关于第03讲 散列表的主要内容,如果未能解决你的问题,请参考以下文章

算法:开放定址法散列表

散列表的开放定址法以及再散列法(C语言)

散列表解决冲突的方式

算法小讲堂之哈希表|散列表|考研笔记

hash算法解决冲突的方案

数据结构散列表