声明: 原文引用参考July大神的csdn博客文章 => 海量处理面试题
所谓海量数据处理,就是数据量太大,无法在较短时间内迅速解决,无法一次性装入内存。本文在前人的基础上总结一下解决此类问题的办法。那么有什么解决办法呢?
时间复杂度方面,我们可以采用巧妙的算法搭配合适的数据结构,如Bloom filter/Hash/bit-map/堆/数据库或倒排索引/trie树。空间复杂度方面,分而治之/hash映射。
海量数据处理的基本方法总结起来分为以下几种:
前提基础知识:
1 byte= 8 bit。
int整形一般为4 bytes 共32位bit。
2^32=4G。
1G=2^30=10.7亿。
问题1
给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
分析:50亿*64=320G大小空间。
算法思想1:hash 分解+ 分而治之 + 归并
问题2
有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
解决思想1:hash分解+ 分而治之 +归并
问题3:
有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
类似问题:怎么在海量数据中找出重复次数最多的一个?
解决思想: hash分解+ 分而治之+归并
问题4
海量日志数据,提取出某日访问百度次数最多的那个IP
解决思想: hash分解+ 分而治之 + 归并
问题5
海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。
解决思想: 分而治之 + 归并。
注意TOP10是取最大值或最小值。如果取频率TOP10,就应该先hash分解。
问题6
在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。
解决思路1 : hash 分解+ 分而治之 + 归并
2.5亿个int数据hash到1024个小文件中a0~a1023,如果某个小文件大小还大于内存,进行多级hash。每个小文件读进内存,找出只出现一次的数据,输出到b0~b1023。最后数据合并即可。
解决思路2 : 2-Bitmap
如果内存够1GB的话,采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32*2bit=1GB内存。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。
注意,如果是找出重复的数据,可以用1-bitmap。第一次bit位由0变1,第二次查询到相应bit位为1说明是重复数据,输出即可。
问题7
一共有N个机器,每个机器上有N个数。每个机器最多存O(N)个数并对它们操作。如何找到N^2个数中的中数?
解决思想1 : hash分解 + 排序
解决思想2: 分而治之 + 归并
先对每台机器上的数进行排序。排好序后,我们采用归并排序的思想,将这N个机器上的数归并起来得到最终的排序。找到第(N^2)/2个便是所求。复杂度是O(N^2 * lgN^2)的。
这里Trie树木、红黑树或者hash_map可以认为是第一部分中分而治之算法的具体实现方法之一。
问题1
上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据。
解决思路: 红黑树 + 堆排序
问题2
1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
解决思路:trie树。
这题用trie树比较合适,hash_map也应该能行。
问题3
一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
解决思路: trie树 + 堆排序
这题是考虑时间效率。
1. 用trie树统计每个词出现的次数,时间复杂度是O(n*len)(len表示单词的平准长度)。
2. 然后找出出现最频繁的前10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。
总的时间复杂度,是O(n*le)与O(n*lg10)中较大的哪一个。
问题4
搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。
解决思想 : trie树 + 堆排序
采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。
BitMap说白了很easy,就是通过bit位为1或0来标识某个状态存不存在。可进行数据的快速查找,判重,删除,一般来说适合的处理数据范围小于8*2^32。否则内存超过4G,内存资源消耗有点多。
问题1
已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
解决思路: bitmap
8位最多99 999 999,需要100M个bit位,不到12M的内存空间。我们把0-99 999 999的每个数字映射到一个Bit位上,所以只需要99M个Bit==12MBytes,这样,就用了小小的12M左右的内存表示了所有的8位数的电话
问题2
2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。
解决思路:2bit map 或者两个bitmap。
将bit-map扩展一下,用2bit表示一个数即可,00表示未出现,01表示出现一次,10表示出现2次及以上,11可以暂时不用。
在遍历这些数的时候,如果对应位置的值是00,则将其置为01;如果是01,将其置为10;如果是10,则保持不变。需要内存大小是2^32/8*2=1G内存。
或者我们不用2bit来进行表示,我们用两个bit-map即可模拟实现这个2bit-map,都是一样的道理。
Bloom filter可以看做是对bit-map的扩展。
参考july大神csdn文章 Bloom Filter 详解
参考引用july大神 csdn文章
MapReduce的初步理解
Hadoop框架与MapReduce模式