k:找第k小的元素
一、一般线性时间选择问题
(1) 排序法
通常算法:排序;找第k小的数(但是会冗余)
(2) 堆+部分排序
意思:不构成完全堆,指利用其中一部分。
建最小堆,然后弹堆顶k次。
优点:比数组好,经得起反复找。
缺点:空间消耗大。
时间复杂度:O(n+k*logn)。【当k很小,就约等于线性效率】
(3) 堆(O(nlogk))【好方法——
把前k小的元素放入堆(最大堆)中,则堆顶为第k小的数。
优点:堆的空间很小。
(4) 快速选择(O(n))
在最坏情况下,算法randomizedSelect需要O(n2)计算时间。
但只要适当选择基准值,可以证明算法randomizedSelect可以在O(n)平均时间内找出n个输入元素中的第k小元素。
template<class Type>
Type RandomizedSelect(Type a[],int p,int r,int k)
{
if (p==r) return a[p];
int i=RandomizedPartition(a,p,r),
j=i-p+1;
if (k<=j) return RandomizedSelect(a,p,i,k);
else return RandomizedSelect(a,i+1,r,k-j);
}
二、不一般的中位数选择问题
快速选择的优化。
Type Select(Type a[], int p, int r, int k)
{
if (r-p<75) {
//用某个简单排序算法对数组a[p:r]排序;
return a[p+k-1];
};
for ( int i = 0; i<=(r-p-4)/5; i++ )
//将a[p+5*i]至a[p+5*i+4]的第3小元素
//与a[p+i]交换位置;
//找中位数的中位数,r-p-4即上面所说的n-5
Type x = Select(a, p, p+(r-p-4)/5, (r-p-4)/10);
int i=Partition(a,p,r, x),
j=i-p+1;
if (k<=j) return Select(a,p,i,k);
else return Select(a,i+1,r,k-j);
}