这篇博客讨论的题目很简单,就是标题所示,高效的查询数组中第k个大元素,比如一个数组中拥有1~10,乱序后第三个大元素就是3。
解决这题的方法很多,你可以:
1,先给数组排序,再直接选取第k个元素,思路简单,时间复杂度最小为o(nlogn);
2,还可以逐个排除,先排除最小的,这样接连排除k次后,就可以得到了,这个时间复杂度为o(n2)
3,用递归分治的思想来解决这题也是一个很好的思路,先找出中项数,将比中项数小的,正好等于的,大于的分别存放在 a,b,c数组中,再将他们的长度与k比较进行排除,比如k小于a数组的长度则可以排除b数组和c数组。 时间复杂度为O(logk),下面代码就是按照这个思路写的,具体解释在注释里
/*
*查询第k个大元素
*/
#include <stdio.h>
#define M 10
void quickSort(int *num,int low,int high);
void swap(int *a,int *b);
int select(int *num,int low,int high,int k);
int main(void)
{
int num[M]={7,5,3,9,2,1,4,8,6,0},k=0;
//循环输入k进行查询,当k大于数组长度时退出
do
{
scanf("%d",&k);
if(k<M) printf("the number is %d\n",select(num,0,M-1,k));
}while(k<M);
return 0;
}
//数组num中,查询第k个大元素
int select(int *num,int low,int high,int k)
{
int len = high-low+1; //求出数组长度
if(len<6) //如果数组足够小,则直接用快速排序
{
quickSort(num,low,high);
return num[k-1];
}
int group = len / 5; //将数组分为group个小组
int i=0,j=0,a=0,b=0,c=0,middle=0;
int center[M/5]={0}; //每组中项的集合
int A1[M]={0},A2[M]={0},A3[M]={0};
//求每组的中项
for(i=0;i<group;i++)
{
quickSort(num,i*5,i*5+4);
center[j++] = num[i*5+2];
}
middle = select(center,0,j-1,j/2); //中项集合中的中项
//对num数组中的元素进行判断
//比middle小的录入A1,相等的录入A2,大于的录入A3
for(i=low;i<=high;i++)
{
if(num[i]<middle) A1[a++] = num[i];
else if(num[i]==middle) A2[b++] = num[i];
else A3[c++] = num[i];
}
//对k的位置进行判断
//如果k小于a,则第k个大元素肯定存在A1数组中
//如果a+b>=k,则第k个大元素肯定存在A2数组中,又因为A2数组中的值都一样,所以可以直接返回数值,并且这个数值就是第k个大元素
//如果a+b<k,则第k个大元素肯定存在A3数组中
if(a>=k) return select(A1,0,a-1,k);
else if(a+b>=k) return middle;
else if(a+b<k) return select(A3,0,c-1,k-a-b);
}
//快速排序
void quickSort(int *num,int low,int high)
{
if(low<high)
{
int i = low+1;
int j = high;
while(i<j)
{
if(num[i]>num[low])
{
swap(num+j,num+i);
j--;
}
else i++;
}
if(num[i]>=num[low]) i--;
swap(num+low,num+i);
quickSort(num,low,i);
quickSort(num,j,high);
}
}
void swap(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}