算法基础习题—排序、最坏情况线性时间选择算法、小顺序统计量
- 1. 1. 1. 下面的排序算法中哪些是稳定的:插入排序、归并排序、堆排序、快速排序和计数排序?给出一个能使任何排序算法都稳定的方法。你所给出的方法带来的额外时间和空间开销是多少?
- 2. 2. 2.给定一个整数数组,其中不同的整数所包含的数字的位数可能不同。但该数组中,所有整数中包含的总数字位数为 n n n。设计算法使其可以在 O ( n ) O(n) O(n)时间内对该数组进行排序。
- 3 3 3.(小顺序统计量) S E L E C T SELECT SELECT算法(找第 i i i小的元素)最坏情况下的比较次数 T ( n ) = Θ ( n ) T(n) =\Theta(n) T(n)=Θ(n),但是其中的常数项是非常大的。请对其进行优化,使其满足:
- 1. 在最坏情况下的比较次数为 Θ ( n ) \Theta(n) Θ(n)。
- 2. 当 i i i是小于 n / 2 n/2 n/2的常数时,最坏情况下只需要进行 n + O ( log n ) n+ O(\log n) n+O(logn)次比较。
1. 1. 1. 下面的排序算法中哪些是稳定的:插入排序、归并排序、堆排序、快速排序和计数排序?给出一个能使任何排序算法都稳定的方法。你所给出的方法带来的额外时间和空间开销是多少?
插入排序、归并排序、计数排序是稳定的。
将数组元素的下标也考虑在比较过程中,即对于原始数组 a r r arr arr的每一个元素 a r r [ i ] arr[i] arr[i]都建立一个结构体 a [ i ] : { v a l u e : a r r [ i ] , i n d e x : i } a[i]:\{value:arr[i],index:i\} a[i]:{value:arr[i],index:i}存入结构体数组 a a a中,在比较大小时,当 a [ i ] . v a l u e < a [ j ] . v a l u e a[i].value<a[j].value a[i].value<a[j].value或者 a [ i ] . v a l u e = = a [ j ] . v a l u e & & a [ i ] . i n d e x < a [ j ] . i n d e x a[i].value==a[j].value\&\&a[i].index<a[j].index a[i].value==a[j].value&&a[i].index<a[j].index时我们认为 a [ i ] < a [ j ] a[i]<a[j] a[i]<a[j],否则认为 a [ i ] > a [ j ] a[i]>a[j] a[i]>a[j],按照这个规则进行排序可以保证任意的排序算法均是稳定的,需要的空间是原来的两倍,额外时间在于 a [ i ] . v a l u e = = a [ j ] . v a l u e a[i].value==a[j].value a[i].value==a[j].value时对 i n d e x index index进行比较的时间,但在线性时间内,不影响总体时间复杂度。
2. 2. 2.给定一个整数数组,其中不同的整数所包含的数字的位数可能不同。但该数组中,所有整数中包含的总数字位数为 n n n。设计算法使其可以在 O ( n ) O(n) O(n)时间内对该数组进行排序。
设第 i i i个整数的位数为 c i c_i ci,有 m m m个整数,则 ∑ i = 1 m c i = n \sum\limits^{m}_{i=1}c_i=n i=1∑mci=n,若最高位数为 c m a x ≤ n c_{max}\le n cmax≤n,则此时使用基数排序的时间复杂度为 Θ ( c m a x ⋅ m ) \Theta(c_{max}·m) Θ(cmax⋅m),不满足 O ( n ) O(n) O(n)时间复杂度的要求。
考虑将数组先按数字位数进行分组,再对每一组采用基数排序,对第 i i i个有 c i c_i ci位的整数,确定它的位数需要的时间为 c i c_i ci,则确定所有分组需要的时间为 ∑ i = 1 m c i = n = Θ ( n ) \sum\limits^{m}_{i=1}c_i=n=\Theta(n) i=1∑mci=n=Θ(n)。假设总共分为 x x x组,对于第 k k k组,该组的每个元素位数为 c k c_k ck,有 m k m_k mk个元素,总位数及总元素个数分别为 ∑ k = 1 x c k = n , ∑ k = 1 x m k = m \sum\limits^{x}_{k=1}c_k=n,\sum\limits^{x}_{k=1}m_k=m k=1∑xck=n,k=1∑xmk=m,对第 k k k组采用基数排序的时间复杂度为 Θ ( c k ⋅ m k ) \Theta(c_k·m_k) Θ(ck⋅mk),总时间复杂度为 ∑ k = 1 x Θ ( c k ⋅ m k ) = Θ ( c 1 m 1 ) + Θ ( c 2 m 2 ) + … + Θ ( c x m x ) = Θ ( n ) \sum\limits^{x}_{k=1}\Theta(c_k·m_k)=\Theta(c_1m_1)+\Theta(c_2m_2)+…+\Theta(c_xm_x)=\Theta(n) k=1∑xΘ(ck⋅mk)=Θ(c1m1)+Θ(c2m2)+…+Θ(cxmx)=Θ(n),满足在 O ( n ) O(n) O(n)时间内进行排序的要求。
3 3 3.(小顺序统计量) S E L E C T SELECT SELECT算法(找第 i i i小的元素)最坏情况下的比较次数 T ( n ) = Θ ( n ) T(n) =\Theta(n) T(n)=Θ(n),但是其中的常数项是非常大的。请对其进行优化,使其满足:
1. 在最坏情况下的比较次数为 Θ ( n ) \Theta(n) Θ(n)。
2. 当 i i i是小于 n / 2 n/2 n/2的常数时,最坏情况下只需要进行 n + O ( log n ) n+ O(\log n) n+O(logn)次比较。
将输入的数组划分为 ⌊ n / 2 ⌋ \lfloor n/2 \rfloor ⌊n/2⌋组,比较次数为 ⌊ n 2 ⌋ \lfloor \cfrac{n}{2} \rfloor ⌊2n⌋,划分后每组有 2 o r 1 2\ or\ 1 2 or 1个元素,然后令每组的较小元素构成一个集合,并对该集合递归执行划分操作,当要找的第 i i i个元素 i ≥ n 2 i\ge \cfrac{n}{2} i≥2n时,跳出递归,此时比较次数为 U i ( ⌈ n 2 ⌉ ) U_i(\lceil \cfrac{n}{2} \rceil) Ui(⌈2n⌉),再对该较小元素集合中的前 i i i个数和对应的较大元素集合中的前 i i i个数执行 S e l e c t Select Select算法,共有 2 i 2i 2i个数字,若初始存在只有一个元素的分组,则将该元素加入这 2 i 2i 2i个数中参与比较,此比较次数为 T ( 2 i ) T(2i) T(2i)。
步骤 1 1 1:对于输入的 n n n个数,判断是否满足 i ≥ n 2 i\ge\cfrac{n}{2} i≥2n,不满足则执行步骤 3 3 3,若满足则对数组两两比较,需比较 ⌊ n 2 ⌋ \lfloor \cfrac{n}{2} \rfloor ⌊2n⌋次,得到两部分,其中一部分由各数对中较大数组成,另一部分由较小数组成
步骤 2 2 2:判断需要找的第 i i i小的数, i i i是否 ≥ \ge ≥由当前较小数组成的集合元素数量 n n n的一半,即是否满足 i ≥ n 2 i\ge\cfrac{n}{2} i≥2n,若满足则继续执行步骤 1 1 1,若不满足,则执行步骤 3 3 3
步骤 3 3 3:采用 S e l e c t Select Select方法对最后分组进行划分,此时前 i i i个数是该分组最小的 i i i个数,对应的较大元素的分组的元素依次大于该分组,取两个分组中前 i i i个数,若初始存在只有一个元素的分组,则将该元素加入这 2 i 2i 2i个数中参与比较,再对这 2 i 2i 2i或 2 i + 1 2i+1 2i+1个数执行 S e l e c t Select Select算法
得到:
U
i
(
n
)
=
{
T
(
n
)
i
≥
n
2
⌊
n
2
⌋
+
U
i
(
⌈
n
2
⌉
)
+
T
(
2
i
)
e
l
s
e
U_i(n)= \left\{ \begin{aligned} &T(n)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i\ge \frac{n}{2} \\ &\lfloor \cfrac{n}{2} \rfloor+U_i(\lceil \cfrac{n}{2} \rceil)+T(2i) \ \ \ else\\ \end{aligned} \right.
Ui(n)=⎩
⎨
⎧T(n) i≥2n⌊2n⌋+Ui(⌈2n⌉)+T(2i) else
i
<
n
2
i<\cfrac{n}{2}
i<2n时,比较次数为
⌊
log
2
(
n
2
i
)
⌋
\lfloor \log_2(\cfrac{\frac{n}{2}}{i}) \rfloor
⌊log2(i2n)⌋,最后运行一次
S
e
l
e
c
t
Select
Select算法,则总次数为
⌊
n
2
⌋
+
⌊
n
4
⌋
+
…
+
T
(
2
i
)
<
n
+
(
log
2
(
n
2
i
+
1
)
T
(
2
i
)
=
n
+
O
(
T
(
2
i
)
log
2
(
n
i
)
)
\lfloor \cfrac{n}{2} \rfloor+\lfloor \cfrac{n}{4} \rfloor+…+T(2i)<n+(\log_2(\cfrac{\frac{n}{2}}{i}+1)T(2i)=n+O(T(2i)\log_2(\cfrac{n}{i}))
⌊2n⌋+⌊4n⌋+…+T(2i)<n+(log2(i2n+1)T(2i)=n+O(T(2i)log2(in)),当
i
i
i为小于
n
/
2
n/2
n/2的常数时,
T
(
2
i
)
、
log
2
(
i
)
T(2i)、\log_2(i)
T(2i)、log2(i)也为常数,则总次数为
n
+
O
(
log
n
)
n+O(\log n)
n+O(logn)。