海量数据查找中位数

现在 有10亿个int型的数字(JAVA中 int 型占4B),以及一台可用内存为1GB的机器,如何找出这10亿个数字的中位数?

 

中位数定义:数字排序之后,位于中间的那个数。比如将10亿个数字进行排序(位置从1到10亿),排序之后,位于第5亿个位置的那个数 就是中位数。

关于中位数,可参考:快速排序中的分割算法的解析与应用

 

一种方法是定义一个长度为10亿的整型数组,采用排序算法排序。但是:

10亿个数字,每个数字在内存中占4B,10亿个数字完全加载到内存中需要:10*108*4B ,约为:4GB内存。显然不能把所有的数字都装入内存。

 

这里,采用基于二进制位比较 和 快速排序算法中的“分割思想”来寻找中位数。具体如下:

假设10亿个数字保存在一个大文件中,依次读一部分文件到内存(不超过内存的限制:1GB),将每个数字用二进制表示,比较二进制的最高位(第32位),如果数字的最高位为0,则将这个数字写入 file_0文件中;如果最高位为 1,则将该数字写入file_1文件中。【这里的最高位类似于快速排序中的枢轴元素】

从而将10亿个数字分成了两个文件(几乎是二分的),假设 file_0文件中有 6亿 个数字,file_1文件中有 4亿 个数字。那么中位数就在 file_0 文件中,并且是 file_0 文件中所有数字排序之后的第 1亿 个数字。

【为什么呢?因为10亿个数字的中位数是10亿个数排序之后的第5亿个数。现在file_0有6亿个数,file_1有4亿个数,file_0中的数都比file_1中的数要大(最高位为符号位,file_1中的数都是负数,file_0中的数都是正数,也即这里一共只有4亿个负数,排序之后的第5亿个数一定是正数,那么排序之后的第5亿个数一定位于file_0中)】。除去4亿个负数,中位数就是6亿个正数从小到大排序之后 的第 1 亿个数

现在,我们只需要处理 file_0 文件了(不需要再考虑file_1文件)。对于 file_0 文件,同样采取上面的措施处理:将file_0文件依次读一部分到内存(不超内存限制:1GB),将每个数字用二进制表示,比较二进制的高位(第31位),如果数字的次高位为0,写入file_0_0文件中;如果次高位为1,写入file_0_1文件 中。

现假设 file_0_0文件中有3亿个数字,file_0_1中也有3亿个数字,则中位数就是:file_0_0文件中的数字从小到大排序之后的第1亿个数字。

抛弃file_0_1文件,继续对 file_0_0文件 根据 次次高位(第30位) 划分,假设此次划分的两个文件为:file_0_0_0中有0.5亿个数字,file_0_0_1中有2.5亿个数字,那么中位数就是 file_0_0_1文件中的所有数字排序之后的 第 0.5亿 个数。

......

按照上述思路,直到划分的文件可直接加载进内存时(比如划分的文件中只有5KW个数字了),就可以直接对数字进行快速排序,找出中位数了。当然,你也使用“快排的分割算法”来找出中位数(比使用快速排序要快)

 

总结:上面的海量数据寻找中位数,其实就是利用了“分割”思想,每次将 问题空间 大约分解成原问题空间的一半左右。(划分成两个文件,直接丢弃其中一个文件),故总的复杂度可视为O(logN) N=10亿。

 

参考资料:

快速排序中的分割算法的解析与应用

五种常用的算法设计技巧之二:分治算法

海量数据处理之BitMap

 

原文:http://www.cnblogs.com/hapjin/p/5769087.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 python 中,如果要查找海量数据中位数,可以使用 heapq 库中的函数 nsmallest() 和 nlargest()。 首先,将所有数据读入内存,然后使用 heapq.heapify() 将数据堆化。接下来,调用 nsmallest() 和 nlargest() 来获取最小的 k 个数和最大的 k 个数。最后,根据这 k 个数的大小关系,就可以得出中位数。 例如,如果 k=len(data)//2,那么中位数就是最小的 k 个数中的最大值。 这种方法的时间复杂度是 O(n log n),空间复杂度是 O(n)。 注意,如果要查找数据量太大,无法一次性读入内存,就需要使用其他方法,例如流式计算。 ### 回答2: 对于海量数据中位数问题,可以使用堆排序算法来解决。 首先,将海量数据分割成多个小块,每个小块可以使用快速排序算法进行排序,再将排序好的小块使用堆数据结构进行合并。 然后,使用一个最大堆和一个最小堆来存储数据。最大堆保存一半较小的数据,最小堆保存一半较大的数据。具体实现方式如下: 1. 初始化最大堆和最小堆为空堆。 2. 依次读取海量数据,并根据数据的大小来决定插入最大堆还是最小堆。 - 如果最大堆的大小小于最小堆的大小,则将数据插入最大堆,并对最大堆进行调整,保证最大堆的堆顶(即最大值)小于等于最小堆的堆顶(即最小值)。 - 如果最大堆的大小大于最小堆的大小,则将数据插入最小堆,并对最小堆进行调整,保证最小堆的堆顶(即最小值)大于等于最大堆的堆顶(即最大值)。 3. 当读取完全部数据后,根据最大堆和最小堆的大小来决定中位数的位置。 - 如果最大堆的大小等于最小堆的大小,则中位数为最大堆的堆顶和最小堆的堆顶的平均值。 - 如果最大堆的大小大于最小堆的大小,则中位数为最大堆的堆顶。 - 如果最大堆的大小小于最小堆的大小,则中位数为最小堆的堆顶。 通过这种方式,不需要将全部数据加载到内存中,可以在读取数据的同时进行排序和求解中位数,从而适用于海量数据的情况。 ### 回答3: 在Python中,处理海量数据中位数的一种常见方法是使用堆。 首先,我们需要了解中位数的概念。对于一个有序的数据集,中位数是指将数据划分为两个等长子集,左子集中的所有元素都小于等于右子集中的所有元素。如果数据集中有奇数个元素,则中位数是中间的那个元素;如果有偶数个元素,则中位数是中间两个元素的平均值。 对于海量数据,我们无法直接将其全部加载到内存中进行排序,因此需要使用堆来解决这个问题。堆是一种特殊的树形数据结构,具有以下特点:每个节点的值都大于(或小于)其子节点的值。 我们可以使用两个堆来实现,一个大根堆和一个小根堆。首先,将数据集的前一半数据插入到大根堆中,将剩余的一半数据插入到小根堆中。这样可以确保大根堆中的所有元素都小于小根堆中的元素。然后,我们可以根据数据集的大小,采取不同的策略来计算中位数。 如果数据集的大小是奇数,中位数就是小根堆的堆顶元素。如果数据集的大小是偶数,中位数就是大根堆的堆顶元素和小根堆的堆顶元素的平均值。 在实际实现中,我们可以使用Python的heapq模块来操作堆。具体的步骤如下: 1. 利用heapq模块的heapify函数,将数据集前一半的元素插入大根堆,将剩余的一半元素插入小根堆。 2. 如果数据集的大小是奇数,直接返回小根堆的堆顶元素。 3. 如果数据集的大小是偶数,返回大根堆的堆顶元素和小根堆的堆顶元素的平均值。 对于海量数据来说,可以将数据分块读取,每次读取一部分数据,然后进行堆的操作。通过这种方式,可以有效地处理海量数据,找到中位数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值