(平均排序)假设我们不是要完全排序一个数组,而只是要求数组中的元素在平均情况下是升序的。更准确地说,如果对所有的 i = 1 , 2 , … , n − k i = 1, 2, …, n−k i=1,2,…,n−k有下式成立,我们就称一个包含 n n n个元素的数组 A A A为 k k k排序的( k k k-sorted):
∑ j = i i + k − 1 A [ j ] k ≤ ∑ j = i + 1 i + k A [ j ] k \frac{\sum_{j=i}^{i+k-1}{A[j]}}{k}≤\frac{\sum_{j=i+1}^{i+k}{A[j]}}{k} k∑j=ii+k−1A[j]≤k∑j=i+1i+kA[j]
a. 一个数组是 1 1 1排序的,表示什么含义?
b. 给出对数字 1 , 2 , … , 10 1, 2, …, 10 1,2,…,10的一个排序,它是 2 2 2排序的,但不是完全有序的。
c. 证明:一个包含 n n n个元素的数组是 k k k排序的,当且仅当对所有的 i = 1 , 2 , … , n − k i = 1, 2, …, n−k i=1,2,…,n−k,有 A [ i ] ≤ A [ i + k ] A[i] ≤ A[i+k] A[i]≤A[i+k]。
d. 设计一个算法,它能在 O ( n l g ( n / k ) ) O(n{\rm lg}(n/k)) O(nlg(n/k))时间内对一个包含 n n n个元素的数组进行 k k k排序。当 k k k是一个常数时,也可以给出 k k k排序算法的下界。
e. 证明:我们可以在 O ( n l g k ) O(n{\rm lg}k) O(nlgk)时间内对一个长度为 n n n的 k k k排序数组进行全排序。(提示:可以利用练习6.5-9的结果。)
f. 证明:当 k k k是一个常数时,对包含 n n n个元素的数组进行 k k k排序需要 Ω ( n l g n ) Ω(n{\rm lg}n) Ω(nlgn)的时间。(提示:可以利用前面解决比较排序的下界的方法。)
解
a.
一个数组 A A A是 1 1 1排序的,说明对所有 i = 1 , 2 , … , n − 1 i = 1, 2, … , n-1 i=1,2,…,n−1,有 A [ i ] ≤ A [ i + 1 ] A[i] ≤ A[i+1] A[i]≤A[i+1],这说明这个数组是完全有序的。
b.
2 1 4 3 6 5 8 7 10 9
c.
这一问题可以分解为两个命题,对于一个包含 n n n个元素的数组 A A A
命题a:数组 A A A是 k k k排序的
命题b:对所有的 i = 1 , 2 , … , n − k i = 1, 2, …, n−k i=1,2,…,n−k,有 A [ i ] ≤ A [ i + k ] A[i] ≤ A[i+k] A[i]≤A[i+k]
本题的意思是要证明这两个命题是等价的,需要分两步证明。
(1) 证明:命题a成立可以推导出命题b成立
如果命题a成立,即数组 A A A是 k k k排序的,那么对所有的 i = 1 , 2 , … , n − k i = 1, 2, …, n−k i=1,2,…,n−k,有
∑ j = i i + k − 1 A [ j ] k ≤ ∑ j = i + 1 i + k A [ j ] k \frac{\sum_{j=i}^{i+k-1}{A[j]}}{k}≤\frac{\sum_{j=i+1}^{i+k}{A[j]}}{k} k∑j=ii+k−1A[j]≤k∑j=i+1i+kA[j]
将上面的不等式的左边减去右边,得到
∑ j = i i + k − 1 A [ j ] k − ∑ j = i + 1 i + k A [ j ] k ≤ 0 \frac{\sum_{j=i}^{i+k-1}{A[j]}}{k}-\frac{\sum_{j=i+1}^{i+k}{A[j]}}{k}≤0 k∑j=ii+k−1A[j]−k∑j=i+1i+kA[j]≤0
即
A [ i ] k − A [ i + k ] k ≤ 0 \frac{A[i]}{k}-\frac{A[i+k]}{k}≤0 kA[i]−kA[i+k]≤0
于是可以得到 A [ i ] ≤ A [ i + k ] A[i] ≤ A[i+k] A[i]≤A[i+k]。所以命题a可以推导出命题b。
(2) 证明:命题b成立可以推导出命题a成立
命题b成立,说明对所有的 i = 1 , 2 , … , n − k i = 1, 2, …, n−k i=1,2,…,n−k有
A [ i ] ≤ A [ i + k ] A[i] ≤ A[i+k] A[i]≤A[i+k]
将上面的不等式左右两边都加上 A [ i + 1 ] + A [ i + 2 ] + … + A [ i + k − 1 ] A[i+1] + A[i+2] + … + A[i+k−1] A[i+1]+A[i+2]+…+A[i+k−1],得到
∑ j = i i + k − 1 A [ j ] ≤ ∑ j = i + 1 i + k A [ j ] \sum_{j=i}^{i+k-1}{A[j]}≤\sum_{j=i+1}^{i+k}{A[j]} ∑j=ii+k−1A[j]≤∑j=i+1i+kA[j]
将该不等式左右两边同时除以 k k k,得到
∑ j = i i + k − 1 A [ j ] k ≤ ∑ j = i + 1 i + k A [ j ] k \frac{\sum_{j=i}^{i+k-1}{A[j]}}{k}≤\frac{\sum_{j=i+1}^{i+k}{A[j]}}{k} k∑j=ii+k−1A[j]≤k∑j=i+1i+kA[j]
于是,数组 A A A是 k k k排序的。所以命题b可以推导出命题a。
d.
根据c的结论,可以考虑将数组 A A A分为 k k k组,每组最多 ⌈ n / k ⌉ ⌈n/k⌉ ⌈n/k⌉个元素。
第 1 1 1组: A [ 1 ] , A [ 1 + k ] , A [ 1 + 2 k ] , … … A[1], A[1+k], A[1+2k], … … A[1],A[1+k],A[1+2k],……
第 2 2 2组: A [ 2 ] , A [ 2 + k ] , A [ 2 + 2 k ] , … … A[2], A[2+k], A[2+2k], … … A[2],A[2+k],A[2+2k],……
… … …… ……
第 k k k组: A [ k ] , A [ 2 k ] , A [ 3 k ] , … … A[k], A[2k], A[3k], … … A[k],A[2k],A[3k],……
对每组元素采用运行时间上界为 O ( n l g n ) O(n{\rm lg}n) O(nlgn)的排序算法,例如堆排序或归并排序,即可完成对整个数组的 k k k排序。
由于每组最多 ⌈ n / k ⌉ ⌈n/k⌉ ⌈n/k⌉个元素,因此每一组排序的时间为 O ( ( n / k ) l g ( n / k ) ) O((n/k){\rm lg}(n/k)) O((n/k)lg(n/k))。一共有 k k k组,所以总的时间为 O ( n l g ( n / k ) ) O(n{\rm lg}(n/k)) O(nlg(n/k))。
e.
对于一个已经 k k k排序的数组来说,按照上文所述方法进行分组,那么每一组内的元素是有序。要对该数组进行全排序,实际上是将 k k k个有序分组进行合并。因此,可以直接采用练习6.5-9的方法,这里不对该方法进行赘述,请参考链接https://blog.csdn.net/yangtzhou/article/details/84801494。根据练习6.5-9的结果,该方法的时间复杂度为 O ( n l g k ) O(n{\rm lg}k) O(nlgk)。
f.
可以直接套用8.1节的排序决策树模型,不过 k k k排序的决策树包含的叶结点数目有所不同。对于一个有 n n n个元素的数组, k k k排序实际上是排序 k k k组序列,每个序列最多包含 ⌈ n / k ⌉ ⌈n/k⌉ ⌈n/k⌉个元素。那么 k k k排序后,数组可能的排列一共有 k ( ⌈ n / k ⌉ ! ) k(⌈n/k⌉!) k(⌈n/k⌉!)种,这也是决策树的叶结点数目。假设该决策树的高度为 h h h,那么它最多包含 2 h 2^h 2h个叶结点。于是有
k ( ⌈ n / k ⌉ ! ) ≤ 2 h k(⌈n/k⌉!)≤2^h k(⌈n/k⌉!)≤2h
对该不等式两边取对数,得到
h ≥ l g ( k ( ⌈ n / k ⌉ ! ) ) = l g k + l g ( ⌈ n / k ⌉ ! ) = Ω ( ( n / k ) l g = Ω ( ( n / k ) ( l g n − l g k ) ) h≥{\rm lg}(k(⌈n/k⌉!))={\rm lg}k+{\rm lg}(⌈n/k⌉!)=Ω((n/k){\rm lg}=Ω((n/k)({\rm lg}n-{\rm lg}k)) h≥lg(k(⌈n/k⌉!))=lgk+lg(⌈n/k⌉!)=Ω((n/k)lg=Ω((n/k)(lgn−lgk))
如果 k k k是常数,那么必然有
h = Ω ( ( n / k ) ( l g n − l g k ) ) = Ω ( n l g n ) h=Ω((n/k)({\rm lg}n-{\rm lg}k))=Ω(n{\rm lg}n) h=Ω((n/k)(lgn−lgk))=Ω(nlgn)
所以,当 k k k是一个常数时,对包含 n n n个元素的数组进行 k k k排序需要 Ω ( n l g n ) Ω(n{\rm lg}n) Ω(nlgn)的时间。