分治思想之线性时间选择

【元素选择】

【问题描述】

给定线性序集中n个元素和一个整数k,1 <= k <= n,要求找出这n个元素中第k小的元素,即如果将这n个元素依次线性序排列时,排在第k个位置的元素即为要找的元素。当k=1时,就是要找的最小元素;当k=n时就是要找的最大元素;当k=(n+1)/2时,称为中位数。

一般的选择问题(找n个元素的最小元素、最大元素以及中位数)在O(n)时间内都可以得到解决。下面将讨论一般选择问题的一个分治算法 线性时间选择。

【算法分析】

1. 找到满足要求的划分基准

(1)将n个输入元素划分成[n/5]个组,每组5个元素,除可能有一个组不是5个元素外。用任意一种排序算法,将每组中的元素排好序,并取出每组中的中位数,共[n/5]个。

(2)递归调用Select找出这[n/5]个元素的中位数。如果[n/5]是偶数,就找它的两个中位数中较大的一个。然后以这个元素作为划分基准。

注:下图为划分策略的示意图,其中n个元素用小圆点来表示,空心小圆点为每组元素的中位数,中位数的中位数x在途中标出,途中所画箭头是由较大元素指向较小元素的。

分析:设所有元素互不相同,在这种情况下,找出的基准x至少比3[(n-5)/10]个元素大,因为在每一组中有两个元素小于本组的中位数,而[n/5]个中位数中又有[(n-5)/10]个小于基准x。同理,基准x也至少比3[(n-5)/10]个元素小,而当n>=75时,3[(n-5)/10]>=n/4。所以按此基准划分所得的两个子数组的长度都至少缩短1/4。

2. Select算法如下:

template<class Type>
Type Select(Type a[], int p, int r, int k)
{
	if (r - p < 75) {
		//用某个简单排序算法对数组a[p:r]排序
		return a[p + k - 1];
	}
	for (int i = 0; i <= (r - p - 4) / 5; i++)
		//将a[p+5*i]至a[p+5*i+4]的第3小元素与a[p+i]交换位置
		//找中位数的中位数,r-p-4即上面所说的n-5
		Type x = Select(a, p, p + (r - p - 4) / 5, (r - p - 4) / 10);
	int i = Partition(a, p, r, x), j = i - p + 1;
	if (k <= j)return Select(a, p, i, k);
	else return Select(a, i + 1, r, k - j);
}

3. 算法Select的时间复杂度分析

设n=r-p+1,即n为输入数组的长度,算法的递归调用只有在n>=75时才执行。因此,当n<75时,算法Select所用的计算时间不超过常数C1。找到中位数的中位数x后,算法Select以x为划分基准调用函数Partition对数组a[p:r]进行划分,需要O(n)的时间。算法Select的for循环共执行n/5次,每次需要O(1)时间,因此for循环共需O(n)时间。

设对n个元素的数组调用Select需要T(n)时间,那么找中位数的中位数x至多用T(n/5)时间。现已证明,按照算法所选的基准x进行划分所得到的两个子数组分别至多有3n/4个元素。所以无论对哪一个子数组调用Select都至多用T(3n/4)时间。可以得到如下关于 T(n)的递归式:

解此递归式可得 T(n) =0(n)。 

4. 由于算法将每一组的大小定为5,并选取75作为是否进行递归调用的分界点。这两点保证了T(n)的递归式中两个自变量之和n/5+3n/4=19n/20=an,0<a<1。
在算法Select中,假设所有元素互不相等,这是为了保证在以x为划分基准调用函 Partition 对数组a[p:r]进行划分之后,所得到的两个子数组的长度都不超过原数组长度的3/4。当元素可能相等时,应在划分之后加一条语句,将所有与基准x相等的元素集中在一起如果这样的元素的个数m≥1,而且j≤k≤j+m-1时,就不必再递归调用,只要返回a[即可。否则最后一行改为调用Select(i+m+1,r,k-j-m)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值