分治法---查询数组中第k个元素

    这篇博客讨论的题目很简单,就是标题所示,高效的查询数组中第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;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要出家当道士

打赏是不可能,这辈子都不可能

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值