分治:hash + 堆 归并 快排 处理大数据

时间:2022-07-22
本文章向大家介绍分治:hash + 堆 归并 快排 处理大数据,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、寻找热门查询,300万个查询字符串中统计最热门的10个查询。

搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

  • 每一个查询串为255Byte,4个为1k
  • 那么总共有1千万个请求,300w个请求3m
  • 3m*1k/4 = 0.75G 所以内存不会超出

所以是典型的TopK问题:

二、hashmap + 堆

1.hashmap进行域名统计,key为请求域名,value为请求的次数,每次判断是否存在key,存在就将value值加1,否则添加项,并将value设置为1.时间复杂度为o(n),l为数据大小

2.维护一个k大的小顶堆,遍历key(实质是去重后的域名),比堆顶小的舍去,比堆顶大的添加,并调整堆,调整时间o(log(k)) k为传入参数。 时间复杂度为n1*log(k),n1为去重后的数据大小。

三、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

由于内存的限制,所以不能同时将1G的文件进行分析计算,可以采用分治思想,将文件分为多个,可以分为每一个只有1M的,这样对小文件的计算就不会出现超出内存的问题。

  • 分割的方法是将每一个单词进行hash后,hash%5000这样将单词分割到5000个小文件中,1G/5000 大约一个文件200k,重复单词一定被分割到同一个文件中。
  • 由于每一项是一个单词,可以采用字典树Trie进行统计/hashmap,统计每一个文件中出现的次以及频率。字典树的时间复杂度为单词最长的数值+遍历一遍n*O(k),hash为遍历一遍+产生hash+冲突解决。
  • 对每一个小文件取出其中频率最大的前100个单词,然后进行合并,或者直接进行归并排序/堆排序,nlog(k)
四、海量日志数据,提取出某日访问百度次数最多的那个IP。

海量文件很容易内存溢出,我们必要的操作步骤为:

1.分治,切割为小文件

2.hash 进行词频统计

3.堆排序,取出前k大

扫描日志文件,对每条访问的IP地址作hash,然后取模,比如(%1000),则把整个大日志文件映射为1000个小文件(同一个IP地址总是被映射到同一个小文件中)。再找出每个小文中出现频率最大的IP(可以采用hash_map对那1000个文件中的所有IP进行频率统计,然后依次找出各个文件中频率最大的那个IP)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。

五、海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。

在这种情况下,很明显可以使用MapReduce的方法,但是如果不使用集群,又该怎么办呢?

  • 首先我们可以对每一个文件进行堆排序,求出每一个文件的前10数据,
  • 再把100台电脑上的数据合并起来再用堆排序求出top前10.
  • 但是这样存在很大的问题,就是如果相同的数据分布在不同的主机,这样可能会导致前100求前10不准确问题。我们可以先将文件合并,在通过hash%100产生100个文件分布在100个机器上,这样相同的数据都会位于一台电脑上。
六、有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
  • 可以采用边读边写顺序的读取10个文件,并将每一个请求域名进行hash%10存放到对应的文件中
  • 然后采用hash_map对每一个文件域名的量进行统计
  • 对所有的输出结果进行合并,并使用快排/堆/归并进行排序,排序的复杂度为nlogn
  • 如果数据的重复量是比较大的,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。
  • 同时也可以直接使用MapReduce来进行分析。
七、 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件url列表的交集?
  • 首先估计每一个文件的大小,50亿 条数据 每条数据64Byte, 5G * 64 = 320G所以是不可能一次性的加载到内存中需要采用分治的思想。
  • 首先对每一个url进行hash映射,hash%1000分割到一千个文件中进行存储,每一个文件的大下为300M,然后对另一个文件进行相同的分割,这样数据相同的都被分割到相同的文件中。
  • 然后将一个小文件的数据存储到hash_set中,然后遍历另一个文件的数据往hash_set中丢,如果存在则表明是共同拥有,然后输出到文件中。
八、一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。

首先我们给出答案:

1.         建立Trie树,记录每颗树的出现次数,O(n*le); le:平均查找长度

2.         维护一个10的小顶堆,O(n*lg10);

3.         总复杂度: O(n*le) + O(n*lg10);
九、1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
  • 用trie树/hash_map,将统计次数不唯一的直接过滤(filter)到即可。
  • 如果数据量很大处理会很不项式,可以采用分治的思想,将文件想用hash%1000进行分割,然后在对每一个文件的字符串进行统计,最后再进行过滤。
十、100w个数中找出最大的100个数。
  • 因为是数字所以可以采用的方法就比较多,比如之前提到的堆排序,维护一个100大小的堆,将其他数据与堆顶进行比较。
  • 或者采用分治思想的快排,每次排序会确定一个数据的位置,如果数据的大小未接近100,就将数据小的部分直接舍去即可。直到数据接近100时,再采用堆/插入等进行排序。