- bitmap : Bit-map的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,可以很大力度的节省空间,常用于对大量整数做去重和查询操作。
- bitset : BitSet就是实现了Bit-Map算法。BitSet位于java.util包下,从JDK1.0开始就已经有了。该类实现了一个按需增长的位向量。位集的每一个组件都有一个boolean类型的值。
BitSet的每一位代表着一个非负整数。可以检查、设置、清除单个位。一个BitSet可以通过逻辑与、逻辑或、逻辑异或去修改另一个BitSet。默认情况下,所有位的标识都是false。
可以看到JDK中的BitSet采用Bit-Map思想,BitSet封装较多的API,可供开发者们随意使用。 - roaringbitmap : Roaring bitmap将32位无符号整数按照高16位分容器,即最多可能有216=65536个容器(container),存储数据时,按照数据的高16位找到container(找不到就会新建一个),
再将低16位放入container中。高16位又称为共享有效位,它用于索引应该到哪个容器中查找对应的数值,属于roaring bitmap的一级索引。
Roaring bitmaps以紧凑高效的两级索引数据结构存储32位整数。高密度块使用位图存储;稀疏块使用16位整数的压缩数组。当一个块包含不超过4096个整数时,我们使用一个排好序的16位整数数组。
当有超过4096个整数时,我们使用2^16 位的位图。为什么按4096作为阀值呢?仅仅是因为当数据块中的整数数量超过这个值之后,bitmap将比数组的内存使用率更高。
一文读懂比BitMap有更好性能的Roaring Bitmap : https://cloud.tencent.com/developer/article/1753528
数据开发_Java中IO序列化以及RoaringBitmap序列化 : https://www.cnblogs.com/ytwang/p/13999654.html
import org.roaringbitmap.RoaringBitmap;
import java.io.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
public class BitmapDemo {
private static final int N = 10000000;
private int[] a = new int[N / 32 + 1];
public static void main(String[] args) {
System.out.println ("bitmap 测试-------------------------------");
int num[] = {1, 5, 30, 32, 64, 56, 159, 120, 21, 17, 35, 45};
BitmapDemo map = new BitmapDemo ();
for (int i = 0; i < num.length; i++) {
map.addValue (num[i]);
}
int temp = 4;
if (map.exits (temp)) {
System.out.println ("value:[" + temp + "] has already exists");
}
map.display (3);
System.out.println ("bitset 测试-------------------------------");
BitSet bitSet = new BitSet ();
System.out.println (bitSet.get (10) + "\t" + bitSet.size ());
bitSet.set (10);
System.out.println (bitSet.get (10) + "\t" + bitSet.size ());
System.out.println (bitSet.get (64) + "\t" + bitSet.size ());
bitSet.set (64);
System.out.println (bitSet.get (64) + "\t" + bitSet.size ());
System.out.println ("roaringbitmap 测试-------------------------------");
test1 ();
}
public void addValue(int n) {
int row = n >> 5;
a[row] |= 1 << (n & 0x1f);
}
public boolean exits(int n) {
int row = n >> 5;
return (a[row] & (1 << (n & 0x1F))) != 0;
}
public void display(int row) {
System.out.println ("BitMap位图展示");
for (int i = 0; i < row; i++) {
List<Integer> list = new ArrayList<Integer> ();
int temp = a[i];
for (int j = 0; j < 32; j++) {
list.add (temp & 1);
temp >>= 1;
}
System.out.println ("a[" + i + "]" + list);
}
}
public static void test1() {
RoaringBitmap r1 = RoaringBitmap.bitmapOf (1, 2, 3, 1000);
r1.add (5);
RoaringBitmap r2 = new RoaringBitmap ();
r2.add (10000, 10009);
RoaringBitmap r3 = RoaringBitmap.or (r1, r2);
r1.or (r2);
System.out.println ("r1 大小: " + r1.getCardinality ());
Iterator<Integer> iterator = r1.iterator ();
while (iterator.hasNext ()) {
System.out.println (iterator.next ());
}
try {
File file = new File ("");
FileOutputStream fileOutputStream = new FileOutputStream (file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream (fileOutputStream);
r1.serialize (objectOutputStream);
objectOutputStream.flush ();
objectOutputStream.close ();
System.out.println ("序列化到文件完成");
} catch (FileNotFoundException e) {
e.printStackTrace ();
} catch (IOException e) {
e.printStackTrace ();
}
RoaringBitmap outRR = new RoaringBitmap ();
try {
FileInputStream fileInputStream = new FileInputStream ("");
ObjectInputStream objectInputStream = new ObjectInputStream (fileInputStream);
outRR.deserialize (new DataInputStream (objectInputStream));
System.out.println ("反序列化到文件完成");
System.out.println ("反序列化后的 outRR 大小: " + outRR.getCardinality ());
Iterator<Integer> iterator1 = outRR.iterator ();
while (iterator1.hasNext ()) {
System.out.println (iterator1.next ());
}
} catch (FileNotFoundException e) {
e.printStackTrace ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
- 部分运行结果如下参考: