zoukankan      html  css  js  c++  java
  • 中位数的求法

      前段时间面试遇到一个小题 把我难住了,题目是数组中有N个正整数,数组存储是无序的,求数组的中位数。当时没想出好的办法 ,在离开后,到了地铁上,我想到一个办法。可以快速解决问题。之前没有研究过这个问题,这个方法全凭我用脑子想出来的。希望大家能提出更好的办法或者建议。

      假如数组中的每个正整数是四字节类型的,则数组的大小范围是 0x 00 00 00 00 到 0x 7F FF FF FF。我们一般最先想到的办法 就是采用排序的方法将数组排序,排序后位于数组 N / 2 位置的数即中位数。(这里我们为了简便,不考虑N是奇数还是偶数,如果是奇数,那就是N/2位置的数,如果是偶数,则是N/2 和 N/2+1位置上的两个数的平均值。)采用排序的办法 ,时间复杂度最少为O(NlogN),太慢。

      我想到的方法时间复杂度是O(N)。思路是这样的:

    (1)建立一个256的统计数组(记为hist),全部置0,统计原始数组(记为array)元素最高字节的出现的次数;

    (2)然后对统计数组进行遍历,找到中值所处的位置,记为mid,则hist[0]到hist[mid-1]的总和记为num_left, hist[mid+1]到hist[255]的总和记为num_right,则

      num_left + num_right + hist[mid] = N,并且 num_left <= N/2 和 num_right <= N/2

    (3)对原始数组中最高字节为mid值的所有元素的次高字节进行统计,再找出新的中值,将中值左边的总数加到num_left中,将中值d右边的总数加到num_right,以此类推,直到找到最低字节。

    下面看源代码,源代码中焉整数的范围只是0x 00 00 到 0x FF FF ,主要是为了简单阐述我的思路。

    /*
    问题:求正整数数组中的中值。正整数的范围是0 到 0xFF FF
    思路:
        (1)先对最高字节通过256的直方图求中值,并统计出中值左右两边分别的数量
        (2)求(1)求得的中值,再只对数组中所有最高字节等于中值的元素,求次高元素的中值
        (3)以此类推
     */
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include <memory.h>
    
    //数组的大小
    #define N 10001
    
    //打印数组内容
    void print(int* arr, int len);
    //求中值
    int  GetMidNum(int* arr, int len);
    //冒泡排序
    void sort_bubble(int* arr, int len);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int *arr = new int[N];
        //产生随机数
        srand((unsigned int)time(NULL));//initialize random seed;
        for (int i = 0; i < N; i++)
        {
            int a = rand() % 256;
            int b = rand() % 256;
            arr[i] = a + (b << 8);
        }
        //print(arr, N);
    
        //求中值
        clock_t t1 = clock();
        int midNum = GetMidNum(arr, N);
        clock_t t2 = clock();
        printf("求中值的结果:%x 时间:%d
    ", midNum,     (t2 - t1) );
    
        //通过排序,求中值,检测上述方法的结果是否正确
        clock_t t3 = clock();
        sort_bubble(arr, N);
        clock_t t4 = clock();
        printf("排序得中值为:%x 时间:%d
    ", arr[N / 2], (t4 - t3) );
        //print(arr, N);
        
        delete []arr;
        system("pause
    ");
        return 0;
    }
    
    void print(int* arr, int len)
    {
        printf("
    print start
    ");
        for (int i = 0; i < len; i++)
        {
            printf("%4x ", arr[i]);
            if (i % 10 == 9)
            {
                printf("
    ");
            }
        }
        printf("
    print end  
    ");
    }
    
    
    int GetMidNum(int* arr, int len)
    {
        const int HIST_NUM = 256;
        int *hist = new int[HIST_NUM];
        memset(hist, 0, sizeof(int) * HIST_NUM);
    
        //求中值
        int midNum    = 0;
        int num_left  = 0;
        int num_right = 0;
    
        //统计最高位字节,
        for (int i = 0; i < len; i++)
        {
            hist[ arr[i] >> 8 ]++;
        }
        //累积直方图
        for (int i = 1; i < HIST_NUM; i++)
        {
            hist[i] += hist[i - 1];
        }
        //求高位中值
        for (int i = 0; i < HIST_NUM; i++)
        {
            if (hist[i] - 1 >= len / 2)
            {
                midNum = i;
                num_left = hist[i - 1];
                num_right = len - hist[i];
                break;
            }
        }
    
        memset(hist, 0, sizeof(int) * HIST_NUM);
        //统计最低位字节,
        for (int i = 0; i < len; i++)
        {
            //printf("%2x %2x 
    ", arr[i], arr[i] >> 8);
            if ( (arr[i] >> 8) == midNum)
            {
                hist[ (arr[i] & 0xFF) ]++;
            }
        }
        
        int midNum2 = 0;
        for (int i = 0; i < HIST_NUM; i++)
        {
            num_left += hist[i];
            if (num_left - 1 >= len / 2 )
            {
                midNum2 = i;
                break;
            }
        }
        
        midNum = midNum << 8;
        midNum += midNum2;
        delete []hist;
        return midNum;
    }
    
    void sort_bubble(int* arr, int len)
    {
        for (int i = 0; i < len; i++)
        {
            int flag = i;
            for (int j = flag + 1; j < len; j++)
            {
                if (arr[j] < arr[flag])
                { 
                    flag = j;
                }
            }
            if ( i != flag )
            {
                int temp = arr[i];
                arr[i]   = arr[flag];
                arr[flag]= temp;
            }
        }
    }

       

  • 相关阅读:
    JavaScript实现上传图片预览[js前端实现]
    Java内存Happen-Before
    《干净架构读书笔记》——业务驱动编程
    《干净架构读书笔记》——编程范式
    Scrum中的冲刺和迭代
    Spring Cloud中通过Kafka传递自定义Header
    领域驱动开发(DDD)Web开发中的典型分层
    给开发团队减减负
    业务实体和用例
    什么是好的代码-代码Review要点
  • 原文地址:https://www.cnblogs.com/sdlypyzq/p/3321052.html
Copyright © 2011-2022 走看看