【分治】线性时间选择(C++)

一、线性时间选择

1. 问题描述

给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素。

2. 线性时间选择-随机划分

算法步骤:

  1. 生成1个随机数 i ,将数组a[p:r]被划分成两个子数组a[p, i]和a[i+1, r];
  2. 使a[p, i]中每个元素都不大于a[i+1, r]中每个元素;
  3. 计算子数组a[p, i]中的元素个数j,如果k<=j,则a[p, r]中第k小个元素落在子数组a[p, i]中;如果k>j,则要找的第k小的元素落在子数组a[i+1, r]中。
  4. 递归的使用这种分割,直到子数组只有1个元素。

3. 线性时间选择-中位数

基本思想:

  • 如果能在线性时间内找到一个划分基准,使得按这个基准划分出的两个子数组的长度都至少为原数组长度的ε倍(0<ε<1是某个正常数),那么在最坏情况下用O(n)时间就可以完成选择任务。
  • 例如,若ε=9/10,算法递归调用所产生的子数组的长度至少缩短1/10。所以,在最坏情况下,算法所需的计算时间T(n)满足递归式T(n)<=T(9n/10)+O(n)。由此可得T(n)=O(n)。

算法步骤:

可以按以下步骤找到满足要求的划分基准。

  1. 将n个输入元素划分成「n/5」个组,每组5个元素,除可能有一个组不是5个元素外。用任意一种排序算法,将每组中的元素排好序,并取出每组的中位数,共「n/5」个。
  2. 递归调用Select找出这「n/5」个元素的中位数。如果「n/5」是偶数,就找它的两个中位数中较大的一个。然后以这个元素作为划分基准。

示意图:

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

二、分治算法实现

1. 编写程序代码

线性时间选择-随机划分:

// 完整程序待补全...

// 线性时间选择-随机划分
int RandomizedSelect(int a[], int p, int r, int k)
{
	if (p == r)
		return a[p];
	
	// 数组a[p:r]被划分成两个子数组a[p, i]和a[i+1, r],
	// 且a[p, i]中每个元素都不大于a[i+1, r]中每个元素。
	int i = RandomizedPartition(a, p, r);
	// 左子数组a[p, i]的长度
	int j = i - p + 1;
	
	// k<=j,则第k小元素在左子数组,否则在右子数组
	if (k <= j)
		return RandomizedSelect(a, p, i, k);
	else
		return RandomizedSelect(a, i + 1, r, k - j);
}

线性时间选择-中位数:

// 线性时间选择-中位数
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]的第3小元素与a[p+i]交换位置
		
		Type x = Select(a, p, p + (r - p - 4) / 5, (r - p - 4) / 10); // 找中位数的中位数,(r-p-4)/5即n-5
		int i = Partition(a, p, r, x);
		int j = i - p + 1;
		if (k <= j)
			return Select(a, p, i, k);
		else
			return Select(a, i + 1, r, k - j);
	}
}

2. 运行结果展示

To be continue……

三、友情链接~


最后,非常欢迎大家来讨论指正哦!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值