2.9 线性时间选择


书本部分:

本节讨论与排序问题类似的元素选择问题。元素选择问题的一般提法是:给定线性序集中n个元素和一个整数1(1≤K<n),要求我出这 n 个元素中第人小的元素,即如果将这n个元素依其线性序排列时,排在第人个位置的元素即为要找的元素。当1-1时,就是要找的最小元素:当人一n时,就是要找最大元素;当1-(n+1)/2时,称为找中位数。在某些特殊情况 下,很容易设计出解选择问题的线性时间算法。例如,找n个元素的最小元素和最大元素显然可以在 O()时问内完成。如果 KEnllogn,通过堆排序算法可以在0(nthlogn=0(n时间内我出第化小元素。当化二n-n/logn时,也一样。一般的选择问题,特别是中位数的选择问题似乎比找最小元素要难。事实上,从渐近阶的意义上看,它们是一样的。一般的选择问题也可以在 O(n时间内得到解决。下面讨论解一般选择问题的一个分治算法 RandomizcdSelect。该算法实际上是模仿快速排序算法设计出来的,基本思想也是对输入数组进行递归划分。与快速排序算法不同的是,它只对划分出的子数组之一进行递归处理。
算法 Randomizedselect 用到了在随机快速排序算法中讨论过的 RandomizedPartition0随
机划分函数,因此划分是随机产生的。由此导致算法 RandomizedSelect 也是一个随机化算法。

要找数组alO:n-1]中第化小元素,只要调用 RandomizedSelect(a, 0,1-1,分即可。具体算法可

template<class Type>
Type RandomizedSelect(Type a[],int p,int k)
if(p==r)//如果该数组只有一个元素即长度为1那么无论你怎么取他都是第k小元素 
{
	return a[p];	
} 
int i=RandomizedPartition(a,p,r);
j=i-p+1;
if(k<=j)//判断第k小元素在那个区间
{
	return RandomizedSelect(a,p,i,k);
}else{
	return RandomizedSelect(a,i+1,r,k-j);
} 

在算法 RandomizedSelect 中执行 RandomizedPartition 后,数组aip:门被划分成两个子数
组aip门和 alit1:门,使alp:门中每个元素都不大于 ali+1:门中每个元素。接着算法计算子数组
arp:]中元素个数j。如果飞二,则alp门中第人小元素落在子数组al0:门中:如果心j,则要找
的第6小元素落在子数组alt1-门中。由于此时己知道子数组 alp:门中元素均小于要找的第化
小元素,因此要找的alp门中第化小元素是ali+1:中的第飞i小元素。
容易看出,在最坏情况下,算法 Randomizedselect 需要 S(G3计算时间。例如,在找最
小元素时,总是在最大元素处划分。尽管如此,该算法的平均性能很好。
由于随机划分函数 RandomizedPartitionO使用了一个随机数产生器 Random,能随机地产
生p和,之间的一个随机整数,因此 RandomizedPartitionO产生的划分基准是随机的。在这
个条件下,可以证明,算法 Randomizedselect 可以在O(n平均时间内找出么个输入元素中的第k小元素。下面讨论一个类似 RandomizedSelecto但可以在最坏情况下用 O(n时问就完成选择任务的算法 Select。如果能在线性时间内找到一个划分基准,使得按这个基准划分出的两个子数组的长度都至少为原数组长度的。倍co<e<1 是某个正常数),那么在最坏情况下用 O(N时间就可以完成选择任务。例如,若 8=9/10,算法递归调用所产生的子数组的长度至少缩短1/10。所以,在最坏情况下,算法所需的计算时间 I(n满足递归式 T(n≤T9n/10+0()。由此可得 Tn=0(n)。下面是重点
可以按以下步骤找到满足要求的划分基准。
① 将n个输入元素划分成「n/5J 个组,每组5个元素,除可能有一个组不是 5个元素
外。用任意一种排序算法,将每组中的元素排好序,并取出每组的中位数,共「n/5」个。
②递归调用 Select 找出这「p/5」个元素的中位数。如果「n/s」是偶数,就找它的两个
中位数中较大的一个。然后以这个元素作为划分基准。
因2-7是上述划分策略的示意图,其中几个元素用小圆点来表示,空心小圆点为每组元
素的中位数。中位数的中位数,在图中标出。图中所画箭头是由较大元素指向较小元素的。

只要等于基准的元素不太多,利用这个基淮冰划分的两个 子数组的大小就不会相差火远。为丁简化问题,我们先没所有元茶互不相同。在这和情况下,找出的基谁,至心比3l(0-5y/10J个元茶大,因为在行组中有两个元素小于本组的中位数,而Ln/5J个中位数中》
有LCn-S)10J个小于其准了。同理,基准,至少比 31(n-S/10J个元素小。而当n≥75时,
3L(n-S)/10J三m4。所以,我此基准划分所得的两个子数组的长度都至少缩短 1/4。这一点是
至关重要的。据此,我们给出算法 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]的第三小元素与a[p+i]交换位置 
	{
		Type x=Select(a,p,p+(r-p-4)/5,(r-p-4)/10);//找中位数的中位数,r-p-4即上面所说的n-5
		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);
		} 
	}
}

为了分析算法 Select 的计算时间复杂性,设1=r-p+1,即n为输入数组的长度。算法的
递归调用只有在n三75 时才执行。因此,当n<75时,算法 Select 所用的计算时间不超过一
个常数Gi。找到中位数的中位数¢后,算法 Select 以s 为划分基准调用函数 PartitionO对数
组alp门进行划分,这需要 0(n)时间。算法 Select 的 for 循环体共执行 n/5 次,每次需要 0①
时间。因此,执行 for 循环共需 O(1时间。
设对n个元素的数组调用 Select 需要Tn时间,那么找中位数的中位数*至多用 TnS)
时间。现已证明,按照算法所选的基准进行划分所得到的两个子数组分别至名有 3n/4个
元素。所以无论对哪一个子数组调用 Select 都至多用 7(3n/4)时间
总之,可以得到关于Tの的递归式
n < 75
(Con + I (n/5) + T(3n/4)
n> 75
解此递归式,可得 7n=0(m)。
由于算法将每组的大小定为 5,并选取 75 作为是否进行递归调用的分界点。这两点保
证了 Tn)的递归式中两个自变量之和 1/5+31/4=19n/20=an (O-a<1)。这是使 T(n=0(n的关
键之处。当然,除了5和75,还有其他选择。
在算法 Select 中,假设所有元素互不相等,这是为了保证在以 x 为划分基准调用函数
ParitionO对数组alp:进行划分之后,得到的两个子数组的长度都不超过原数组长度的314。
当元素可能相等时,应在划分之后加一条语句,将所有与基准x相等的元素集中在一起,如
果这样的元素的个数m二1,而且j<Kjim-1时,就不必再递归调用,只要返回al门即可。
否则最后一行改为调用 Select(itmt1,r,K-j-m)。

我的理解:

1.线性时间选择算法是什么?

线性时间选择算法(Linear-time Selection Algorithm)是一种在未排序的数组中寻找第k小元素的算法,其时间复杂度为线性级别,即O(n)。该算法的基本思想是借鉴快速排序算法的分治思想(这里启发我本书中算法之间是由联系的,我们可以比较它们研究性质)

2.线性时间选择算法的基本思路

通过一次划分操作将数组分成左右两个部分,并确定第k小元素所在的区间,然后递归处理所在的部分,最终在O(n)的时间复杂度内找到第k小元素。

3.线性时间选择算法的具体实现步骤

具体实现时

1.可以选择数组中的一个元素作为pivot(支点),将数组分为两个部分,其中一部分包含所有小于pivot的元素,另一部分包含所有大于等于pivot的元素。

2.然后,根据pivot所在的位置和k的大小关系,可以确定第k小元素在哪一部分中,只需要递归处理该部分即可。由于每次递归处理的数组规模都是原数组规模的一半左右,因此该算法的时间复杂度为O(n)。

需要注意的是,该算法并不会对数组进行排序,因此其时间复杂度要比快速排序算法的O(nlogn)更优。此外,由于算法中需要进行多次递归操作,因此其空间复杂度为O(logn)。

时空复杂度的分析:

时间复杂度分析:

首先,对于一个长度为n的未排序数组,我们需要进行O(n)次划分操作才能找到第k小元素所在的区间。

每次划分操作的时间复杂度为O(n),因为需要遍历整个数组,并根据pivot将数组分为两个部分。而且每次划分操作都会将数组的规模缩小至原来的一半左右。

接下来,我们需要递归地处理第k小元素所在的那个部分,直到找到第k小元素为止。由于每次递归的规模都是原来的一半左右,因此递归的深度最多为O(log n)。而且,在每一层递归中,我们只需要处理一个部分,因此每层的时间复杂度都是O(n)。

综上所述,线性时间选择算法的时间复杂度为O(n + n/2 + n/4 + ... + 1),这是一个等比数列,其和为2n,因此该算法的时间复杂度为O(n)。

需要注意的是,上述计算中忽略了一些常数项和低阶项,但对于大规模的数据,这些项可以忽略不计,因此该算法的实际运行时间比O(n)略高,但是远远快于O(nlogn)的时间复杂度算法。

空间复杂度的分析:

线性时间选择算法的空间复杂度为 O(1),即算法使用的额外空间与输入的规模无关,只需要常数级别的空间存储一些变量和常数。

具体来说,线性时间选择算法主要使用的空间是输入数组 A 和一些局部变量的空间,其中输入数组 A 的大小为 n,局部变量的空间使用与输入规模无关,因此总的空间复杂度为 O(1)。

需要注意的是,如果输入数组 A 是可变的,即算法对输入数组进行修改,则算法的空间复杂度可能会变为 O(n),因为可能需要额外存储一些中间结果。但是,在标准的线性时间选择算法中,输入数组是不可变的,因此空间复杂度为 O(1)。

具体应用:

线性时间选择算法的具体应用包括:

  1. 在一组数据中找到第 k 大的元素。这个问题可以通过线性时间选择算法来解决,具体做法是选取一个中位数作为基准值,将数组分为两部分,然后根据基准值和两部分的大小关系递归地继续查找。
  2. 快速寻找中位数。在一组数据中寻找中位数可以看作是寻找第 k=(n+1)/2 大的元素,其中 n 是数组大小。因此,可以使用线性时间选择算法来快速寻找中位数。
  3. 模拟主元素算法。主元素算法是指在一组数据中寻找出现次数超过一半的元素。可以使用模拟主元素算法来实现,即假设存在主元素,然后验证其是否为主元素。模拟主元素算法的关键是如何选择候选主元素,线性时间选择算法可以用来实现这一过程。
  4. 解决随机化选择问题。随机化选择是指在一组数据中随机选择一个元素作为基准值,然后根据基准值将数组分为两部分。随机化选择的目的是使算法具有随机化的特性,从而提高其效率和准确性。线性时间选择算法可以用来实现随机化选择过程中的基准值选取。
  5. 总之,线性时间选择算法在很多算法中都可以被使用,是一个非常重要的算法。

在各个学科中的应用:

线性时间选择算法在计算机科学中有广泛的应用,具体来说,它可以用于以下几个方面:

  1. 统计学:在线性时间选择算法中使用的中位数是一个重要的统计量,在各种数据分析领域都有广泛的应用。例如,中位数可以用来衡量数据的集中趋势,评估数据的异常值等。
  2. 数据库管理:在线性时间选择算法中使用的快速选择算法可以用来处理数据库中的数据排序、查询等操作。例如,快速选择算法可以用来实现Top-K查询,即查询某个数据集合中前K个最大(或最小)的数据。
  3. 数字信号处理:在线性时间选择算法中使用的快速选择算法也可以用来处理数字信号,例如对信号进行峰值检测、降噪等操作。
  4. 机器学习:在线性时间选择算法中使用的快速选择算法可以用来处理机器学习中的特征选择问题,即从海量的特征中选出一小部分最重要的特征,以提高模型的准确性和效率。
     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值