递归与分治策略之利用中位数线性时间选择

前言

这一篇文章就上上一篇博文算法的进一步优化了!
这里我们就利用中位数来进行线性时间的选择算法!

中位数就是指将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的那个数据就是中位数。

算法思路

(1)将输入的n个数划分成 n5 个组,当然最后一组的数目可能是小于5的!
(2)用任意的排序方法对他们进行排序,并取出一共 n5 个中位数。
(3)找出该 n5 个中位数中的中位数。(如果 n5 是偶数则取相对大的那个数)
(4)将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。

我们用小圆点表示元素,得到如下图:
递归与分治策略之利用中位数线性时间选择_第1张图片

说明:
图中中间白色圈表示各组数据的中位数,最中间灰色表示中位数的中位数! 箭头是从较小的数指向较大的数!

故我们可以使用该数作为划分的基准(比上一个随机基准的方法会好很多)!

递归与分治策略之利用中位数线性时间选择_第2张图片

图中

3A1=3(n5)10

当n≥75时,3A1大于等于 14n 。所以按此基准划分所得的左右2个子数组的长度都至少缩短 14

代码描述

int Select(int a[],int p,int r,int k)   
{  
    if(r-p<75)  
    {  
        //这里对数组 a[p->r] 进行排序 
        return a[p+k-1];  
    }  
    //(r-p-4)/5相当于n-5  
    for(int i=0; i<=(r-p-4)/5; i++)  
    {  
        //这里将元素每5个分成一组,分别排序,并将该组中位数与a[p+i]交换位置  
        //使所有中位数都排列在数组最左侧,以便进一步查找中位数的中位数  
    }  

    int x = Select(a,p,p+(r-p-4)/5,(r-p-4)/10);  //找中位数的中位数  
    int i = Partition(a,p,r,x); //以x为基准对数组a进行划分 

    int j = i-p+1;  
    if(k<=j)  
    {  
        return Select(a,p,i,k);  
    }  
    else  
    {  
        return Select(a,i+1,r,k-j);  
    }  
}  

你可能感兴趣的:([,算法,算法基础,])