Order statistics

描述: 寻找一个数组中第i 小的元素

很容易联想到最小值问题,O(n)内解决,但好像无法直接应用,这时最直观的就是先排序,再查找O(nlgn), 仔细想来,一旦完成排序意味者所有的元素都可以找到,而我们只需要寻找一个(常数个),显然解决方案是一个“更加泛型”的算法,这样就会出现“杀鸡用了牛刀—大材小用”,如果改用“鸡刀”显然复杂度会有所降低。
如何降低呢?与排序算法一样,就是减少不必要的比较,此时几种O(nlgn)的排序算法浮现出来,merge, quick都是只对一半的元素比较,此时也可以只对一半元素比较,第一步就是确定划分,然后决定位于哪一部分

rand_select(a,start,end,i)
    if(start == end)
        return a[start]
    p = rand_partion(a,start,end);
    k = p-start+1
    if(k==i)  //whether the pivot is the answer
        return a[p]
    else if(k>i) // in the left
        return rand_select(a,start,p-1,i)
    else //in the right
        return rand_select(a,p+1,end,i-k)

当然真实的代码中必须检测i 的合法性,分析可知,关键部分rand_partion将数据分为两部分(有点divide and conquer),然后按partion节点分为三种情况,left, current , right, 意味者每一次理想情况下只检查一半,O(n+n/2 + n/4 +…) = O(2n) = O(n).

// order statistic
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int partion(vector<int>& a, int start, int end)
{
    int key = a[start];
    int i = start;
    int j = end;
    while (i < j)
    {
        while (i<j && a[j]>key)
        {
            j--;
        }
        a[i] = a[j];
        while (i<j && a[i]<=key)
        {
            i++;
        }
        a[j] = a[i];
    }
    a[i] = key;
    return i;
}

int select(vector<int>& a, int start, int end, int i)
{
    if (i > a.size())
        return -1;
    int p = partion(a, start, end);
    int k = p - start + 1;
    if (k == i)
        return a[p];
    else if (i < k)
        return select(a, start, p - 1, i);
    else
        return select(a, p + 1, end, i - k);
}

int main(int argc, int** argv)
{
    vector<int> array;
    for (int i = 0; i < 10; i++)
        array.push_back(rand() % 100);


    cout << "old array" << endl;
    for (auto val : array)
        cout << val << "  ";
    cout << endl;

    for(int i=1;i<=array.size();i++)
        cout << select(array, 0, array.size()-1, i) << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值