java位图去重,Java BitSet解决海量数据去重

先提一个问题,怎么在40亿个整数中找到那个唯一重复的数字?

第一想法就是Set的不可重复性,依次把每个数字放入HashSet中,当放不去进去的时候说明这就是重复的数字,输出这个数字。

1 if(hs.contains(x))2 System.out.println("重复的数字是"+x);3 else{4 hs.add(x);5 }

但是,

1 HashSet里contains():2 public booleancontains(Object o) {3 returnmap.containsKey(o);4 }5 HashMap里containsKey():6 public booleancontainsKey(Object key) {7 return getEntry(key) != null;8 }9 HashMap里getEntry():10 final EntrygetEntry(Object key) {11 if (size == 0) {12 return null;13 }14

15 int hash = (key == null) ? 0: hash(key);16 for (Entry e =table[indexFor(hash, table.length)];17 e != null;18 e =e.next) {19 Object k;20 if (e.hash == hash &&

21 ((k = e.key) == key || (key != null &&key.equals(k))))22 returne;23 }24 return null;25 }

但是怎么说呢,contains()方法消耗的时间,消耗的空间很大,毕竟有约40亿的数据,所以觉得HashSet是不可取的。

然后百度了,发现了BitSet这个神奇的东西。

源代码就不贴了,简述下为什么用BitSet能行。

BitSet就是位图,它的值只有1和0。内部是基于long[]实现的,long是8字节(64位),所以Bitset最小是64位,每次扩大一次扩大64位,即内部大小是64的倍数。每次BitSet新增加一个数字时,就将该位置为1。

也就是说BitSet并不直接存储每个数据,而是存储数字是否存在过(1表示存在,0表示不存在)。

|---------------|-----------|-------------|-------------|----------|

|

| 数字范围 [0,63] [64,127] [128,191] ......... |

|---------------|-----------|-------------|-------------|----------|

|

| long数组索引 0 1 2 ........ |

|---------------|-----------|-------------|-------------|----------|

若添加一个数字 10 ,那么将long[0]的二进制位中从左往右第十个数置为1,

若添加一个数字 64 ,那么将long[1]的二进制位中从左往右第一个数置为1,没有添加的数字所在位数是0,用此方法就可记录一个数字是否在BitSet中。

1 import java.util.*;2

3 public classMain{4 public static void main(String[] args) throwsException{5 BitSet bs = newBitSet();6 int[] nums={1,2,3,4,5,6,7,8,9,10,10};7 for (intnum : nums) {8 if(bs.get(num)){9 System.out.println(num); //10

10 break;11 }else{12 bs.set(num);13 }14 }15 }16 }

再提个问题,40亿个数中,给你一个数X,怎么判断X是否在40亿个数中呢?

二分查找 (理论上的想法,其实我也不知道能不能行..o(>﹏

先将数据转为二进制数(其实很多地方都可以转二进制计算,比如IP地址),31位二进制可表示约21亿,那么40亿需要32位二进制。将40亿数最高位按1、0分开,那么就分成了0-21亿,21-40亿两部分,然后次最高位按1、0分开.....

ac3234f3b05da0a664d996b5b66ac0dd.png

然后把需要查找的数字转为32位的二进制,只要从最高位依次往下比较即可。假如重复数字是在【A,B】间,B-A=100000(在我电脑上,进行100000次的for循环查找需要3ms,所以是能接受的),大概位数要比较二三十次,在计算机中比较二三十次的位数非常快。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值