线性时间选择

文章介绍了如何使用Randomized-Select算法在无序线性集合中找到第k小元素,以及如何通过改进算法,确保在最坏情况下也保持线性时间复杂度。关键步骤包括利用随机化的Partition过程和中位数划分策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

在给定线性集中有n个元素,要求找出这n个元素中第k(1<=k<=n)小的元素。给定的线性集是无序的。要求在线性时间内完成,线性时间的要求是指在最坏情况下也要保证在O(n)时间内完成选择。

以期望线性时间做选择:


一般选择问题:找出数组中第k大的元素。看起来比找最小值要复杂,但实际上两种问题的渐进运行时间相同,都是Θ(n)。Randomized-Select的这个算法很强悍,期望的时间复杂度就能达到O(n),但最坏情况下的时间复杂度却为O(n^2)。该算法采用的是快速排序章节中的Partition过程来得到划分的中点i,如果该中点恰好等于选择的点,则即为所求,否则如果k>i则在k到n区域内用同样的方法找,如果k<i再在左边区间中用同样的方法再次寻找

代码如下

int PARTITION(int A[], int p,int r)  
{  
    int x=A[r];//A[r]作为主元,围绕它来划分子数组  
    int i=p-1,j,tmp;  
    for( j=p; j<=r-1 ; j++ )  
    {  
        if( A[j]<=x )  
        {  
            i++;  
            tmp=A[j]; //小于A[r]的数往左移,交换A[i]和A[j]的值    
            A[j]=A[i];  
            A[i]=tmp;  
        }     
    }  
    tmp=A[j]; //交换A[r]和A[i+1]的值    
    A[j]=A[i+1];  
    A[i+1]=tmp;  
    return i+1;  
}  
 
int Randomized_Partition(int A[], int p, int r)
{
     int i = p + rand() % (r - p + 1);     
     int tmp=A[i];
	 A[i]=A[r];
	 A[r]=tmp;
     return PARTITION(A, p, r);
}
 
int Randomized_Select(int A[], int p, int r, int i )
{
     if( p==r )
		 return A[p];
	 int q=Randomized_Partition(A,p,r);
	 int k=q-p+1;
	 if( i == k )
		 return A[q];
	 else if( i<k )
		 return Randomized_Select(A,p,q-1,i);
	 else
		 return Randomized_Select(A,q+1,r,i-k);
}

最坏限行时间的选择

对Randomized_Select算法进行改编,保证该算法取的基准划分数尽可能好,怎可保证复杂度为O(n),步骤如下

1. 将输入数组的n个元素划分为n/5(上取整)组,每组5个元素,且至多只有一个组有剩下的n%5个元素组成。
2. 寻找每个组织中中位数。首先对每组中的元素(至多为5个)进行插入排序,然后从排序后的序列中选择出中位数。
3. 对第2步中找出的n/5(上取整)个中位数,递归调用SELECT以找出其中位数x。(如果是偶数去下中位数)
4. 调用PARTITION过程,按照中位数x对输入数组进行划分。确定中位数x的位置k。
5. 如果i=k,则返回x。否则,如果i<k,则在地区间递归调用SELECT以找出第i小的元素,若干i>k,则在高区找第(i-k)个最小元素

通过select取出的中位数作为基准数进行划分


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值