CLRS2e读书笔记—Chapter11

散列技术

直接寻址表是对数组的一种简单扩展,适用于元素的关键字全域[0,1...m-1]范围较小的情况,每个槽对应一个关键字,如果槽k为NIL,说明没有关键字为k的元素。

如果元素存在某种一致性而可以直接放在一个序列里,可以考虑直接在数组中存放元素,使用下标作为索引,这样直接寻址表就退化为数组。

如果只需要数据结构支持Insert、Delete和Search三种操作,那么散列技术是最好的存放海量数据的方法,这种技术在数据库中被大量使用。简单来说就是使用散列函数将关键字映射到槽中,当需要搜索关键字时,直接如果有两个不同的关键字却散列到同一个槽中,这种情况被称为碰撞。

为了避免碰撞,散列函数要尽可能随机,使得碰撞即使发生,也不能太过集中。这样可以保持操作的期望速度为O(1)。

但是碰撞是不可避免的,尤其是数据量很大的情况下。书中介绍了链接法和开放寻址法来解决碰撞问题。

链接法(chaining)是将所有碰撞的元素放在一个链表中,然后对散列表的操作也就映射到链表中。如果元素不存在,那么数组(散列表)中的元素为NIL。

利用概率分析,我们可以证明使用链接法可以使三种操作的期望操作时间保持在O(1)。

散列函数:一个好的散列函数可以使散列值趋于简单一致,不过这一般很难实现。通过对关键字的分析而得到性能尽可能好的散列函数的方法称为“启发式”的方法。

一般将key解释为自然数,如果key不是自然数,可以使用某种算法将之转换为自然数。

除数散列法:h(k)=k mod m,难点在m的选择(即散列表的大小),一般取为与2的整数幂不太接近的质数。

乘法散列法:h(k)=$\lfloor m(kA \mod 1) \rfloor$,0<A<1,m的选择无所谓,一般选择为2的某个幂次,A为$s/2^w$,s为0<s<2w的一个整数,w是计算机的字长,一般取A=$(\sqrt{5}-1)/2$,或与之接近的数。

全域散列:准备一组有限的散列函数$\mathcal{H}$,这些函数都将关键字U映射到[0,m-1]中,在散列的时候随机选择一个函数作为散列函数。设计一个全域散列需要一定的数论知识(好吧我看不懂…)

开放寻址法:开放寻址法不使用卫星数据,所以n≤m必须成立。我们将散列函数h(k)进行扩充,增加一个因子称之为探查号。h(k,i),对于每一个key,需要i次不同的查找。有多种方法来计算探查序列,线性查找,二次探查和双重散列等等,其中双重散列的性能较好。

完全散列:使用两重散列技术,第一重确定下标,第二重确定碰撞后同一个槽的散列表中的下标。为了彻底解决碰撞问题,必须让第二级散列表的大小是其中存放元素数的平方。适用于静态关键字的情况。

 

本章基本上都是数学…如果不能好好理解的话,写出性能很好的代码是很困难的。除法散列和乘法的散列都很简单,而且性能也不好。一般实际使用中,链接法和开放寻址法使用的较多。代码…还是不献丑了,试着写了开放寻址,一时半会搞不定,先放这吧,时间无多,还是先备战面试要紧的课题【让你平时尽学一些没用的!】

 

作业全是数学,俺放弃了…回头闲下来再做吧。总之,这一章先到这里。

posted @ 2012-09-05 19:04  生无所息  阅读(156)  评论(0编辑  收藏  举报