zoukankan      html  css  js  c++  java
  • 中位数和顺序统计量(第9章)

    学习由n个不同的树的集合中选择第i个顺序统计量的问题。
    输入:一个包含n个(互异的)数的集合A,1in的整数i。
    输出:元素xA,并且 A中恰好有i个元素小于它。

    求解第i小的元素的算法设计

    1. Max 和 Min

    在一个有n个元素的集合中,确定Max 和 Min的方法是遍历。

    同时找到最大值和最小值,我们只需要最多3n/2次比较就可以确定。具体的方法是对输入的元素成对的处理,首先我们将一对输入元素进行比较,然后将较小的与最小值比较,较大的与最大值比较。这样每两个元素仅需要三次比较。

    2. 期望时间是线性时间的选择算法

    //划分算法 A[q]作为划分数组的主元
    PARTITION(A,p,q){
        x=A[q]
        i=p-1
        for j=p to q-1
            if(A[j]<=x){//将比A[q]小的数值统一按照顺序移动到前面
                i=i+1
                exchange A[i] with A[j]
            }
        exchange A[i+1] with A[q]
        return i+1; 
    }
    
    //随机划分算法 随机选择主元
    RANDOMIZED-PARTITION(A,p,q){
        i=Random(p,q)
        exchange A[q] with A[i];
        return PARTITION(A,p,q)
    }
    
    
    //Algorithms 
    //这里不是从整个数组中找,而是从其中的一段中找  递归的算法设计如下
    RANDOMIZED-SELECT(A,p,q,i){
        if(p==q)//检查递归的基本情况,A中仅仅包括一个元素这种情况下 i=1.
            return A[p]
        r=RANDOMIZED-PARTITION(A,p,q)//随机划分函数
        k=r-p+1;//小于A[r]的元素的个数的计算 
        if(i==k){
            return A[r]
        else if(i<k)
            RANDOMIZED-SELECT(A,p,r-1,i)
        else
            RANDOMIZED-SELECT(A,r+1,q,i)
        }
    
    }

    如上 RANDOMIZEDSELECT(A,p,q,i)所示,在算法中首先检查数组仅包含一个元素的情况,i=1.其他的情况,我们调用随机划分函数RANDOMIZEDPARTITION(A,p,q),类似于快速排序中的思路,将数组A划分为A[p....r1]A[r+1...q],A[r].然后计算前面部分的元素个数k=rp+1;//A[r] ,后面进行检查和递归求解。

    3. 最坏情况为线性的选择算法

      指示器随机变量(indicator random variable):给定一个样本空间S和 事件A,那么事件A对应的指示器随机变量I{A}=1(如果A发生),0(如果A不发生);显而易见,事件A对应的指示器随机变量的期望等于事件A发生的概率。实例分析见指示器随机变量

      类似于RANDOMIZED-SELECT算法,SELECT通过对输入数组的递归划分来找出所需元素,但是该算法能够保证对数组的一个好的划分。核心就是在划分主元的确定上,将PARTITION中的主元也作为输入参数进行输入。
      具体算法的文字描述:

    Step 1:把数组划分为若干个子数组,每个子数组里包含5个数,因为会有无法整除的可能,所以最后一个子数组可能会小于5.
    Step 2:用插入排序把每个组的5个数排序,然后找出中位数。
    Step 3:把获得的中位数又排序,找出中位数的中位数x。如果中位数的个数是偶数,那么取排好序的第 m/2 个数,m指的是中位数的个数。
    Step 4:把原来的数组使用类似快排的方法,分成两个部分。一部分比x大,一部分比x小。我们可以假设左边的数小,右边的数大。然后我们可以得到“中位数的中位数”的位置i.
    //这个地方是调用修改后的PARTITION,返回当前x的位置。 假设下标从1开始。
    Step 5:如果i = k, 那么那个“中位数的中位数”就是第小的数。如果 i < k, 则在低区递归调用SELECT来找出第i小的元素,如果i > k, 则在高区递归查找第i-k大的元素。

    分析算法:
      整个过程中,第1,2,4步所需时间为O(n), 注意第2步的复杂度不为O(n^2),第3步的复杂度为 T(n/5),第五步的复杂度为 T(7n/10)。注意这里第2步虽然我们使用的是插入排序,但是待排的序列长度为常数5,所以对一组的排序时间花费为O(1),对于n/5个组,其时间预期是O(n/5),即O(n)。
      时间预期为T(n)<=T(n/5)+T(7n/10+6)+O(n)

    算法伪代码描述:

    //设定主元参数的划分函数
    PARTITION(A,p,q,key){
        i=p-1;
    
        for j=p to q-1{
            if(A[j]<=key){//将比A[q]小的数值统一按照顺序移动到前面
                i=i+1
                exchange A[i] with A[j]
            }   
        }
        return i+1; 
    }
    //---------------------------------
    SELECT(A,p,q,i){
        if(A.length<5){
            InsertSort(A,p,q);
            return A[i];
        }
    
        groups=A.length/5;
        midValues[groups]=0;//声明初始化一个中位数数组
        for(int t=0;t<groups;t++){
            InsertSort(A,t*5,t*5+5);
            midvalues[t] = A[t*5+3];//中
        }
        InsertSort(midvalues,0,groups);
        if(groups/2==0){
            x=midvalues[groups/2];//中位数的中位数作为主元
        }else{
            x=midvalues[groups/2+1];//中位数的中位数作为主元
        }
    
        r=PARTITION(A,p,q,x)//设定主元的划分函数
        k=r-p+1;//小于A[r]的元素的个数的计算 
        if(i==k){
            return A[r]
        else if(i<k)
            SELECT(A,p,r-1,i)
        else
            SELECT(A,r+1,q,i)
        }
    }
    踏实 踏踏实实~
  • 相关阅读:
    leetcode------Add Two Numbers
    leetcode------Reverse Bits
    leetcode------Edit Distance
    leetcode------Rotate Image
    leetcode------Spiral Matrix
    leetcode------Sort Colors
    [转载]C#中的WebBrowser控件的使用
    [转载]WebBrowser控件表单(form)的自动填写和提交
    通过WebBrowser获取网页验证码
    HTMLDocument命名空间/引用
  • 原文地址:https://www.cnblogs.com/mrzhang123/p/5365808.html
Copyright © 2011-2022 走看看