选择算法
算法导论选择算法
期望时间为线性时间的选择算法
算法思想:设数组长度为n,要求数组中第i大的数字,在待选择的数组中选择一个数x,使用Partition函数(快排中的)进行划分,假设划分为两部分:
{
A
[
1
]
,
A
[
2
]
,
.
.
.
,
A
[
k
−
1
]
}
,
{
A
[
k
+
1
]
,
A
[
k
+
2
]
,
.
.
.
,
A
[
n
]
}
\left\{ {A[1], A[2],...,A[k-1]} \right\}, \left\{ {A[k+1], A[k+2],...,A[n]} \right\}
{A[1],A[2],...,A[k−1]},{A[k+1],A[k+2],...,A[n]}
现在,A[1 ~ (k-1)]都是小于A[k]的数字,A[(k+1) ~ n]都是大于A[k]的数字。对比 k 和 i 的大小,分为三种情况:
- k = i: A[k]即是要找的数字,返回A[k]。
- k < i: 要找的数字在高区,在高区递归调用Select。
- k > i: 要找的数字在低区,在低区递归调用Select。
代码:
#include <bits/stdc++.h>
using namespace std;
int Partition(vector<int>& A, int q, int r) {
int& x = A[q], i = q + 1;
for (int j = q + 1; j <= r; j++) {
if (A[j] < x) {
swap(A[i], A[j]);
i++;
}
}
swap(A[i-1], x);
return i-1;
}
int Select(vector<int>& A, int q, int r, int target) {
if (q < 0 || r >= A.size()) return -1;
int i = Partition(A, q, r);
if (i == target) return A[i];
else if (i > target) return Select (A, q, i-1, target);
else return Select(A, i+1, r, target);
}
int main() {
vector<int> A = {5,1,2,10,7,9};
cout << Select(A, 0, A.size()-1, 5) << endl;
}
复杂度分析:
- 最好情况下,第一次划分即得到目标值,此时的复杂度是 T ( n ) = Θ ( n ) T(n)=\Theta(n) T(n)=Θ(n)。
- 最好情况下,每一次划分都将数组划分为两部分:0个元素和n-1个元素,而目标值存在n-1个元素的部分里。递归式为
T
(
n
)
=
T
(
n
−
1
)
+
Θ
(
n
)
T(n) = T(n-1) + \Theta(n)
T(n)=T(n−1)+Θ(n),现在证明
T
(
n
)
=
Θ
(
n
2
)
T(n) = \Theta(n^2)
T(n)=Θ(n2):
T ( n ) = T ( n − 1 ) + Θ ( n ) = c ( n − 1 ) 2 + Θ ( n ) = c n 2 − 2 c n + c + Θ ( n ) = c n 2 − [ c ( 2 n − 1 ) − Θ ( n ) ] ≤ c n 2 \begin{aligned} T(n) &= T(n-1) + \Theta(n) \\ &= c(n-1)^2 + \Theta(n) \\ &= cn^2 - 2cn + c + \Theta(n) \\ &= cn^2 - [c(2n-1) - \Theta(n)] \\ & \le cn^2 \end{aligned} T(n)=T(n−1)+Θ(n)=c(n−1)2+Θ(n)=cn2−2cn+c+Θ(n)=cn2−[c(2n−1)−Θ(n)]≤cn2 - 时间复杂度的期望值:
设指示器随机变量(indicator):
x
k
=
{
1
,
if k : n-k-1 split
,
0
,
otherwise
x_k = \begin{cases} 1, & \text{if k : n-k-1 split}, \\ 0, & \text{otherwise} \end{cases}
xk={1,0,if k : n-k-1 split,otherwise
由于每次的k是独立的,因此
E
(
x
k
)
=
1
n
E(x_k) = \frac{1}{n}
E(xk)=n1
将划分的所有情况的时间复杂度公式写出,则是:
T
(
n
)
≤
{
T
(
m
a
x
{
0
,
n
−
2
}
)
+
Θ
(
n
)
,
if 0, n-1 split
T
(
m
a
x
{
1
,
n
−
2
}
)
+
Θ
(
n
)
,
if 1, n-2 split
.
.
.
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
+
Θ
(
n
)
,
if k, n-k-1 split
.
.
.
T
(
m
a
x
{
n
−
1
,
0
}
)
+
Θ
(
n
)
,
if n-1, 0 split
=
∑
k
=
0
n
−
1
x
k
(
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
+
Θ
(
n
)
)
\begin{aligned} T(n) &\le \begin{cases} T(max\left\{0, n-2\right\}) + \Theta(n), &\text{if 0, n-1 split}\\ T(max\left\{1, n-2\right\}) + \Theta(n), &\text{if 1, n-2 split}\\ ... \\ T(max\left\{k, n-k-1\right\}) + \Theta(n), &\text{if k, n-k-1 split}\\ ... \\ T(max\left\{n-1, 0\right\}) + \Theta(n), &\text{if n-1, 0 split} \\ \end{cases} \\ &= \sum_{k=0}^{n-1}x_k(T(max\left\{k, n-k-1\right\}) + \Theta(n)) \end{aligned}
T(n)≤⎩
⎨
⎧T(max{0,n−2})+Θ(n),T(max{1,n−2})+Θ(n),...T(max{k,n−k−1})+Θ(n),...T(max{n−1,0})+Θ(n),if 0, n-1 splitif 1, n-2 splitif k, n-k-1 splitif n-1, 0 split=k=0∑n−1xk(T(max{k,n−k−1})+Θ(n))
故有:
E
(
T
(
n
)
)
=
E
(
∑
k
=
0
n
−
1
x
k
(
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
+
Θ
(
n
)
)
)
E(T(n)) = E(\sum_{k=0}^{n-1}x_k(T(max\left\{k, n-k-1\right\}) + \Theta(n)))
E(T(n))=E(k=0∑n−1xk(T(max{k,n−k−1})+Θ(n)))
由期望的线性性质可得:
E
(
T
(
n
)
)
=
E
(
∑
k
=
0
n
−
1
x
k
(
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
+
Θ
(
n
)
)
)
=
E
(
x
k
)
∗
E
(
∑
k
=
0
n
−
1
(
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
)
)
+
E
(
∑
k
=
0
n
−
1
Θ
(
n
)
)
=
1
n
E
(
∑
k
=
0
n
−
1
(
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
)
)
+
Θ
(
n
)
\begin{aligned} E(T(n)) &= E(\sum_{k=0}^{n-1}x_k(T(max\left\{k, n-k-1\right\}) + \Theta(n))) \\ &= E(x_k) * E(\sum_{k=0}^{n-1}(T(max\left\{k, n-k-1\right\}))) + E(\sum_{k=0}^{n-1}\Theta(n)) \\ &= \frac{1}{n}E(\sum_{k=0}^{n-1}(T(max\left\{k, n-k-1\right\}))) + \Theta(n) \end{aligned}
E(T(n))=E(k=0∑n−1xk(T(max{k,n−k−1})+Θ(n)))=E(xk)∗E(k=0∑n−1(T(max{k,n−k−1})))+E(k=0∑n−1Θ(n))=n1E(k=0∑n−1(T(max{k,n−k−1})))+Θ(n)
由于
k
k
k与
n
−
k
−
1
n-k-1
n−k−1相加固定为
n
−
1
n-1
n−1,因此
∑
k
=
0
n
−
1
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
)
≤
2
∗
∑
k
=
⌊
n
2
⌋
n
−
1
T
(
k
)
\sum_{k=0}^{n-1}T(max\left\{k, n-k-1\right\})) \le 2 * \sum_{k=\lfloor{\frac{n}{2}}\rfloor}^{n-1}T(k)
k=0∑n−1T(max{k,n−k−1}))≤2∗k=⌊2n⌋∑n−1T(k)
当n为偶数时为等号。
故上式化简为:
E
(
T
(
n
)
)
=
1
n
E
(
∑
k
=
0
n
−
1
T
(
m
a
x
{
k
,
n
−
k
−
1
}
)
)
+
Θ
(
n
)
≤
2
n
E
(
∑
k
=
⌊
n
2
⌋
n
−
1
T
(
k
)
)
+
Θ
(
n
)
=
2
n
∑
k
=
⌊
n
2
⌋
n
−
1
E
(
T
(
k
)
)
+
Θ
(
n
)
\begin{aligned} E(T(n)) &= \frac{1}{n}E(\sum_{k=0}^{n-1}T(max\left\{k, n-k-1\right\})) + \Theta(n) \\ &\le \frac{2}{n}E(\sum_{k=\lfloor{\frac{n}{2}}\rfloor}^{n-1}T(k)) + \Theta(n) \\ &= \frac{2}{n}\sum_{k=\lfloor{\frac{n}{2}}\rfloor}^{n-1}E(T(k)) + \Theta(n) \end{aligned}
E(T(n))=n1E(k=0∑n−1T(max{k,n−k−1}))+Θ(n)≤n2E(k=⌊2n⌋∑n−1T(k))+Θ(n)=n2k=⌊2n⌋∑n−1E(T(k))+Θ(n)
现在假设其上界为线性,即
E
(
T
(
n
)
)
≤
c
n
E(T(n)) \le cn
E(T(n))≤cn,通过代入法进行推导:
E
(
T
(
n
)
)
≤
2
n
∑
k
=
⌊
n
2
⌋
n
−
1
E
(
T
(
k
)
)
+
Θ
(
n
)
≤
2
n
∑
k
=
⌊
n
2
⌋
n
−
1
c
k
+
Θ
(
n
)
≤
2
n
∗
3
8
c
n
2
+
Θ
(
n
)
=
c
n
−
(
1
4
c
n
−
Θ
(
n
)
)
≤
c
n
\begin{aligned} E(T(n)) &\le \frac{2}{n}\sum_{k=\lfloor{\frac{n}{2}}\rfloor}^{n-1}E(T(k)) + \Theta(n) \\ & \le \frac{2}{n}\sum_{k=\lfloor{\frac{n}{2}}\rfloor}^{n-1}ck + \Theta(n) \\ & \le \frac{2}{n} * \frac{3}{8}cn^2 + \Theta(n) \\ & = cn - (\frac{1}{4}cn - \Theta(n)) \\ & \le cn \end{aligned}
E(T(n))≤n2k=⌊2n⌋∑n−1E(T(k))+Θ(n)≤n2k=⌊2n⌋∑n−1ck+Θ(n)≤n2∗83cn2+Θ(n)=cn−(41cn−Θ(n))≤cn
因为
Θ
(
n
)
\Theta(n)
Θ(n)在特定规模下是确定的,因此对于每种规模都能取到
c
c
c值使得上式成立。故该选择算法的期望时间复杂度为
Θ
(
n
)
\Theta(n)
Θ(n)。