算法导论-散列表习题解
2012-04-24 10:12 meteorgan 阅读(1444) 评论(0) 编辑 收藏 举报11.1-4 我们希望通过利用在一个非常大的数组上直接寻址的方式来实现字典。开始时,该数组中可能存在废料,但要对整数数组进行初始化是不现实的,因为该数组规模太大。请给出在大数组上实现直接寻址字典的方案。每个存储的对象占用O(1)的空间;操作SEARCH, INSERT,DELETE的时间为O(1);对数据结构的初始化的时间为O(1)。
解: 由于数组中存在废料,直接对字典进行查询可能取到非法的值。因此需要对字典中的关键字进行验证。方法是:用数组实现一个栈S,栈顶部为TOP[S]栈大小等于已插入到词典中的关键字的个数,如果关键字k的确存在,则令D[k] = j(D是用原数组实现的字典),S[j] = k。显然如果k不存在于字典中,即使D中的废料碰巧使D[k] = j,S[j]也不会等于k,这样就完成了对字典中关键字的校验。然后可另外实现一个数组array存贮关键字k对应的值value,令array[j] = value-k。
SEARCH(k): 如果 1<=D[k] <= TOP[S] and S[D[k]] == k,则返回array[D[k]];否则返回NULL。
INSERT(k, value): 如果 1<=D[k] <= TOP[S] and S[D[k]] == k,则令array[D[k]] = value;否则,TOP[S]++; D[k] = TOP[S]; S[TOP[S]] = k; array[TOP[S]] = value;
DELETE(K): 如果 1<=D[k] <= TOP[S] and S[D[k]] == k,则用栈顶元素替换要删除的元素: S[D[k]] = S[TOP[S]]; D[S[TOP[S]]] = D[k]; array[D[k]] = array[TOP[S]]; TOP[S]--;
以上操作均可以在O(1)时间内完成。
11.2-1 假设用一个散列函数h,将n个不同的关键字散列到一个长度为m的数组中。假定采用的是简单一致散列法,那么期望的碰撞数是多少?更准确地,集合{{k,l}: k != l, 且h(k) = h(l)} 的期望的基是多少?
解:定义指示器变量Xkl = I{h(k) = h(l)},由于是简单一直散列,所以有Pr{h(k) = h(l)} = 1/m,所以有E[Xkl] = 1/m。期望碰撞数为:
11.3-5 定义一个从有限集合U到有限集合B上的散列函数簇H为ε全域的,如果对U中所有的不同元素对k和l,都有: Pr{h(k) = h(l)}<= ε。其中概率是相对从函数簇H中随机抽取的散列函数h而言的。证明:一个ε全域散列函数簇必满足: ε >= 1/|B| - 1/|U|。
解:设 u = |U|, b = |B|,U中不同元素的个数为d = (u-1)u/2,如果碰撞次数为n,则有Pr{h(k)=h(l)} = n/d。设散列值等于bj 的关键字个数为nj,则总的碰撞个数为:
又有:
利用拉格朗日乘数法,可知当 uj = u/b时,n最小,且值为: u(u/b - 1)/2,所以有:
11.4-3 假设使用双重散列来解决碰撞;亦即,所用的散列函数为h(k,i) = (h1(k) + ih2(k))mod m。证明:如果对某个关键字k,m和h2(k)有最大公约数d >=1,则在对关键字k的一次不成功的查找中,在回到槽h1(k)之前,要检查散列表的1/d。于是,当d=1时,m和h2(k)互质,查找操作可能要检查整个散列表。
解:假设第s次探查回到h1(k),则有sh2(k) mod m = 0。如果m和h2(k)有最大公约数d,则有s = m/d,所以需要检查散列表的(m/d)/m = 1/d 部分。如果d = 1, 则1/d = 1,查找操作需要检查整个散列表。
11.5-1 假设要将n个关键字插入到一个大小为m、采用了开放寻址法和一致散列技术的散列表中。设p(n,m)为没有碰撞的概率。证明:p(n,m) <= e-n(n-1)/2m (提示:见公式(3.11))。论证当n超过sqrt(m)时,不发生碰撞的概率迅速趋于0。
解:公式(3.11) ex>= 1 + x。n个关键字,共有Cn2 对,每对发生碰撞的概率为1/m。所以有: