5.1 一般想法
散列主要需要解决冲突发生时如何处理
5.2 散列函数
对于关键字为字符串时,若将字符串所有的字符相加得到哈希值,则对于大表而言,其值过小,使关键字集中于表的前面,分布不均。若只是取前面少数字符构造多项式,则实际组合数过少,对于大表的利用率低。最好的方法是对字符串的所有字符均使用多项式,提高利用率和使其分布均匀。
5.3 分离链接法
在分离链接法中,最好将元素插在链表前端,因为新近插入的元素被访问到的概率较高。
散列表的对象需要重写hashcode和equal方法,前者用于计算哈希位置,后者用于寻找元素所用。
在分离链接中,装填因子一般可为1.
5.4 不用链表的散列表
对于探测表而言,装填因子一般为0.5.
如果使用平方探测,且表的大小为素数,那么当表至少有一半时,那我们保证总能够插入一个新元素。
探测表只能选择懒惰删除,否则后面的寻找、删除例程,不好判断寻找终止条件。
在平方探测寻找例程中,位置的变换采用加法的迭代,避免了乘法和除法,提高了效率。
对于双散列探测方法,第二个散列函数如R-(x mode R)的格式,R为小于表大小的素数。
表的大小最好为素数,避免了探测时出现循环探测的意外。
5.5 再散列
再散列对于分离链接法和开放定址法(即探测法)实际上是相当于扩容,通过改变散列表大小,改变了散列函数。
5.6 标准库中的散列表
String采用了闪存散列代码技巧,使同一个String对象多次运用时,不用重新计算哈希值。
对于每个不同的String对象,即使其值相同,也无法共用闪存的散列代码,因为String的成员变量为常量修饰,更新字符串时,只能创建新的String对象。
5.7 最坏情形下o(1)访问的散列表
如果散列表的大小是元素个数的平方,发生冲突的概率小于一半。
完美散列采用二级散列表,对于二级散列表也使表大小为元素个数的2倍,此算法在所有项都事先知道的情况下使用比较方便。
布谷鸟散列中的多表算法、多散列函数算法、多项存储算法其实本质上相同,均能降低冲突概率,方便插入例程实现。
布谷鸟散列在更换散列函数时,要考虑到同一函数多次选取或者同一位置被多次选中的糟糕情形。
布谷鸟分扩容和再散列两个例程,扩容不更换散列族函数,再散列不改变表大小。
5.8 通用散列函数
((A*X + B)% P)% M
A、B是随机数
P一般为梅森素数
M为表大小
其利用了公式:R=q+r(modp)
其中R为A*X+B
q为R/(p+1)的商,其可用右移操作,右移位数为P+1对应的2进制位数
r为R/(p+1)的余数,其可用位与操作,使梅森素数与R位与操作可得。
最后q+r所得若大于p再减去1次p即可。
5.9 可扩散列
可扩散列在需要时才会扩容,并只扩需要的大小。提供了对大型数据的插入和查找的快速寻找。
对知识点的理解
1.提高算法效率的一般规则有:以空间换时间,或者牺牲某些特性
2.散列表通过允许存在空位置,使用哈希索引,而失去排序信息,来提高寻找效率。
3.散列表类似于分组思想,通过分组提高搜索效率
疑难点
15练习题的f小题