题目:
在给定线性集中有n个元素,要求找出这n个元素中第k(1<=k<=n)小的元素。给定的线性集是无序的。要求在线性时间内完成,线性时间的要求是指在最坏情况下也要保证在O(n)时间内完成选择。
以期望线性时间做选择:
一般选择问题:找出数组中第k大的元素。看起来比找最小值要复杂,但实际上两种问题的渐进运行时间相同,都是Θ(n)。Randomized-Select的这个算法很强悍,期望的时间复杂度就能达到O(n),但最坏情况下的时间复杂度却为O(n^2)。该算法采用的是快速排序章节中的Partition过程来得到划分的中点i,如果该中点恰好等于选择的点,则即为所求,否则如果k>i则在k到n区域内用同样的方法找,如果k<i再在左边区间中用同样的方法再次寻找
代码如下
int PARTITION(int A[], int p,int r)
{
int x=A[r];//A[r]作为主元,围绕它来划分子数组
int i=p-1,j,tmp;
for( j=p; j<=r-1 ; j++ )
{
if( A[j]<=x )
{
i++;
tmp=A[j]; //小于A[r]的数往左移,交换A[i]和A[j]的值
A[j]=A[i];
A[i]=tmp;
}
}
tmp=A[j]; //交换A[r]和A[i+1]的值
A[j]=A[i+1];
A[i+1]=tmp;
return i+1;
}
int Randomized_Partition(int A[], int p, int r)
{
int i = p + rand() % (r - p + 1);
int tmp=A[i];
A[i]=A[r];
A[r]=tmp;
return PARTITION(A, p, r);
}
int Randomized_Select(int A[], int p, int r, int i )
{
if( p==r )
return A[p];
int q=Randomized_Partition(A,p,r);
int k=q-p+1;
if( i == k )
return A[q];
else if( i<k )
return Randomized_Select(A,p,q-1,i);
else
return Randomized_Select(A,q+1,r,i-k);
}
最坏限行时间的选择
对Randomized_Select算法进行改编,保证该算法取的基准划分数尽可能好,怎可保证复杂度为O(n),步骤如下
1. 将输入数组的n个元素划分为n/5(上取整)组,每组5个元素,且至多只有一个组有剩下的n%5个元素组成。
2. 寻找每个组织中中位数。首先对每组中的元素(至多为5个)进行插入排序,然后从排序后的序列中选择出中位数。
3. 对第2步中找出的n/5(上取整)个中位数,递归调用SELECT以找出其中位数x。(如果是偶数去下中位数)
4. 调用PARTITION过程,按照中位数x对输入数组进行划分。确定中位数x的位置k。
5. 如果i=k,则返回x。否则,如果i<k,则在地区间递归调用SELECT以找出第i小的元素,若干i>k,则在高区找第(i-k)个最小元素
通过select取出的中位数作为基准数进行划分