zoukankan      html  css  js  c++  java
  • 中位数和顺序统计量

    中位数和顺序统计量

    在一个由n个元素组成的集合中,第i个顺序统计量是该集合中第i小的元素。一个中位数是它所属集合的“中点元素”。当n为奇数时,中位数是唯一的,位于i=(n+1)/2处;当n为偶数时,存在两个中位数,分别位于i=n/2和i=n/2+1处。如果不考虑n的奇偶性,中位数总是出现在i=⌊(n+1)/2⌋处(下中位数)和i=⌈(n+2)/2⌉(上中位数)。

    1、最小值和最大值

    在一个有n个元素的集合中,需要做n-1次(上界)比较才能找到最小值或最大值。

    复制代码
    int MiniValue(const int *A, int len)
    {
        int minValue = A[0];
    
        for (int i = 1; i < len; ++i)
        {
            if (A[i] < minValue)
            {
                minValue = A[i];
            }
        }
    
        return minValue;
    }
    复制代码

    那么如何同时找到最小值和最小值呢?

    比较简单的思路是:只要分别独立找出最大值和最小值,各需要n-1次比较,共需2n-2次比较。下面给出一个算法,只需要最多3⌊n/2⌋次比较就可以同时找到最大值和最小值。

    思路是:记录已知的最大值和最小值,对输出元素成对地进行处理。

    (1)首先,将一对输入元素相互比较,然后将较小的与当前最小值比较,较大的与当前最大值比较,这样每对元素共需3次比较。

    (2)如果n是奇数,将最小值和最大值的初值都设为第一个元素的值,然后成对地处理余下的元素;如果n是偶数,就对前两个元素做一次比较,决定最大值和最小值的初值,然后成对地处理余下的元素。

    复制代码
     1 void MinMaxValue(const int *A, int len, int &minValue, int &maxValue)
     2 {
     3     int i, tmpMin, tmpMax;
     4 
     5     if (len % 2 == 0 && len != 0)
     6     {
     7         minValue = A[0] < A[1] ? A[0] : A[1];
     8         maxValue = A[0] + A[1] - minValue;
     9         i = 2;
    10     }
    11     else
    12     {
    13         minValue = A[0];
    14         maxValue = A[0];
    15         i = 1;
    16     }
    17 
    18     for (; i < len; i += 2)
    19     {
    20         if (A[i] < A[i + 1])
    21         {
    22             tmpMin = A[i];
    23             tmpMax = A[i + 1];
    24         }
    25         else
    26         {
    27             tmpMin = A[i + 1];
    28             tmpMax = A[i];
    29         }
    30 
    31         if (tmpMin < minValue)
    32         {
    33             minValue = tmpMin;
    34         }
    35 
    36         if (maxValue < tmpMax)
    37         {
    38             maxValue = tmpMax;
    39         }
    40     }
    41 }
    复制代码

    如果n是奇数,共进行3⌊n/2⌋次比较。如果n是偶数,共进行3(n-2)/2+1=3n/2-2次比较。

    2、期望为线性时间的选择算法

    下面介绍一种解决选择问题的分治算法。

    复制代码
    #include <iostream>
    using namespace std;
    
    int RandomizedPartition(int *A, int low, int high)
    {
        int key = A[high], tmp;
        int i = low - 1, j;
    
        for (j = low; j < high; ++j)
        {
            if (A[j] <= key)
            {
                i = i + 1;
    
                tmp = A[i];
                A[i] = A[j];
                A[j] = tmp;
            }
        }
    
        A[high] = A[i + 1];
        A[i + 1] = key;
    
        return i + 1;
    }
    
    int RandomizedSelect(int *A, int low, int high, int i)
    {
        if (low == high)
        {
            return A[low];
        }
    
        int q = RandomizedPartition(A, low, high);
        int k = q - low + 1;
    
        if (i == k)
        {
            return A[q];
        }
        else if (i < k)
        {
            return RandomizedSelect(A, low, q - 1, i);
        }
        else
        {
            return RandomizedSelect(A, q + 1, high, i - k);
        }
    }
    
    //test
    int main()
    {
        int A[] = {10, 9, 5, 4, 3, 2, 1, 8, 7, 6};
    
        for (int i = 1; i <= 10; ++i)
        {
            cout << RandomizedSelect(A, 0, 9, i) << ' ';
        }
        cout << endl;
    
        return 0;
    }
    复制代码

    说明:

    (1)RandomizedSelect的最坏运行时间为,因为每次划分时可能总是按余下的元素中最大的来进行划分,而划分操作需要时间。

    (2)与快速排序不同的是,快速排序会递归处理划分的两边,而RandomizedSelect只处理划分的一边,这一差异体现在性能上就是快速排序的期望运行时间为,而RandomizedSelect的期望运行时间为

    3、最坏情况为线性时间的选择算法

    下面介绍一个最坏情况运行时间为O(n)的选择算法Select。

    步骤1:将输入数组的n个元素划分为⌊n/5⌋组,每组5个元素,且至多只有一组由剩下的n mod 5个元素组成。

    步骤2:寻找这⌈n/5⌉组中每一组的中位数:首先对每组元素进行插入排序,然后确定每组有序元素的中位数。

    步骤3:对步骤2中找出的⌈n/5⌉个中位数,递归调用Select以找出其中位数x。

    步骤4:利用修改过的Partition版本,按中位数的中位数x对输入数组进行划分。

    步骤5:k为划分的低区元素个数+1。如果i=k,返回x;如果i<k,则在低区递归调用Select来找出第i小的元素;如果i>k,则在高区递归查找第i-k小的元素。

    说明:Select算法通过对输入数组的递归划分来找出所需元素,在该算法中能够保证得到对数组的一个好的划分。Select使用的也是快速排序的确定性划分算法Partition,做的修改是将划分的主元也作为输入参数。

     
  • 相关阅读:
    SQL Server 2008中的hierarchyid
    SQL判断空值、nvl处理与JOIN的使用
    Transact-SQL语法速查手册
    MySQL连接字符串
    如何让spark sql写mysql的时候支持update操作
    基于calcite做傻瓜式的sql优化(三)
    基于calcite做傻瓜式的sql优化(二)
    基于calcite做傻瓜式的sql优化(一)
    spark升级:从1.6升级到2.4.6的记录
    彻底解决,sparkSQL读取csv中Map字段类型的问题
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4351188.html
Copyright © 2011-2022 走看看