算法导论11-3

读书笔记

本小节介绍了散列表的灵魂--散列函数

一个好的散列函数应满足简单均匀散列假设:每个关键字都被等可能地散列到\(m\)个槽位中的任何一个,并与其他关键字已散列到哪个槽位无关。

虽然上述假设难以实现,但是可以作为衡量其他散列函数的标准。

有一些动态集合的元素关键字并不是自然数,我们需要使用各种各样的方法将其变为自然数,以便进行散列;

除法散列法

说是除法,但实际上进行的却是取模操作,具体函数如下

\[h(k) = k \;mod\; m \]

其中\(m\)的取值有一些讲究,应当避免为\(2\)的幂;其取值应该为一个不太接近\(2\)的整数幂的素数。

乘法散列法

有两个步骤:

  1. 用关键字\(k\)乘以常数\(A(0<A<1)\),并提取\(kA\)的小数部分;
  2. \(m\)乘以这个小数,再向下取整;

具体函数如下:

\[h(k) = \lfloor m(mA \;mod\; 1)\rfloor \]

乘法散列法的一个优点就是对\(m\)的选择不是特别关键,一般选择它为\(2^p\)

全域散列法

事实上,我觉得全域散列法不能被称为散列方法,应该是一种散列策略;

全域散列法在执行之前,从一组散列函数中通过随机算法选出一种作为散列算法,然后进行散列;

课后习题

11.3-1

假设我们希望查找一个长度为\(n\)的链表,其中每一个元素都包含一个关键字\(k\)并具有散列值\(h(k)\)。每一个关键字都是长字符串。那么在表中查找具有给定关键字的元素时,如何利用各元素的散列值呢?

对链表中每一个元素,先比较该元素与待查关键字的散列值。若一样,在比较字符串值。

11.3-2

假设将一个长度为\(r\)的字符串散列到\(m\)个槽中,并将其视为一个以\(128\)为基数的数,要求应用除法散列法。我们可以很容易地把数\(m\)表示为一个\(32\)位的机器字,但对长度为\(r\)的字符串,由于它可以被当作以\(128\)为基数的数来处理,就要占用若干机器字。假设应用除法散列表来计算一个字符的散列值,那么如何才能在除了该串本身占用的空间外,只利用常数个机器字?

题目本身讲的有点绕,请参考这里

11.3-3

考虑除法散列法的另一个版本,其中\(h(k)= k \; mod \; m, m = 2^p -1\)\(k\)为按基数\(2^p\)表示的字符串。试证明:如果串\(x\)可由串\(y\)通过自身字符置换排列导出,则\(x\)\(y\)具有相同的散列值。给出一个应用的例子,其中这一特性在散列函数中不希望出现的。

不会证明,但是这道题的出现说明需要注意\(m\)的取值;

11.3-4

考虑一个大小为\(m=1000\)的散列表和一个对应的散列函数\(h(k) = \lfloor m (kA \;mod \;1)\),其中\(A=(\sqrt{5} -1)/2\),尝试计算关键字\(61,62,63,64,65\)被映射到的位置。

k h(k)
61 700
62 318
63 936
64 554
65 172
posted @ 2021-01-15 11:35  ijkzen  阅读(193)  评论(0编辑  收藏  举报