• 计算大数据的中位数


    题目:在一个大文件中有10G个整数,乱序排列,要求找出中位数(内存有2G限制,不能一次全部加装),请写出算法设计思路。

    中位数的定义:对于一个排序好的序列,如果数据有奇数个的话,中位数就取中间的一个;如果有偶数个的话,中位数一般取中间两个数的平均值。

    解题:

    思路一:堆排序(转换为求前5G大的元素)

      堆排序的常用场景之一是选择topk元素,这种做法不需要对数据进行排序,只需要拿新数据与堆顶数据进行比较即可,它也不需要一次性将全部数据都加载到内存,只需要构建一个k个大小的堆。当我们需要求前k小的数据时,构建一个大顶堆,当读取的新数据比堆顶元素大时舍弃,比堆顶元素小时,替换掉堆顶元素并进行堆化,重复这一过程直至读取完全部数据,最后堆中的数据就是前k小的数据。当我们需要求前k大的数据时,构建一个小顶堆,当读取的新数据比堆顶元素小时舍弃,比堆顶元素大时,替换掉堆顶元素并进行堆化,重复这一过程直至读取完全部数据,最后堆中的数据就是前k大的数据。

      对于10G的数据,它的中位数就是第5G个元素,但是内存只有2G,无法构建大小为5G的堆。因此,我们先遍历数据,构建一个1G大小的大顶堆,得到堆顶元素,即第1G大小的元素,然后利用该元素构建一个新的1G大小的堆,求出第2G大的元素,依次类推直至求出第5G大的元素。

      这种方法需要多次遍历全部数据,频繁的磁盘IO操作降低了效率。

    思路二:借鉴桶排序思路(推荐)

      1.假设整数为有符号的32位数据,其取值范围是[-2^31, 2^31-1],将范围等份划分10000段,即thread_1[],thread_2[]...thread_10000[]。

      2.将数据分为10组依次读入。首先装载第一个1G个数,遍历这些数,看它们落入thread_1[]至thread_10000[]的哪个区间,落入的对应区间统计计数增1;然后装载第二个1亿个数,重复比较与计数。

      3.数据全部装载一次之后,从thread_1[]的计数开始累加,直至计数累加到全部数据的一半(假设为N/2),那么第N/2个元素所在的区间thread_i[]就包含了中位数。

      4.假设中位数区间的范围是[a, b],且前面所有区间的数据计数共有m个,再次按照每组1G个元素遍历全部数据,对于处在thread_i[]区间的每个元素都进行计数。

      5.当thread_i[]区间每个元素的计数累加之和加上m第一次超过N/2时,该计数处的元素就是中位数。

      这种方法需要两次遍历全部数据,效率较高。

  • 相关阅读:
    开发一个delphi写的桌面图标管理代码
    web颜色转换为delphi
    delphi RGB与TColor的转换
    用Delphi制作仿每行带按钮的列表
    Delphi 之 编辑框控件(TEdit)
    numEdit
    DropDownList添加客户端下拉事件操作
    19个必须知道的Visual Studio快捷键
    asp.net线程批量导入数据时通过ajax获取执行状态
    详解JQuery Ajax 在asp.net中使用总结
  • 原文地址:https://www.cnblogs.com/kongzimengzixiaozhuzi/p/12982104.html
Copyright © 2020-2023  润新知