大数据排序算法总结

1、(算法课大报告)大数据的查找与排序

2、算法的力量:位运算在排序与搜索中的应用

3、大数据分析中常用的7种排序算法的视觉图

4、对大数据量进行排序--位图法

5、大数据排序的实现代码, 理论上支持几百亿没问题吧

6、大文件内数据排序问题:采用文件映射内存技术

7、堆排序 海量数据求前N大的值

8、大数据排序相关

9、【参考】给大数据量的磁盘文件排序

10、大数据排序问题Java实现

11、大数据算法:对5亿数据进行排序

12、桶排序之大数据排序

13、大数据集上排序算法性能的体验

14、编程珠玑 第一章 大数据排序

15、Hadoop-MapReduce-TeraSort-大数据排序例子

16、【大数据】大数据排序或取重或去重相关问题

17、大数据处理算法三:分而治之/hash映射 + hash统计 + 堆/快速/归并排序

18、大数据多路归并排序(重要)

19、大数据面试题(重要)

20、常用 大数据量、海量数据处理 方法 / 算法总结

21、大数据计算:如何仅用1.5KB内存为十亿对象计数

22、【开车了】9个大数据竞赛思路分享

23、大数据, 海量数据算法

24、DOM4J解析大数据的方案


一、查找


1、位图法10亿个正整数,只有其中1个数重复出现过,要在O(n)的时间里面找出这个数,内存要尽可能少(小于100M)


(1)首先看一下10亿个正整数,正整数可以表示的范围为1到2的31次方-1。

10亿也就是1*10^9,2^31次方=2*1024*1024*1024>20亿,再想起int为32位。再想起位图法。位图法也就是对于出现的数,其中每1bit代表这个数,如果该位为1,则说明该数出现;如果该位为0,则说明该数没有出现。那多大的内存能够表示10亿的数呢?

1 byte = 8 bit
1024 byte = 8*1024 bit = 1k
1024 k = 8*1024*1024 bit = 1M = 8388608 bit


     将10,0000,0000处以8388608得到119.20928955078125,也就是差不多120M的内存,可以表示全10亿的数。所以可以建立120M的一个位图,将其所有位设置为0,然后开始遍历这10亿个整数,每遍历一个,则对应到位图中相应的位置1,如果对应到位图中相应的位已经置1了,则说明这个数是要找的那个重复的数。用这种方法,最多就是遍历一遍,将这个10亿个正整数遍历完。而使用的内存为120M左右。
     当然,题目中要求是小于100M。其实写到这里,似乎感觉这个题目是在哪里看到过。似乎是《编程珠玑》或者类似的书中,当然,最初的来源肯定是编程珠玑,关于电话号码的部分。于是下一步我就是将这本书翻出来,结果就是在开篇就是关于这个问题。
不过我们遇到的问题是10亿个数,100M内存。而书中的问题是10^7个正整数,1M的可用主存。书中的问题乘以100,就正好是我们遇到的问题了。不过书中的问题是去掉所有重复的数,并将结果是一个有序的排列。
     如果严格的使用100M以下内存的话,我们只能利用磁盘作为虚拟存储空间。如果使用磁盘的话,应该就会涉及到外排序之类的。或者是虚拟内存的管理,页面的换入换出?
     其实我们这里的问题并不需要完全排序,而只是需要找出重复的数就可以。是否可以不用排序就得到?再想想,其实题目出的有问题,应该是最大不会超过10亿,不然位图法也不行。或者就需要做hash来得到对应关系了。


(2)100M的内存=100*1024*1024*8bit=8,3886,0800 bit。我们做个取整,那么100M可以用的bit数将由8亿


     那么用每个bit来表示1个数,0表示没有出现,1表示出现,我们用取模的方式num%8亿来将数映射到8亿个bit中去,最前的2亿个bit会被重复映射,而剩下的6亿个bit只被映射一次(step1,遍历一次);由于10亿个正整数,只有其中1个数重复出现过,因此如果在映射到这后6亿个bit中,若发现某bit位已经是1,那么我们就提前找到这个数了;否则我们可以认为重复的数是那些被映射到前2亿位的数。因此只要在第一遍映射中没有发现重复的数,则接下来我们只需要用4亿个bit来判断重复的数,即,前2亿个bit用来记录num/2亿=0的数,而后2亿个位用来记录num/2亿=4的数,这样同样若发现某bit位已经是1,那么我们就提前找到这个数了(step2,遍历一次)。一共遍历了2遍,时间复杂度O(2n)=O(n)。

