1亿数字中找出重复次数TopN的问题

/**
 * @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);
}

以上是对这个问题单台机器单线程的实现方式,里面有需要优化的地方,暂时没有实现。忘大神多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值