快速选择(quick select) + 线性时间选择(linear-time select) - 求出n个数中第k大的数

原文链接:http://blog.csdn.net/jiyanfeng1/article/details/8543855

利用快速排序中partition函数,很容易求出n个数中第k大的数,因此在划分后如下图。



左半(包括q)有j = q - p + 1个元素。如果k < j,只需要在左半找第k大元素;如果k > j,需要在右半找第k - j大元素。可以证明,期望时间复杂度为O(n)。


int partition ( int p , int q)
{
	int x = a[p], i = p;
	for(j = p +1; j <= q; j ++)
		if(a[j] <= x) swap (a[++i], a[j]);
			swap (a[p], a[i]);
	return i;
}

int select ( int p , int r , int k){
	if(p == r) return p;
	int i = p + rand()%(r–p+1); swap (a[i], a[p]);
	int q = partition (p , r);
	int j = q– p + 1;
	if(k == j) return q;
	else if(k < j) return select (p , q , k);
	else select (q+1 , r , k-j);
}



快速选择在期望意义下是线性的,事实上还存在最坏情况线性的算法。它由Blum, Floyd, Pratt, Rivest和Tarjan于1973年提出。

它的思想是:pivot不是随机选择,而是采取某种确定性的策略,使得每次递归调用后保证长度至少缩短为原来的a倍(a < 1)。这样,T(n)<= T(an)+O(n),由主定理得T(n)=O(n)。


如图8.1.2所示,把所有元素分成5个一组共约n/5组,每组用暴力法求出中位数(图中为中心行白点所示),一共有n/5个中位数。用递归法求出这n/5个数的中位数x,则所有k个中位数中至少有约n/10个数比x小。由于每个中位数在自己组中至少有3个数不比它大(也就不会比x大),因此至少有3(n/10) = 0.3n个数比x小。更精细的分析指出,当n>=75时至少有n/4个数比x小。同理,也至少有n/4个数比x大。求n/5个数的中位数需要T(n/5)的时间,而划分后的选择不超过T(3n/4),因此T(n)>=T(n/5)+T(3n/4)+O(1),解为T(n)=O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值