2、分割法10亿个不重复的整数,查找数值大小在中间的数,要求给出效率最高的算法

/*   我的思路是这样的,假设是32位的无符号整数,共有2^32 = 2^16 * 2^16 个整数,把全部整数等分成2^16个区间
然后统计每个区间里面的数的个数,确定中位数是在哪个区间里面,再对10亿个数中落在该区间里面每个数上的个数进行计数
这样进行从小进行加和就可以确定中位数了
*/

//这里没有考虑10亿个数是怎么存储,怎么读的,只是假设他存在数组a[N]中, N在这里等于10亿

int SelectMedian()
{
int zone[2^16] = { 0 };
int MediumZone[2^16] = { 0 };
int i = 0;

for(; i< N ; i++)
   zone[a/(2^16)]++;

int sum = 0; 
i = 0;

do
   sum += zone[i++];
while(sum < N/2)

sum -= zone[i-1];
izone = i-1;  //这里,我们把中位数所在区间叫中位组,存储中位组的标号
int floor = 2^16 * izone, ceiling = 2^16 * (izone + 1);
//floor 和ceiling 用来存储 中位组的下限和上限
for(i=0; i= floor && a <= ceiling)
          MediumZone[a-floor]++;

i=0;
do
   sum += MediumZone[i++];
while(sum < N/2)

return a[floor + i -1];

}   

//这里遍历了10亿数两次,用了两个2^16 = 16k大小的数组, 时间复杂度 为o(n), 空间用了32k
//这是对32位数而言的,对于64位数 2^64 = 2^16  * 2^16 * 2^16  * 2^16  分四次就可以了, 算法复杂度依然是o(n), 空间用 16k * 4 = 64k


3、建堆法从1亿个整数里找出100个最大的数(用哪种算法效率高)


我的思路:
(1)读取前100个数字,建立最大值堆。
(2)依次读取余下的数,与最大值堆作比较,维持最大值堆。可以每次读取的数量为一个磁盘页面,将每个页面的数据依次进堆比较,这样节省IO时间。
(3)将堆进行排序,即可得到100个有序最大值。

二、亿级排序

输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且n=10^7。
输出:得到按从小到大升序排列的包含所有输入的整数的列表。

《编程珠玑》中提出的问题,有三种解法:

(1)磁盘合并排序


先将所有数据分成多个小文件,多个小文件采用内部排序后,再用多路合并排序完成排序输出。

        总数据为n, 内存中采用内部排序最多m。先分成n/m个小文件,再内部排序,第三部读取所有小文件,每次将最小的数输出即可。

(2)多通道


0~10^k-1

10^k~2*10^k-1

...

分成m个通道,读m次,每次读取在通道范围内的数,按顺序写到对应的输出文件,完成排序。

(3)bitmap排序


在内存中开10^7比特,均初始化为0,若出现则设置为1,输出为1的数即可。



题目:


如果有一个20g的日志文件,日志文件记录着用户访问过的url,每一行为一个url,给你一台512M的主机,找出出现次数最多的10个url

参考答案及思路:

1. Top K算法:使用堆排序算法+大顶堆+10个元素的数组。

2.

  • IP地址最多有2^32=4G种取值情况,所以不能完全加载到内存中处理;
  • 可以考虑采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件最多包含4MB个IP地址;
  • 对于每一个小文件,可以构建一个IP为key,出现次数为value的Hash map,同时记录当前出现次数最多的那个IP地址;
  • 可以得到1024个小文件中的出现次数最多的IP,再依据常规的排序算法得到总体上出现次数最多的IP;


你可能感兴趣的:(算法)