小知识
- 在实际项目中,我们经常需要聚合统计,比如统计一个年龄在20-30,喜欢看技术书籍,喜欢听音乐,喜欢宅在家的程序员等等一系列标签的用户。 如果使用mysql求并集,首先语句随着标签变长而变长,其次聚合,分组,去重严重影响语句性能。这种情况如何解决?
- 比如现在比较火的面试题,在10亿整数中找出100个重复的数,或者任意给定一个整数,判断是否在这个10亿数中。
bitMap原理
bitMap就是使用bit位来标记元素,key为该元素,value一般为0或者1,大大节省存储空间.
现在有(2, 3, 4, 5,7)5个数,任意给定一个在0-7范围内的数字,判断是否在此集合中:
创建一个范围为(0-7)的Byte类型数组,将集合数字对应数组的bit位置置1;
然后遍历该Byte数组,如果Byte数组位置为1即代表该数存在。
同理对于10亿整数也可以这样处理,一个int型数字4个字节,32bit,如果使用bit标记正整数,就可以节省32倍的内存空间。
10亿数字,40亿字节,320亿bit,需要大约4g内存,使用bitMap标记,只需要125M内存空间即可存储,大大节省内存空间。
以上和桶排序排序的思想非常相似。
bitMap实际运用
对于1千万数据,判断任意给定的数是否在其中?
分治思想
使用int数组作为bitMap。
将数组分成32组,每组内有(0-31)个位置,如果给定数组在指定数组中的bit是0,则不存在。
- 求十进制数在对应数组a中的下标
a[i] = a[N/32] - 求int[]中bit位置
index = a[i] % 32
上述两个运算可以改成位运算,因为位运算的效率非常高,占用cpu的时钟周期非常少。
结论:对于2的倍数,%2^n = &(2^n-1),模运算等于与预算,例:a % 16 = a & 15,这里的15做与运算时需要化成16进制,即0x0F.
在10000000个范围为[1-100000]数中,给定指定一个数,判断是否在这个集合中
代码
1 | public class BitMapActual { |