Day_16,最坏情况为线性的选择算法之找到第position小的数

算法思路如下

在这里插入图片描述

#include<iostream>
#include<stdlib.h>
#include <math.h>
using namespace std;

//交换函数
void swap(int a[], int i, int j)
{
    int tmp=a[i];
    a[i] = a[j];
    a[j] = tmp;
}

//你们所熟悉的快速排序,但是这里只用了一个指针
//也可以如第一篇博客所写的那样采用两个指针(头尾)
int Partition(int *arr, int left, int right,int pivot)
{
    int x = arr[pivot];
    swap(arr,right,pivot);
    int i = left -1;
    for (int j=left;j<right;j++)
    {
        if (arr[j]<=x)
        {
            i++;
            swap(arr,i,j);
        }
    }
    swap(arr,i+1,right);
    return i+1;
}

//通过插入排序找到中位数
int InsertSortAndFindMid(int *arr, int left,int right)
{
    int len = right-left;
    int mid = floor((left+right)/2);
    for (int i=left+1;i<=right;i++)
    {
        int key=arr[i]; //保存此时交换节点的值
        int j=i-1; //i之前的数组
        while((j>=left) && (key<arr[j])){
            arr[j+1]=arr[j];//将值比key大的右移1位
            j--;
        }
        arr[j+1]=key;//此时j+1的位置是空出来的,右侧全是比key大的值
    }
    return mid;
}

int Select(int *arr, int left, int right, int position)
{
    if (right-left+1<5)
    {
        InsertSortAndFindMid(arr,left,right);
        return arr[left+position-1];
    }
    int group = (right-left+5)/5; //划分组数
    for(int i = 0;i<group;i++)
    {
        int l = left+5*i;
        int r = (left + i * 5 + 4) > right ? right : left + i * 5 + 4;  //如果超出右边界就用右边界赋值
        int mid = InsertSortAndFindMid(arr, l, r);
        swap(arr, left + i, mid);     // 将各组中位数与前i个
    }
    int pivot = Select(arr,left,left+group,(group+1)/2);//中位数的中位数
    int q = Partition(arr,left,right,pivot);
    int len = q-left+1; //[left,q]的长度
    if (position==len)
        return arr[q];
    else if (position<len)
        return Select(arr,left,q-1,position);
    else
        return Select(arr,q+1,right,position-len);
}

//这里所有的函数都包含right
//position 是从1开始的 不包含0
int main()
{
    int midNum1;
    //int data[3] = {5,3,2};
    int data[21] = { 2,6,8,99,45,63,102,556,10,41,11,23,25,64,62,75,83,46,53,29,95 };
    midNum1 = Select(data, 0, sizeof(data)/sizeof(*data)-1,20);
    cout<<"midNum1="<<midNum1<<endl;
    return 0;
}

代码如上,排序结果如下,可以自行测试
在这里插入图片描述

运行时间下界的计算

ceil(向上取整) floor(向下取整) x(中位数的中位数)
1、 上述将数组分为 ceil(n/5),经过x为“主元”的划分之后,最起码可以确定除了划分不足5个的那组+主元x所在的那组这两组,**ceil(n/5)**组中至少有一半的组中存在3个元素大于x,因此不计算上述两组,比x大的元素至少有
3(ceil(1/2×ceil(n/5)-2)≥3×(1/2×n/5 -2) =3n/10-6
2、 因此在文初的第五步中,需要用Select进行递归遍历的最多只有 7n/10+6个元素
3、 假设文初步骤 1、2、4需要的时间为 O(n),步骤3为 T(ceil(n/5)) , 步骤5最多为 T(7n/10+6)
因此得到下式子,(先暂时不管140这个值)
在这里插入图片描述
4、 进行替代, 令O(n)≤an, T(n)≤cn,其中a和c为适当打的常数 (大于0),将两式子带入上式得到
在这里插入图片描述
5、 让上式最多是cn,因此 -cn/10+7c+an ≤ 0
进行化简得到 c(7-n/10)≤-anc≥an/(n/10-7)=10a × n/(n-70) ,观察式子可知当 n>70的时候,方可满足a,c均大于0
又因为 n≥140,所以 n(n-70)≤2 即当 c≥20a 的时候 仅存在一个cn ,证得最坏情况下 运行时间为线性

思考,为什么是划分成5个一组,如果是7个、3个一组还是线性的吗

1、当7个一组的时候: 最后计算会得到 T(n)≤cn+(-cn/7+9c+an),可得到当n>63的时候,方可满足a,c均大于0
又因为 n≥140,所以 n(n-63)<2 即当 c≥14a 的时候 仅存在一个cn ,证得最坏情况下 运行时间为线性

2、当3个一组的时候: 最后计算会得到 T(n)≤cn+5c+an,因为 5c+an>0,所以证得最坏情况下 运行时间不是线性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值