(合并有序列表的下界)合并两个有序列表是我们经常会遇到的问题。作为MERGE-SORT的一个子过程,我们在2.3.1节中已经遇到过这一问题。对这一问题,我们将证明在最坏情况下,合并两个都包含
n
n
n个元素的有序列表所需的比较次数的下界是
2
n
−
1
2n−1
2n−1。
首先,利用决策树来说明比较次数有一个下界
2
n
−
o
(
n
)
2n−o(n)
2n−o(n)。
a. 给定
2
n
2n
2n个数,请算出共有多少种可能的方式将它们划分成两个有序的列表,其中每个列表都包含
n
n
n个数。
b. 利用决策树和(a)的答案,证明:任何能够正确合并两个有序列表的算法都至少要进行
2
n
−
o
(
n
)
2n−o(n)
2n−o(n)次比较。
现在我们来给出一个更紧确界
2
n
−
1
2n−1
2n−1。
c. 请说明:如果两个元素在有序序列中是连续的,且它们分别来自不同的列表,则它们必须进行比较。
d. 利用你对上一部分的回答,说明合并两个有序列表时的比较次数下界为
2
n
−
1
2n−1
2n−1。
解
a.
题目问的是有多少种方式将
2
n
2n
2n个数划分成两个都包含
n
n
n个数的有序的列表。实际上题目可以转化为求取有多少种方式将
2
n
2n
2n个数分成两组,每组都有
n
n
n个数。因为,只要分组确定了,每组都只有一种可能的排序。根据排列组合原理,分组方式一共有
C
2
n
n
=
(
2
n
)
!
/
(
n
!
∙
(
2
n
−
n
)
!
)
=
(
2
n
)
!
/
(
n
!
∙
n
!
)
C_{2n}^n=(2n)!/(n!∙(2n-n)!)=(2n)!/(n!∙n!)
C2nn=(2n)!/(n!∙(2n−n)!)=(2n)!/(n!∙n!)种。
b.
为了表示合并两个有序列表的决策树是什么样的,我们举个简单的例子。假设要合并的两个有序列表都包含
2
2
2个元素,分别为
<
a
,
b
>
<a, b>
<a,b>和
<
c
,
d
>
<c, d>
<c,d>,其中
a
≤
b
a ≤ b
a≤b并且
c
≤
d
c ≤ d
c≤d。合并这两个序列的决策树如下图所示。
在决策树中,每个叶结点都是合并后可能的序列,每个非叶结点表示一次比较。上图决策树中,一共有6个叶结点,这符合a的结论,因为
C
4
2
=
6
C_4^2=6
C42=6。
根据a的结论,对于合并两个都包含
n
n
n个元素的有序序列的问题,它的决策树包含
(
2
n
)
!
/
(
n
!
∙
n
!
)
(2n)!/(n!∙n!)
(2n)!/(n!∙n!)个叶结点。假设该决策树的高度为
h
h
h,那么它最多包含
2
h
2^h
2h个叶结点。于是有
(
2
n
)
!
(
n
!
∙
n
!
)
≤
2
h
\frac{(2n)!}{(n!∙n!)} ≤ 2^h
(n!∙n!)(2n)!≤2h
对该不等式两边取对数,得到
h
≥
l
g
(
2
n
)
!
(
n
!
∙
n
!
)
=
l
g
(
(
2
n
)
!
)
−
2
l
g
(
n
!
)
h ≥ {\rm lg}\frac{(2n)!}{(n!∙n!)} = {\rm lg}((2n)!) - 2{\rm lg}(n!)
h≥lg(n!∙n!)(2n)!=lg((2n)!)−2lg(n!)
令
f
(
n
)
=
l
g
(
(
2
n
)
!
)
−
2
l
g
(
n
!
)
f(n) = {\rm lg}((2n)!) - 2{\rm lg}(n!)
f(n)=lg((2n)!)−2lg(n!),有
f
(
n
)
=
l
g
(
(
2
n
)
!
)
−
2
l
g
(
n
!
)
=
∑
i
=
1
2
n
l
g
i
−
2
∙
∑
i
=
1
n
l
g
i
=
∑
i
=
2
2
n
l
g
i
−
2
∙
∑
i
=
1
n
−
1
l
g
i
−
2
l
g
n
f(n) = {\rm lg}((2n)!) - 2{\rm lg}(n!) = \sum\limits_{i=1}^{2n}{{\rm lg}i} - 2∙\sum\limits_{i=1}^{n}{{\rm lg}i} = \sum\limits_{i=2}^{2n}{{\rm lg}i} - 2∙\sum\limits_{i=1}^{n-1}{{\rm lg}i} - 2{\rm lg}n
f(n)=lg((2n)!)−2lg(n!)=i=1∑2nlgi−2∙i=1∑nlgi=i=2∑2nlgi−2∙i=1∑n−1lgi−2lgn
直接对对数求和不方便,可以采用积分近似求和的方法(参考《算法导论》附录A.2)。于是有
根据以上分析,可以得到决策树的高度
h
≥
2
n
–
o
(
n
)
h ≥ 2n–o(n)
h≥2n–o(n)。这也证明了任何能够正确合并两个有序列表的算法都至少要进行
2
n
−
o
(
n
)
2n−o(n)
2n−o(n)次比较。
c.
简要说明一下。假设有两个待合并的有序序列
<
A
1
,
A
2
,
…
,
A
n
>
<A_1, A_2, …, A_n>
<A1,A2,…,An>和
<
B
1
,
B
2
,
…
,
B
n
>
<B_1, B_2, …, B_n>
<B1,B2,…,Bn>,我们现在要确定两个元素
A
i
A_i
Ai和
B
j
B_j
Bj的次序。为简化分析,假设所有元素都不相等。确定二者的次序只有两种方法:
(1) 二者直接比较:
A
i
<
B
j
A_i < B_j
Ai<Bj或者
A
i
>
B
j
A_i > B_j
Ai>Bj。
(2) 通过其他元素间接比较:
A
i
<
x
<
B
j
A_i < x < B_j
Ai<x<Bj或者
A
i
>
x
>
B
j
A_i > x > B_j
Ai>x>Bj,以及
A
i
<
x
<
…
<
y
<
B
j
A_i < x < … < y < B_j
Ai<x<…<y<Bj或者
A
i
>
x
>
…
>
y
>
B
j
A_i > x > … > y > B_j
Ai>x>…>y>Bj,
如果通过第(2)种方式,那么说明至少存在一个元素
x
x
x,使得
A
i
<
x
<
B
j
A_i < x < B_j
Ai<x<Bj或者
A
i
>
x
>
B
j
A_i > x > B_j
Ai>x>Bj成立,所以
A
i
A_i
Ai和
B
j
B_j
Bj肯定不相邻,因为二者之间至少间隔一个元素
x
x
x。反过来,如果
A
i
A_i
Ai和
B
j
B_j
Bj相邻,说明肯定不存在这样的元素
x
x
x,使得
A
i
<
x
<
B
j
A_i < x < B_j
Ai<x<Bj或者
A
i
>
x
>
B
j
A_i > x > B_j
Ai>x>Bj成立。这说明,如果
A
i
A_i
Ai和
B
j
B_j
Bj相邻,只能通过第(1)种方式来确定二者的次序,即二者直接比较。
多提一句,在排序问题中,如果在排序后的序列中两个元素相邻,那么二者也必须进行直接比较,原因与上面是一样的。
d.
注意,本题要证明的是:在最坏情况下,合并两个有序列表时的比较次数的下界为
2
n
−
1
2n−1
2n−1。
利用c的结论,如果有两个来自不同序列的元素,并且二者在合并后的序列中相邻,那么二者必须进行直接比较。我们只需要统计在合并后的序列中,有多少对相邻的元素来自不同的序列,就可以知道合并过程中至少需要比较多少次。
假设有两个待合并的有序序列
<
A
1
,
A
2
,
…
,
A
n
>
<A_1, A_2, …, A_n>
<A1,A2,…,An>和
<
B
1
,
B
2
,
…
,
B
n
>
<B_1, B_2, …, B_n>
<B1,B2,…,Bn>。最好的情况是合并后的序列中只有
1
1
1对相邻的元素来自不同的序列,比如
<
A
1
,
A
2
,
…
,
A
n
,
B
1
,
B
2
,
…
,
B
n
>
<A_1, A_2, …, A_n, B_1, B_2, …, B_n>
<A1,A2,…,An,B1,B2,…,Bn>,只有一对相邻元素
A
n
A_n
An和
B
1
B_1
B1,二者来自不同的序列。因此,最好情况下,至少只需要比较一次。
而最坏情况发生在合并之后,任意两个相邻的元素都来自不同的序列,比如
<
A
1
,
B
1
,
A
2
,
B
2
,
…
,
A
n
,
B
n
>
<A_1, B_1, A_2, B_2, …, A_n, B_n>
<A1,B1,A2,B2,…,An,Bn>。合并后的序列一共有
2
n
2n
2n个元素,相邻的元素一共有
2
n
−
1
2n−1
2n−1对。其中每一对相邻的元素都来自不同的序列,那么合并过程至少需要比较
2
n
−
1
2n−1
2n−1次。因此在最坏情况下,合并两个有序列表时的比较次数的下界为
2
n
−
1
2n−1
2n−1。