在O(n)时间内找出n个数中的第k个(《编程珠玑》第11章)

主要利用了快速排序的相当于折半查找的效率,能够在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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值