Exercise 11.1-1
从 T 中的第一个索引开始,跟踪到目前为止具有非 NIL条目的最高索引。 这需要时间 O(m)。
Exercise 11.1-2
从位向量 b 开始,如果 k 在动态集合中,它在 k 的位置上包含一个 1,否 则包含一个 0。为了进行搜索,如果 b[x] == 1,我们返回 true。要插入 x,设 置 b[x] = 1。要删除 x,设置 b[x] = 0。每一个都需要 O(1)时间。
Exercise 11.1-3
您可以将表中的每个条目设置为一个指针,该指针指向包含该键的所有对 象的双链表,如果没有则为 NIL。Search 只返回列表中与给定键对应的第一个 元素。由于列表中的所有元素都有相同的键,所以哪个搜索返回都无关紧要。 Insert 只是将键加到双链表的开头。最后,在双链表中,删除可以在常数时间 内完成,见问题10-1 。
Exercise 11.1-4
额外的数据结构将是一个双重链表 S,它在许多方面的行为类似于堆栈。最初,将 S 设置为空,不做任何事情来初始化这个巨大的数组。存储在巨大数组 中的每个对象将有两部分:键值,以及指向 S元素的指针,其中包含一个返回到巨大数组中对象的指针。要插入 x,向堆栈中添加一个元素 y,其中包含一个 指向巨大数组中 x位置的指针。更新大数组 A 中的位置 A[x]以包含 S 中指向 y 的指针。要查找 x,请转到 A 的位置 x 并转到存储在那里的位置。如果该位置 是 S 中包含指向 A[x]的指针的元素,则我们知道 x在 A中,否则 x A。要删 除 x,则删除 S 中 A[x]所指向的元素。每一个都取 O(1),S 中的元素最多等于 A 中有效元素的数量。
Exercise 11.2-1
在简单均匀哈希的假设下,我们将使用期望的线性来计算这个。假设所有的键都是完全有序的{k1,…kn}。设 Xi 为 > k 的个数,使得 。注意,这和是一样的。然后,根据期望的线性,碰撞次数是碰撞中每个可能最小元素的碰撞次数之和。预期碰撞次数为。
Exercise 11.2-2
标记我们表的槽位为 0,1,2,…8。在表格中出现在左边的数字是稍后插入的。
Exercise 11.2-3
这两种搜索都成为 Θ(1 + lg(α))的预期运行时间。插入和删除保持 Θ(1 + α),因为插入或删除排序列表的时间是线性的。
Exercise 11.2-4
如果元素包含值,哈希表的每个槽中的标志将为1,如果元素是空闲的, 则为0。空闲列表必须是双向链接的。搜索是未修改的,所以它的预期时间是 O(1)。要插入一个元素 x,首先检查 T[h(x.key)]是否空闲。如果是,则删除 T[h(x.key)],并将 T[h(x.key)]的标志改为 1。如果一开始它不是自由的,只需 在存储在那里的列表的开头插入 x.key。要删除,首先检查 x.prev 和 x.next 是否为 NIL。如果是,则删除x时列表将为空,因此将 T[h(x.key)]插入空闲 列表,将 T[h(x.key)]的标志更新为 0,并从存储它的列表中删除 x。因为从 单链表中删除一个元素不是 O(1),所以我们必须使用双链表。其他所有操作都是O(1)。
Exercise 11.2-5
有一个大小为n的子集哈希到同一个点,因为如果每个点只有n−1个元素哈希到它,那么宇宙的大小只能是(n−1)m。最坏情况下的搜索时间是如果我们放入哈希表的所有元素都是这个大小为n的子集,它们都到同一个点,这是线性的。
Exercise 11.2-6
在哈希表的 m 个点中随机选择一个。设 nk 表示存储在T[k]处的元素个数。 接下来从 1 到 L中均匀随机选取一个数字x。如果 x < nj ,则返回列表上的第x个元素。否则,重复此过程。哈希表中的任何元素都将以 1/mL 的概率被选 中,因此我们以相同的概率返回任何键。设 X 为随机变量,它计算在我们停 止之前必须重复这个过程的次数,p 为我们在给定尝试时返回的概率。那么 E[X] = p(1+α)+(1− p)(1+E[X]),因为我们预计需要 1+α 步才能到达列表中 的一个元素,而且因为我们知道每个列表中有多少元素,如果元素不存在, 我们马上就会知道。然后我们有 E[X] = α +1/p。选择一个特定元素的概率是 n/mL = α/L,所以我们有
E[X] = α + L/α = L(α/L + 1/α) = O(L(1 + 1/α)) 因为α≤L。
Exercise 11.3-1
如果每个元素还包含长字符串的哈希值,那么在搜索所需元素时,我们将首先检查链表中节点的哈希值是否一致,如果不一致则继续进行。这可以将运行时间增加一个与长字符串长度成正比的因子。
Exercise 11.3-2
计算第一个字符 mod m 的值,加上第二个字符 mod m 的值,再加上第三个字符 mod m 的值,以此类推,直到所有 r 个字符都被处理完毕。
Exercise 11.3-3
我们将展示每个字符串的哈希值为其位数的和,取mod( 2^p − 1 )的值。我们将通过对字符串的长度进行归纳来实现这一点。作为基本情况,假设字符串是单个字符,那么该字符的值就是 k 的值,然后对 m 取模。现在,对于归纳步骤,设 w = w1w2 其中 |w1|≥1 且 |w2|=1。 设 h(w1)= k1,则 h(w1) =h(w1)2^p + h(w2) mod 2^p − 1= h(w1) + h(w2) mod 2^p− 1。因此,由于 h(w1)是除最后一位数外所有数的和, 对m取模,而我们将最后一位数加到对 m 取模,我们就得到了期望的结论。
Exercise 11.3-4
键 61、62、63、64和 65分别被映射到位置 700、318、936、554和172.
Exercise 11.3-5
作为一个简化的假设,假设|B| 除 |U|。如果分不匀,就会稍微混乱一些。
假设有一个矛盾 。这意味着对于所有对 k,l 在 U 中,我们有 H 中对这两个元素有碰撞的非哈希函数的个数 满足 。所以,对 U 中所有元素对求和,我们得到总数小于≤ .
任何特定的哈希函数都必须有至少有碰撞对。所有的哈希函数,我们得到至少总共有碰撞对 。既然我们知道最多有某个数小于这个数,我们就有了一个矛盾,因此必须对有期望的限制。
Exercise 11.3-6
固定 b∈Zp。通过练习31.4-4,hb(x)与 hb(y)在最多 n− 1 个其他 y∈U 中发生碰撞,因为 hb 总共有 p 个可能的值 ,所以 hb(x) =hb(y)的概率从上面以 (n− 1)/p 为 界。因为这对 b 的任何值都成立,所以 H 是((n-1)/p)-全称的。
Exercise 11.4-1
这是使用线性探测每次插入后数组的样子:
对于二次探测,在插入第五个元素时发生碰撞之前,它看起来是一样的。 然后,它是
最后,对于双哈希,我们有:
Exercise 11.4-2
我们通过将第 4 行更改为:if T[j] == NIL 或 T[j] ==DELETED。
Exercise 11.4-3
对于 α = 3/4 的情况,我们只需要分别代入定理 11.6 和 11.8,就可以得到,对于一个不成功的搜索,期望探测数以 4 为界。而对于一次成功的搜索, 探测的期望次数以 ln(4)*4/3为界。 对于 α = 7/8。不成功探针数的期望边界为 8,成功探针数的期望边界为 8ln(8)/7。
Exercise 11.4-4
对于常数 c1,c2 ,令 h2(k) = d*c1 和 m = d*c2 当我们检查了表的第(1/d)项 时, 这对应于它们的 m/d = c2 。此时我们检查的表项是[h1(k) + (m/d)h2(k)] mod m = [h1(k) + (m/d)(dc1)] mod m≡h1(k)。当 d = 1 时,我们可能要检查整个哈希表。
Exercise 11.4-5
我们将尝试找到一个合理的解,设 α= m/n。利用定理 11.6 和 11.8,我们 要解出方程
不幸的是,这个超越方程不能用简单的技巧来解。有一个精确解用的是的朗伯函数W
其计算结果约为 α= .7153。
Exercise 11.5-1
让 Aj,k 把 j 和 k 散列到不同的东西上。由于均匀散列,Pr(Aj,k) = (m− 1)/m。 同样,我们可以说事件之间存在负相关关系。也就是说,如果我们知道有几对元素散列到同一事物上,那么我们只能降低其他一些元素对散列到不同事 物上的可能性。这让我们知道所有事件发生的概率≤所有事件独立发生的概率,所以,
所以,如果我们有 n 超过 m,那么- n^2 /(2m)项要比 n/2m项大得多,那么, 指数趋于− ∞,也就是说概率趋于0。