主要利用了快速排序的相当于折半查找的效率,能够在O(n)时间内找出n个数中的第k个数。减而治之,每次都能够减去一般的区间查找。代码如下。
注意此处的停止条件,是找到第k个数为止,并非k=1。注意边界条件!
测试代码时候,用了N=2000进行测试,k从1到2000,如果出错,则打印error,运行结果显示正确。
#include<iostream>
using namespace std;
void quickSort1(int A[],int n)
{
if(n<=1)
return;
swap(A[0],A[rand()%n]);
int temp=A[0];
int lo=0,hi=n-1;
while(lo<hi)
{
while(hi>lo && A[hi]>temp)//这里>和>=差别很大,尽管加上=
hi--; //后会减少交换,但是这样使得分成的两部分更加均匀了
if(hi==lo)
break;
A[lo++]=A[hi];
while(lo<hi && A[lo]<temp)//前面已经保证了必然有元素大于等于A[0],
lo++; //因此lo<hi在这里必然成立
A[hi--]=A[lo];
}
A[lo]=temp;
quickSort1(A,lo);
quickSort1(A+lo+1,n-lo-1);
}
int selectKth(int A[],int n,int k)
{
int lo=0,hi=n-1;
swap(A[0],A[rand()%n]);
int temp=A[0];
while(lo<hi)//最后以lo==hi或lo==hi+1结束循环
{
while(hi>lo && A[hi]>temp)
hi--;
if(hi==lo)
break;
A[lo++]=A[hi];
while(lo<hi && A[lo]<temp)
lo++;
A[hi--]=A[lo];
}
A[lo]=temp;
if(lo+1==k)
return A[lo];
else if(lo+1>k)
selectKth(A,lo,k);
else
selectKth(A+lo+1,n-lo-1,k-lo-1);
}
int selectKth1(int A[],int n,int k)
{
int lo=0,hi=n;
swap(A[0],A[rand()%n]);
while(lo<hi)
{
while(--hi>lo && A[hi]>A[0]);
if(lo==hi)
break;
while(++lo<hi && A[lo]<A[0]);
swap(A[lo],A[hi]);
}
swap(A[0],A[lo]);
if(lo+1==k)
return A[lo];
else if(lo+1>k)
selectKth1(A,lo,k);
else
selectKth1(A+lo+1,n-lo-1,k-lo-1);
}
int main()
{
const int N=2000;
int A[N],K[N];
generate_n(A,N,rand);
for(int i=1;i<=N;i++)
K[i]=selectKth1(A,N,i);
quickSort1(A,N);
for(int i=0;i<N;i++)
if(A[i]!=K[i+1])
cout<<"error"<<endl;
system("pause");
return 0;
}