中位数的查询

1.线性时间选择:找中位数

       元素选择问题的一般提法是∶给定线性序集中n个元素和一个整数k,1<= k<=n,要求找出这n个元素中第k小的元素,即如果将这n个元素依其线性序排列时,排在第k个的元素即为要找的元素。当k=1时,就是要找最小元素;当k= n时,就是要找最大元素;当k = (n+1)/2时,称为找中位数。

      在某些特殊情况下,很容易设计出解选择问题的线性时间算法。例如,找n个元素的最小元素和最大元素显然可以在O(n)时间完成。如果k <= n/logn,通过堆排序算法可以在O(n + klogn) =O(n)时间内找出第k小元素。当k>= n --- n/logn时也一样。

       一般的选择问题,特别是中位数的选择问题似乎比找最小元素要难。但事实上,从渐近阶的意义上看,它们是一样的。一般的选择问题也可以在O (n)时间内得到解决。下面要讨论解一般的选择问题的分治算法。该算法实际上是模仿快速排序算法设计出来的。其基本思想也是对输入数组进行递归划分。与快速排序算法不同的是,它只对划分出的子数组之一进行递归处理。

int Partition(int* nums, int left, int right)//定义一个划分函数
{
    int i = left, j = right;
    int tmp = nums[i];        //以nums[i]作为划分基准
    while (i < j)
    {
        while (i<j && nums[j]>tmp) --j;
            if (i < j)nums[i] = nums[j];
            while (i < j && nums[i] <= tmp) ++i;
            if (i < j)nums[j] = nums[i];
    }
    nums[i] = tmp;
    return i;
}
int SelectK(int* nums, int left, int right, int k)
{
    if (left == right && k == 1) return nums[left];//数组中仅有一个元素,且k=1,直接返回
    int i = Partition(nums, left, right);    //划分基准的数组下标
    int j = i - left + 1;    //划分基准是第j小元素
    if (k == j) return nums[i];         //k=j时,恰好就是划分基准,直接返回
    if (k < j) return SelectK(nums, left, i-1, k);//说明在划分基准的左面
    else return SelectK(nums, i + 1, right, k - j);//说明在划分基准的右面
}
int SelectKMin(int* nums, int n, int k)
{
    if (nullptr == nums ||n<1|| k<1 || k>n)return -1;
    return SelectK(nums, 0, n - 1, k);
}
int main()
{
    int arr[] = { 56,23,78,45,90,89,12,34,67,89,100 };
    int n = sizeof(arr) / sizeof(arr[0]);
    for (int k = 1; k <= n; k++)
    {
        int kmin = SelectKMin(arr, n, k);
        cout << k << " : " << kmin << endl;   //我们直接打印第几小的数
    }
    return 0;
}

划分以后的数组:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值