page contents

如何从5亿个数中找出中位数?

轩辕小不懂 发布于 2021-10-08 11:15
阅读 859
收藏 0
分类:Golang

从5亿个数中找出中位数。数据排序后,位置在最中间的数值就是中位数。当样本数为奇数时,中位数=(N+1)/2;当样本数为偶数时,中位数为N/2与1+N/2的均值。

2098
Nen
Nen
- 程序员

分析解答:如果这道题目没有内存大小的限制,可以把所有的数字排序后找出中位数,但是最好的排序算法的时间复杂度都是O(nlogn)(n为数字的个数)。这里介绍另外一种求解中位数的算法:双堆法。

方法一:双堆法这种方法的主要思路是维护两个堆,一个大顶堆,一个小顶堆,且这两个堆需要满足如下两个特性:

特性一:大顶堆中最大的数值小于等于小顶堆中最小的数。

特性二:保证这两个堆中的元素个数的差不能超过1。在数据总数为偶数的时候,当这两个堆建立好以后,中位数显然就是两个堆顶元素的平均值。当数据总数为奇数的时候,根据两个堆的大小,中位数一定在数据多的堆的堆顶。对于本题而言,具体实现思路为:维护两个堆maxHeap与minHeap,这两个堆的大小分别为max_size和min_size。然后开始遍历数字。对于遍历到的数字data:

(1)如果data<maxHeap的堆顶元素,此时为了满足特性一,只能把data插入到maxHeap中。为了满足特性二,需要分以下几种情况讨论。

1)如果max_size<=min_size,说明大顶堆元素个数小于小顶堆元素个数,此时把data直接插入大顶堆中,并把这个堆调整为大顶堆。

2)如果max_size>min_size,为了保持两个堆元素个数的差不超过1,此时需要把maxHeap堆顶的元素移动到minHeap中,接着把data插入到maxHeap中。同时通过对堆的调整分别让两个堆保持大顶堆与小顶堆的特性。


(2)如果maxHeap堆顶元素<= data<= minHeap堆顶元素,为了满足特性一,此时可以把data插入任意一个堆中,为了满足特性二,需要分以下几种情况讨论:

1)如果max_size<min_size,显然需要把data插入到maxHeap中。

2)如果max_size>min_size,显然需要把data插入到minHeap中。

3)如果max_size==min_size,可以把data插入到任意一个堆中。

3)如果data>maxHeap的堆顶元素,此时为了满足特性一,只能把data插入到minHeap中。为了满足特性二,需要分以下几种情况讨论。

1)如果max_size>=min_size,那么把data插入到minHeap中。

2)如果max_size<min_size,那么需要把minHeap堆顶元素移到maxHeap中,然后把data插入到minHeap中。通过上述方法可以把5亿个数构建两个堆,两个堆顶元素的平均值就是中位数。这种方法由于需要把所有的数据都加载到内存中,当数据量很大的时候,由于无法把数据一次性加载到内存中,因此这种方法比较适用于数据量小的情况。对于本题而言,5亿个数字,每个数字在内存中占4B,5亿个数字需要的内存空间为2GB内存。如果可用的内存不足2G的时候显然不能使用这种方法,因此下面介绍另外一种方法。

请先 登录 后评论