zoukankan      html  css  js  c++  java
  • ZOJ 3499. Median

        地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4322

        题意:寻找中位数。对于一个(浮点数)数组,如果含有奇数个元素,“中位数”就是排序后位于数组中间那个。如果含有偶数个元素,“中位数”是排序后数组中间那两个元素的平均值。

        

        此题应该是直接取自《算法导论》第9章(中位数和顺序统计学)的命题。如果对数组排序,再得出中位数,时间复杂度是 O(n log n) ,但这样的效率不高。对于这个命题不需要排序,算法导论的 9.2 节给出平均情况为 O(n)的方法,代码类似快排,其最差情况是 O(n^2),但由于对数组随机选取一个点作为分割点,所以最差情况几乎不可能发生。第 9.3 节给出一种最差情况也能达到线性时间的方法,但编码实现比较麻烦。书中也没有给出伪码。以下代码是第 9.2 节中的方法:

    #include <stdio.h>
    #include <stdlib.h>
    
    double nums[500];
    
    void exchange(double* A, int i, int j)
    {
        double tmp;
        if(i != j)
        {
            tmp = A[i];
            A[i] = A[j];
            A[j] = tmp;
        }
    }
    
    /* 以A中最后一个元素作为分割点,把A就地划为为两个子序列 */
    int fix_partition(double* A, int begin, int end)
    {
        double x = A[end];
        int i = begin - 1, j;
        for(j = begin; j < end; j++)
        {
            if(A[j] <= x)
            {
                i++;
                exchange(A, i, j);
            }
        }
        exchange(A, i+1, end);
        return i + 1;
    }
    
    /* 从A中随即取一个元素作为分割点,把A就地划为为两个子序列 */
    int random_partition(double* A, int begin, int end)
    {
        int i = rand() % (end - begin + 1) + begin;
        exchange(A, i, end);
        return fix_partition(A, begin, end);
    }
    
    /* 返回数组 A[begin, ..., end] 中第 i 小的数字,即排序后的 A[begin + i -1]  */
    double random_select(double* A, int begin, int end, int i)
    {
        if(begin == end)
            return A[begin];
    
        int q = random_partition(A, begin, end);
        int k = q - begin + 1;
        
        if(i == k)
        {
            return A[q];
        }
        else if(i < k)
        {
            return random_select(A, begin, q-1, i);
        }
        else
        {
            return random_select(A, q+1, end, i-k);
        }
    }
    
    
    int main(int argc, char* argv[])
    {
        int i, j;
        int T, n;
        scanf("%ld", &T);
        double result;
        for(i = 0; i < T; i++)
        {
            scanf("%ld", &n);
            for(j = 0; j < n; j++)
                scanf("%lf", nums + j);
    
            if(n & 1)
            {
                result = random_select(nums, 0, n-1, n/2+1);
            }
            else
            {
                result = random_select(nums, 0, n-1, n/2);
                result += random_select(nums, 0, n-1, n/2+1);
                result *= 0.5;
            }
            printf("%.3lf\n", result);
        }
        return 0;
    }

        参考资料:

        (1)《算法导论》第9章,中位数和顺序统计学。

  • 相关阅读:
    C计算double能精确到多少位
    C计算int最大值、最小值
    AndroidStudio右键new无activity
    java替换特殊字符串 $
    lamda表达式排序
    docker toolbox 设置镜像加速
    tomcat优化
    nginx配置相关
    SQL 优化
    elasticsearch 概念初识
  • 原文地址:https://www.cnblogs.com/hoodlum1980/p/2547201.html
Copyright © 2011-2022 走看看