算法导论习题解答17-2

Problem 17-2

(动态二分查找)有序数组上的二分查找花费对数时间,但插入一个新元素的时间与数组规模呈线性关系。我们可以通过维护多个有序数组来提高插入性能。

具体地,假定我们希望支持 n n n元集合上的 S E A R C H SEARCH SEARCH I N S E R T INSERT INSERT操作。令 k = ⌈ lg ⁡ ( n = 1 ) ⌉ k = \lceil \lg(n=1)\rceil k=lg(n=1),令 n n n的二进制表示为 < n k − 1 , n k − 2 , ⋯   , n 0 > <n_{k-1},n_{k-2},\cdots, n_0> <nk1,nk2,,n0>。我们维护 k k k个有序数组 A 0 A_0 A0 A 1 A_1 A1 ⋯ \cdots A k − 1 A_{k-1} Ak1,对 i = 0 , 1 , ⋯   , k − 1 i=0,1,\cdots,k-1 i=0,1,,k1,数组 A i A_i Ai的长度为 2 i 2_i 2i。每个数组或满或空,取决于 n i = 1 n_i=1 ni=1还是 n i = 0 n_i=0 ni=0。因此所有 k k k个数组中保存的元素总数为 ∑ i = 0 k − 1 n i 2 i = n \sum_{i=0}^{k-1}n_i2^i = n i=0k1ni2i=n。虽然单独每个数组都是有序的,但不同数组中的元素之间不存在特定的大小关系。

a. 设计算法,实现这种数据结构上的 S E A R C H SEARCH SEARCH操作,分析其最坏情况运行时间。

Answer:

对于 S E A R C H ( x ) SEARCH(x) SEARCH(x)操作,我们需要一次在 k k k个有序数组中做有序查找,对于满的数组 A i A_i Ai,查找的时间复杂度为 O ( i ) O(i) O(i)。最坏情况下所有数组都为满,且 x x x不在任意数组中,则最坏情况时间复杂度为:
T ( n ) = ∑ i = 0 k − 1 c i = c ⋅ ⌈ lg ⁡ ( n + 1 ) ⌉ ⋅ ( ⌈ lg ⁡ ( n + 1 ) ⌉ − 1 ) / 2 = O ( lg ⁡ 2 n ) T(n) = \sum_{i=0}^{k-1}ci = c\cdot \lceil \lg(n+1)\rceil \cdot (\lceil \lg(n+1)\rceil - 1) / 2 = O(\lg^2n) T(n)=i=0k1ci=clg(n+1)(lg(n+1)1)/2=O(lg2n)

b. 设计 I N S E R T INSERT INSERT算法。分析最坏情况运行时间和摊还时间。

Answer:

本题的数据结构实际上是将 n n n转化为二进制表示,该二进制数的位数为 ⌈ lg ⁡ ( n + 1 ) ⌉ \lceil \lg(n+1)\rceil lg(n+1),于数据结构中的数组一一对应,二进制数的该位为1时,对应数组为满,否则为空。因此为了在插入操作时保持数据结构特性,本题化为二进制数的 { 0 , 1 } \{0,1\} {0,1}翻转问题。

当插入一个元素时,新创建一个大小为1的数组 S S S存放该元素。然后进行以下操作:

  • 1.找到数据结构中大小与 S S S相同的数组 A lg ⁡ ∣ S ∣ A_{\lg|S|} AlgS
  • 2.若数据结构中大小与 S S S相同的数组 A lg ⁡ ∣ S ∣ A_{\lg|S|} AlgS为满,则创建新的数组 S S S有序存放原 S S S A lg ⁡ ∣ S ∣ A_{\lg|S|} AlgS中的元素。该操作时间复杂度度为 O ( ∣ S ∣ ) O(|S|) O(S)。完成后回到步骤0。
  • 3.若数据结构中大小与 S S S相同的数组 A lg ⁡ ∣ S ∣ A_{\lg|S|} AlgS为空,则用S替代该数组,插入操作完成。
  • 4.若不存在若数据结构中大小与 S S S相同的数组 A lg ⁡ ∣ S ∣ A_{\lg|S|} AlgS,直接将 S S S数组作为 A k A_k Ak加入数组集合。

