当前位置: 首页 > 后端技术 > Java

美团方面:100亿数据如何求中位数?

时间:2023-04-01 22:34:48 Java

在海量数据中求中位数,内存肯定不能一下子放这么多数据。中位数的定义:数排序后,位于中间的数。例如,对100亿个数字进行排序。排序后,第50位的数为中位数。桶排序1)创建多个小文件桶,设置每个桶的取值范围,然后根据值将海量数据元素分配到对应的桶中,并记录桶中元素的个数2)根据元素的值bucketnumber中,计算中位数所在的bucket(比如有100亿条数据,第一个bucket到第18个bucket总共有49亿条数据,第19个bucket有2亿条数据,那么中位数必须在第19个桶),然后对桶进行排序,就可以找到海量数据的中值(如果内存还是不够,可以继续拆分桶;或者直接使用BitMap排序)简单用100条数据画图直观理解:分治法+基于二进制比较假设这100亿条数据都是int类型,4字节(32位)有符号整数,存储在一个非常大的文件中。用二进制表示每个数,比较二进制的[最高位](第32位),如果该数的最高位为0,则将这个数写入file_0文件;如果最高位为1,则将数字写入file_1文件。最高位是符号位,也就是说file_1中的数字都是负数,而file_0中的数字都是正数。通过这个操作,将100亿个数字分成两个文件,假设file_0文件中有60亿个数字,file_1文件中有40亿个数字。这样划分之后,想一想:中位数在哪个文件中?100亿个数的中位数是100亿个数排序后的第50亿个数。现在file_0有60亿个正数,file_1有40亿个负数。file_0中的数大于file_1中的数,排序后的第50亿个数是中位数,那么这个中位数一定位于file_0中,是file_0中所有数排序后的第10亿个数。现在,我们只需要处理file_0文件(不用再担心file_1文件了)。对于file_0文件,同样可以采取上述措施:将file_0文件的一部分依次读入内存,将每一个数用二进制表示,比较二进制[第二高位](第31位),如果数的第二高位为0,写入file_0_0;如果第二高位为1,则写入file_0_1。现在假设file_0_0中有30亿个数,file_0_1中有30亿个数,则中位数为:file_0_1中的数从小到大排序后的第10亿个数。放弃file_0_0文件,继续按照[secondhighestbit](第30位)划分file_0_1文件,以此类推