- 写出哈希表的基本概念
哈希表又称散列表,其基本思路是,设要存储的元素个数为n,设置一个长度为m(m>=n)的连续内存单元,以每个元素的关键字ki(0=<i<=n-1)为自变量,通过一个称为哈希函数的函数h(ki)把ki映射为内存单元的地址(或下标)h(ki),并把该元素存储在这个内存单元中,h(ki)也称为哈希地址。把如此构造的线性表存储结构称为哈希表。
- 列出常用的哈希函数构造方法,并阐述各自的特点
直接定址法
取关键字或关键字的某个线性函数值为散列地址。
即 H(key) = key 或 H(key) = a*key + b,其中a和b为常数。
除留余数法
取关键字被某个不大于散列表长度 m 的数 p 求余,得到的作为散列地址。
即 H(key) = key % p, p < m。
数字分析法
当关键字的位数大于地址的位数,对关键字的各位分布进行分析,选出分布均匀的任意几位作为散列地址。
仅适用于所有关键字都已知的情况下,根据实际应用确定要选取的部分,尽量避免发生冲突。
平方取中法
先计算出关键字值的平方,然后取平方值中间几位作为散列地址。
随机分布的关键字,得到的散列地址也是随机分布的。
折叠法(叠加法)
将关键字分为位数相同的几部分,然后取这几部分的叠加和(舍去进位)作为散列地址。
用于关键字位数较多,并且关键字中每一位上数字分布大致均匀。
随机数法
选择一个随机函数,把关键字的随机函数值作为它的哈希值。
通常当关键字的长度不等时用这种方法
(3)列出常见的解决哈希冲突的方法,并阐述各自的优缺点
解决哈希冲突的四种方法
1.开放地址方法
(1)线性探测
按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上往后加一个单位,直至不发生哈希冲突。
(2)再平方探测
按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。
(3)伪随机探测
按顺序决定哈希值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来哈希值的基础上加上随机数,直至不发生哈希冲突。
2.链式地址法(HashMap的哈希冲突解决方法)
对于相同的哈希值,使用链表进行连接。使用数组存储每一个链表。 优点:
(1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
(2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
(3)开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
(4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
缺点:
指针占用较大空间时,会造成空间浪费,若空间用于增大散列表规模进而提高开放地址法的效率。
3.建立公共溢出区
建立公共溢出区存储所有哈希冲突的数据。
4.再哈希法
对于冲突的哈希值再次进行哈希处理,直至没有哈希冲突。
(4)写出影响哈希查找性能的3个主要因素
使用平均查找长度来衡量哈希表的查找效率,在查找过程中与关键字比较的比较次数取决于hash函数的选取和处理冲突的方法。
假设hash函数是均匀的,即对同样的一组随机关键字出现冲突的可能是相同的。因此,哈希表的查找效率主要取决于处理冲突的方法。发生冲突的次数和hash表的装填因子有关,哈希表的装填因子如下:
a = 哈 希 表 中 数 据 元 素 个 数 / 哈 希 表 的 长 度 a=哈希表中数据元素个数/哈希表的长度a=哈希表中数据元素个数/哈希表的长度
填入表中的数据元素越多,a aa越大,产生冲突的可能性越大;填入表中的数据元素越少,a aa越小,产生冲突的可能性越小,a aa通常取1和0.5之间的较小数(一般取0.75左右)。
(5)计算各关键字存储地址的过程,并完成表1中所构造的哈希表。
答:(7*3)/7=3
(8*3)/7=3……3
(30*3)/7=12……3
(11*3)/7=4……5
(18*3)/7=7……5
(9*3)/7=3……6
(14*3)/7=6
地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
关键字 | 7 | 14 | 8 | 11 | 30 | 18 | 9 |
(6)分别计算等概率情况下查找成功和查找不成功的平均查找长度。
答:ASLsucc=1/7(1+2+1+1+1+3+3)=12/7
ASLunsucc=1/10(3+2+1+2+1+5+4+3+2+1)=12/5