上述操作最坏情况为初始的数组集合 { A i } \{A_i\} {Ai}全部为满,此时的最坏情况运行时间为:
T ( n ) = ∑ i = 0 ⌈ lg ⁡ ( n + 1 ) ⌉ c ⋅ 2 i = O ( 2 ⌈ lg ⁡ ( n + 1 ) ⌉ + 1 − 1 ) = O ( n ) T(n) = \sum_{i=0}^{\lceil \lg(n+1)\rceil} c \cdot 2^i = O(2^{\lceil \lg(n+1)\rceil + 1} - 1) = O(n) T(n)=i=0lg(n+1)c2i=O(2lg(n+1)+11)=O(n)

下分析摊还时间。从上述分析中可以看出,当数组 A i A_i Ai从空被置为满时,对应的数组 A j A_j Aj要被置满再置空 2 i − j − 1 2^{i-j-1} 2ij1次。此处 j < i j < i j<i。则从 0 0 0开始不断插入元素,插入的总开销小于等于插入 2 ⌈ lg ⁡ ( n + 1 ) ⌉ + 1 − 1 2^{\lceil \lg(n+1)\rceil + 1} - 1 2lg(n+1)+11个元素的开销。在此分析中,与数组 A i A_i Ai相关的开销为被置为满的单次开销乘以置满的次数:
T ( A i ) = 2 i ⋅ ( 1 + ∑ j = 1 k − 1 − i 2 j ) = 2 i ⋅ ( 2 k − i − 1 ) = Θ ( 2 k ) = Θ ( n ) T(A_i) = 2^i \cdot \left(1 + \sum_{j=1}^{k-1-i}2^{j}\right) = 2^i \cdot (2^{k-i}-1) = \Theta(2^k) = \Theta(n) T(Ai)=2i(1+j=1k1i2j)=2i(2ki1)=Θ(2k)=Θ(n)

则总开销为:
T ( n ) = ∑ i = 0 k − 1 T ( A i ) = k ⋅ Θ ( n ) = Θ ( n lg ⁡ n ) T(n) = \sum_{i=0}^{k-1}T(A_i) = k\cdot \Theta(n) = \Theta(n\lg n) T(n)=i=0k1T(Ai)=kΘ(n)=Θ(nlgn)

故摊还时间为 O ( lg ⁡ n ) O(\lg n) O(lgn)

c. 讨论如何实现 D E L E T E DELETE DELETE

Answer:

与二进制减法相同,假设状态为满的最小下标数组为 A i A_i Ai,则删除操作需要变动的数组仅限被删除的元素本身所在的数组 A m A_m Am以及 A 0 , A 1 , ⋯   , A i A_0,A_1,\cdots,A_i A0,A1,,Ai。具体操作为 S E A R C H ( x ) SEARCH(x) SEARCH(x),所需时间为 O ( lg ⁡ 2 n ) O(\lg^2n) O(lg2n)。然后将 A m A_m Am中的 x x x替换为 A i A_i Ai中的一个元素,并将该元素从 A i A_i Ai中删除。然后将 A i A_i Ai中剩余的 2 i − 1 2^i-1 2i1个元素填入 A 0 , A 1 , ⋯   , A i − 1 A_0,A_1,\cdots,A_{i-1} A0,A1,,Ai1中,最后置空 A i A_i Ai。最坏情况下的总时间复杂度为:
T ( n ) = Θ ( lg ⁡ 2 n ) + 2 k − 1 = Θ ( n ) T(n) = \Theta(\lg^2n) + 2^k - 1 = \Theta(n) T(n)=Θ(lg2n)+2k1=Θ(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值