如何从一个无序数组中求出第K大的数(假设数组中的数各不相同)。例如,对数组{5,12,7,2,9,3}来说,求第2大的数为9。
最直接的想法是对数组进行排序,然后取出第K个元素即可。但这样做的时间复杂度为O(nlogn),而随机选择算法,他对任何输入都可以达到O(n)的期望时间复杂度。
随机选择算法的原理类似于随机快速排序算法。当对A[left,right]执行一次randPartition函数后,主元左侧的元素个数就是确定的,且他们都小于主元。假设此时主元是A[P],那么A[P]就是A[left,right]中的第p-left+1大的数。不妨令M表示p-left+1,那么如果K==M成立,说明第K大的数就是主元A[P]。
int randPartition(int A[],int left,int right){
//生成[left,right]内的随机数p
int p=round(1.0*rand()/RAND_MAX*(right-left)+left);
swap(A[p],A[left]); //交换A[p]和A[left]
int temp=A[left]; //将A[left]存放至临时变量temp
while(left<right){ //只要left与right不相遇
while(left<right&&A[right]>temp) //反复左移right
right--;
A[left]=A[right]; //将A[right]挪到A[left]
while(left<right&&A[right]<=temp) //反复右移left
left++;
A[right]=A[left]; //将A[left]挪到A[right]
}
A[left]=temp; //把temp放到left与right相遇的地方
return left;
}
int randSelect(int A[],int left,int right,int K){
if(left==right) //边界
return A[left]; //划分后主元位置为p
int p=randPartition(A,left,right); //A[p]是A[left,right]中的第M大
int M=p-left+1;
if(K==M) //找到第K大的数
return A[p];
if(K<M) //第K大的数在主元左侧
return randSelect(A,left,p-1,K);
else //第K大的数在主元右侧
return randSelect(A,p+1,right,K-M);
}
需要加上头文件#include<algorithm>