最坏情况为线性时间的选择算法---算法导论学习笔记(2)

前面学习了在期望时间内选择任意顺序统计量,这次就运用这种顺序统计量的选择去实现线性时间的选择。
1.算法概述

     1.将集合分成ceil(n/5)个组,即每个组中的元素都为5,最后一组元素数量为n mod 5
     2.对每个组分别使用插入排序,并寻找出每个组的中位数。
     3.每个组的中位数形成数量为ceil(n/5)的集合,在此集合内再求其中位数,即中位数的中位数,记为x。(这里就要再次递归调用select函数)
     4.使用分区函数partition(就是上次笔记里学习到的partition分区),得到索引i,索引位置之前的低分区要比索引位置之后的高分区数量x小1
     5.如果i=k,则返回x;如果i<k,则递归调用低分区(left,i-1,k);如果i>k,则递归调用高分区(i+1,right,k-i)

以上就是整个算法的过程,看起来比较的笼统,因为真正涉及到实现的时候有挺多的细节问题要注意到。尤其是在第(5)步递归调用的时候,需要控制好边界条件和分区函数的思路一样。
2.Java实现

public class SelectN {
    public static void InsertSort(int[] arr,int start,int end) {
        for(int i=start;i<=end;i++) {
            for(int j=start;j<i;j++) {
                if(arr[i]<arr[j]) {
                    int x=arr[i];
                    for(int k=i;k>j;k--) {
                        arr[k]=arr[k-1];
                    }
                    arr[j]=x;
                    break;
                }
            }
        }
    }
    public static int partition(int[] arr,int start,int end,int key) {
        int i=start;
        int j=end;
        while(true) {
            while(i<end&&arr[i]<=key)
                i++;
            while(arr[j]>key)
                j--;
            if(i>=j)
                break;
            swap(arr,i,j);
        }
    swap(arr,findk(arr,key),j);       //交换最终结果
        return j;
    }
    //获得元素的索引
    public static int findk(int[] arr,int key) {
        for(int i=0;i<arr.length;i++)
            if(arr[i]==key)
                return i;
        return -1;
    }

    public static int select(int[] arr,int left,int right,int k) {
        if(right-left<5) {
            InsertSort(arr,left,right);
            return arr[left + k - 1];
        }
        int group=(right-left+5)/5;
        for(int i=0;i<group;i++) {
            int l=left+i*5;
            int r;
            if(left+i*5+4>right)
                r=right;
            else
                r=left+5*i+4;
        InsertSort(arr,l,r);           
        swap(arr,left+i,(r+l)/2);        //将中位数都放在第一组集合中
        }
    InsertSort(arr,left,left+group-1);   //对中位数进行排序
        int line=select(arr,left,left+group-1,(group+1)/2);
        int lower=partition(arr,left,right,line);  //得到中位数的中位数分区后的索引
        if(k==lower)                        //若索引等于k,则直接返回
            return arr[lower];
        else if(k<=lower-1)
            return select(arr,left,lower-
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值