数据结构之位图 bitset bitmap

730 阅读3分钟

1.介绍

在JAVA数据结构中除了常见的8种数据结构:数组、链表、哈希表、队列、栈、堆、树、图还有一些非常用的数据结构如位图。

位图的思想类似于哈希表,使用二进制的比特位来表示一个数字是否存在,在的话是1,不在的话是0。

2.案例

有这么一道题:给40亿个不重复的无符号整数,并且未排过序。如何判断一个数是否在这40亿个数中。 这道题的核心点是40亿的整数(量大且无序),在内存中判断比较。其中byte、short、int、long都是表示整数的,只不过他们的取值范围不一样。

  • byte的取值范围为-128~127,占用1个字节(-2的7次方到2的7次方-1)

  • short的取值范围为-32768~32767,占用2个字节(-2的15次方到2的15次方-1)

  • int的取值范围为(-2147483648~2147483647),占用4个字节(-2的31次方到2的31次方-1)

  • long的取值范围为(-9223372036854774808~9223372036854774807),占用8个字节(-2的63次方到2的63次方-1)。

int numArray[] = new int[900000000];

我的电脑内存为16G,当初始化9亿的int 数组时,就已经产生了OutOfMemoryError内存溢出。

而位图一个字节就可以表示八个整数是否在存在。相当于byte占用的1/8,极大的减少了内存的占用,40亿个无符号整数只需要512mb左右就可以表示了。BitSet底层是用long类型的数据进行存储的,且长度单位为64,和HashSet 一样有set 和get方法。

BitSet bitSet = new BitSet();

由于采用了位为单位来存放数据,所以节省了大量的空间。在Java中一般一个int数字要占用32位,如果能用一位就表示这个数,就可以缩减大量的存储空间。一般把这种方法称为位图法,即Bitmap。位图法比较适合于判断是否存在这样的问题,元素的状态比较少,元素的个数比较多的情况。关于bitmap和bitset的区别见参考资料

这道题除了使用占用内存更小的方式来处理,还有一种思路也很优秀。 将这些整数分割压缩成一连串后的有序数组。 如1,2,3,4,6,7,8,10,11。可以表示为 [[1,4],[6,8],[10,11]] 当内部数组的连续性越高,则效果越好。

所以我们做技术的思想是非常关键的,同一个问题在不同场景不同人可能有不同的答案,而我们要做的就是要深入的了解和学习每种解法的本质原理和适用场景,才能更好的决定如何解决问题。

3.bitset 在存储方面的应用

有一个数据表,量很大(千万级),其中有个字段存储格式为逗号隔开的整数,如1,5,11,17 数据也大。

  • 这个字段如果使用全like 会出现不精确的问题;
  • 如果使用数据库函数split 分割,在并发量上来的时候对数据库的CPU会带来很高的负载。 此时我们就可以使用bitset 机制,先根据符合条件的数据从数据库查询后,在应用层分割转换为bitset,通过这个对象就能实际过滤需要的数据,对服务器的内存要求也不高。从而减少了数据库的此类性能问题。

参考资料

www.cnblogs.com/muzhongjian… blog.csdn.net/m0_37907797…