Ari的小跟班

  :: :: 博问 :: 闪存 :: :: :: :: 管理 ::
  65 随笔 :: 1 文章 :: 1 评论 :: 15073 阅读

TOP K 问题

​ 比如“从10亿个数字中找出最大的前100个数”,会怎么操作?

​ 我们可以考虑使用小根堆(如果是求最小的前100个数,那么就可以使用大根堆),先顺序取出前100个,建立小根堆后,从第101个开始遍历,如果当前的数字小于小根堆的堆顶元素的话,那就直接丢弃,不考虑,如果是大于堆顶元素的话,那么先把堆顶元素删除后,添加当前的元素......直到全部遍历完成。

​ 关于时间复杂度:建堆的时间复杂度为O(mlogm)(m为数组的大小即为100),然后遍历后续的数字,并于堆顶(最小)数字进行比较。如果比最小的数小,则继续读取后续数字;如果比堆顶数字大,则替换堆顶元素并重新调整堆为最小堆。整个过程直至1亿个数全部遍历完为止。然后按照中序遍历的方式输出当前堆中的所有10000个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是100(常数)。

​ 这种方法对于内存的要求不高,并且也只需遍历一次即可。唯一不足的就是,单机运行可能效果不好。

如果是多机环境的话,可以考虑使用MapReduce,增加可拓展性:

public class WordCountMapper extends Mapper<LongWritable, Text, Text,IntWritable> {
private static IntWritable data = new IntWritable(); //静态变量了解一下
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
String line = value.toString();
data.set(Integer.parseInt(line));
context.write(data, new IntWritable(1));//就用1作为value即可
}
}
}
public class MyReducer extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable>{
public void reduce(IntWritable key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException{
for(IntWritable val : values){
context.write(data, key);
break;//重复的数字我只采用一次
}
}
}
posted on   Ari的小跟班  阅读(10)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示