<算法导论>第九章3 最坏情况线性时间的选择

 

最坏情况线性时间的选择(找第i小的元素):

1.分组:每组最多5个元素(这里可以为5,7,...个元素);

2.找中位数:在每组中找出中位数;

3.中位数的中位数:找第2步中得到的中位数数组中的中位数;

4.划分:将第3步得到的中位数作为划分元素划分数组,返回中位数的位置k;

5.如果中位数是第i小的元素则返回,否则如果i<k,则在低区递归调用找第i小的元素;否则在高区递归找第i-k小的元素;

代码的实现稍微有一点不同。因为我们用C++编码的时候小标从0开始,最后测试了147个元素的情况来验证代码的正确性:

下面是简单的实现:

/*
x做划分元素
保证x肯定是其中的元素
*/
int Partition(DataType* A,int L,int H,DataType x)
{
    int i=L-1,j;
    for(j=L;j<=H;++j)
        if(A[j]==x) break;
    swap(A[j],A[H]);
    for(j=L;j<H;++j)
    {
        if(A[j]<=x)
        {
            ++i;
            swap(A[i],A[j]);
        }
    }
    swap(A[i+1],A[H]);
    return i+1;
}
void InsertSort(DataType* A,int L,int H)
{
    int i,j;
    DataType key;
    for(j=L+1;j<=H;++j)//插入排序
    {
        key = A[j];
        i = j-1;
        while(i>=L && A[i]>key)
        {
            A[i+1] = A[i];
            --i;
        }
        A[i+1] = key;
    }
}
inline int Mid(int L,int H)
{
    return L+(H-L)/2;
}
DataType Median(DataType* A,int L,int H)//返回中位数
{
    InsertSort(A,L,H);
    return A[Mid(L,H)];
}
DataType Select(DataType* A,int L,int H,int i)
{
    if(H-L<5)
    {
        InsertSort(A,L,H);
        return A[L+i];
    }
    int j,left,right;
    for(j=0; j<(H-L+5)/5; ++j)//分组
    {
        left=L+j*5, right=(L+j*5+4)>H ? H : L+j*5+4;
        InsertSort(A,left,right);
        swap(A[L+j], A[Mid(left,right)]);//把几个中位数放到前面
    }
    left = L;right = L+(H-L)/5;
    DataType x = Select(A,left,right,Mid(left,right)-left); //中位数的中位数
    int M = Partition(A,L,H,x);
    int K = M-L; //左侧元素个数为M-L,右侧元素个数H-M-1,中间一个位划分元素
    if(i==K) return A[M];
    else if(i<K) return Select(A,L,M-1,i);
    else return Select(A,M+1,H,i-K-1);
}
void TestSelect()
{
    const int MAX = 147; //数据的数目
    DataType A[MAX];
    int i;
    for(i=0;i<MAX;++i) A[i] = i+1;
    random_shuffle(A,A+MAX);//随机排列,打乱顺序

    cout<<"Init A:\n";
    copy(A,A+MAX,ostream_iterator<DataType>(cout," "));
    cout<<endl;

    for(int i=0;i<MAX;++i)
    {
        cout<<i<<" th element: ";
        cout<<Select(A,0,MAX-1,i)<<endl;
    }
    cout<<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值