/** * @Date 2020/7/3 * @param dataSize 数据量的大小 * @param randomNumRange 产生随机数的范围
* @param topN 找出重复次数前N的。 * @return void * @Description 在大数据量的数字中查找重复次数前N个的数字 */
public static void repeatTopN(int dataSize,int randomNumRange,int topN){ long
start = System.currentTimeMillis(); int maxValue = randomNumRange;
Map<Integer,Integer> map1 = new HashMap<Integer,Integer>();//存放key:数字
value:出现次数 Map<Integer, List<Integer>> map2 = new
HashMap<Integer,List<Integer>>();//存放 key:出现次数 value:数字 Random r = new
Random(); for(int i = 0 ; i < dataSize ; i++){ int number =
r.nextInt(maxValue); int count = 1; if(map1.containsKey(number)){ count =
map1.get(number)+1; map1.put(number,count); }else{ map1.put(number,1); }
if(map2.containsKey(count)){//这里需要优化。出现次数最多的数字会在之前出现次数的List集合都存在。
map2.get(count).add(number); }else{ List list = new ArrayList<Integer>();
list.add(number); map2.put(count,list); } } BitSet bs = new BitSet();
//使用BitSet的位向量 原理。对应下标位置如果设置则为true,否则为false
//设置出现次数为bs对应下标的设置,这样最大下标所对应的值为true。 for(Map.Entry<Integer,Integer> entry :
map1.entrySet()){ bs.set(entry.getValue()); } //注意:这里使用TreeSet
是为了解决上面最多出现次数的数字会在之前的list都出现一遍,为了去重和按照顺序插入到result中 Set <Integer> result = new
TreeSet<Integer>();
//倒序循环bs。只要值为true的。说明是出现过的最大次数。然后倒序输出,使用出现次数从map2中查找对应的数字列表, 查找topN个数字。
a:for(int j = bs.size();j>=0;j--){ //这里bs的size是2的n次幂。 if(bs.get(j)){
b:for(Integer num : map2.get(j)){ if(result.size() > topN){ //result的大小
大于用户需要取出的topN。退出循环 break a; } //取出重复次数前topN的数字 boolean flag = result.add(num);
if(flag){//如果是不重复并且增加进去的则输出数字出现的次数。 System.out.println("["+num +"]出现过:"+j+"次");
} } } } long end = System.currentTimeMillis(); System.out.println(result);
System.out.println("共耗时:"+((end-start)/1000) +"秒"); } public static void
main(String[] args) { repeatTopN(100000000,1000,5); }
以上是对这个问题单台机器单线程的实现方式,里面有需要优化的地方,暂时没有实现。忘大神多多指教。