算法实现
set 集合实现查找
将1 亿个数存储在 set 集合内, 然后根据 contains 方法来判断该整数是否存在集合中即可。
bitmap 位图实现查找
程序实现
public class AnswerApp {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
BitSet bitSet = new BitSet(Integer.MAX_VALUE);
int count = 1 << 27;
System.out.println("本次要在 " + count + " 个数中进行查看某个整数是否在其中");
System.out.println();
System.out.println("加载数据到内存中...\n");
// 随机生成 Integer.MAX_VALUE 以内的 count 个整数
for (int i = 0; i < count; i++) {
bitSet.set(new Random().nextInt(Integer.MAX_VALUE));
}
System.out.println("加载数据到内存耗时: " + (System.currentTimeMillis() - startTime) + " ms.");
startTime = System.currentTimeMillis();
System.out.println();
System.out.println("查找中...");
System.out.println("bitSet 的总大小: " + bitSet.length());
System.out.println();
System.out.println("整数 1024 是否在" + count +"个数当中: " + bitSet.get(1024));
System.out.println("整数 20190607 是否在" + count +"个数当中: " + bitSet.get(20190607));
System.out.println();
// 把整数 20190607 放到数字容器中
bitSet.set(20190607);
// 此时再看 20190607 是否存在数字容器内
System.out.println("整数 20190607 是否在" + count +"个数当中: " + bitSet.get(20190607));
System.out.println();
// 把整数 20190607 从数字容器内移除
bitSet.set(20190607, false);
// 此时再看 20190607 是否存在数字容器内
System.out.println("整数 20190607 是否在" + count +"个数当中: " + bitSet.get(20190607));
System.out.println();
System.out.println("查找数据耗时: " + (System.currentTimeMillis() - startTime) + " ms.");
}
}
运行输出
本次要在 134217728 个数中进行查看某个整数是否在其中
加载数据到内存中...
加载数据到内存耗时: 21029 ms.
查找中...
bitSet 的总大小: 2147483641
整数 1024 是否在134217728个数当中: false
整数 20190607 是否在134217728个数当中: false
整数 20190607 是否在134217728个数当中: true
整数 20190607 是否在134217728个数当中: false
查找数据耗时: 0 ms.
两种方式占用内存对比
- 采用 set 集合实现, 1亿个int类型整数占用空间是 4亿字节 大约是 400MB
- 1亿 int 整数 = 4字节 * 1 亿 = 4亿字节
- 采用位图实现, 因为 一个int 类型是32位, 所以占用的空间是 set 方式的 1/32, 即 400/32=12.5MB
换算规则
- 1GB = 1024MB =
1024 * 1024 KB
= 1024 * 1024 * 1024 Byte
= 1073741824 字节 约等于
十亿字节 - int 值的取值范围 -2147483648(-2的31次方) ~ 2147483647(2的31次方 - 1)
- 1个 int 类型整数 = 二进制位数32位(bit) = 4字节(byte)
BitSet类
BitSet中实现了Cloneable接口中定义的方法如下表所列:
序号 | 方法描述 |
1 | void and(BitSet set) 对此目标位 set 和参数位 set 执行逻辑与操作。 |
2 | void andNot(BitSet set) 清除此 BitSet 中所有的位,其相应的位在指定的 BitSet 中已设置。 |
3 | int cardinality( ) 返回此 BitSet 中设置为 true 的位数。 |
4 | void clear( ) 将此 BitSet 中的所有位设置为 false。 |
5 | void clear(int index) 将索引指定处的位设置为 false。 |
6 | void clear(int startIndex, int endIndex) 将指定的 startIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 false。 |
7 | Object clone( ) 复制此 BitSet,生成一个与之相等的新 BitSet。 |
8 | boolean equals(Object bitSet) 将此对象与指定的对象进行比较。 |
9 | void flip(int index) 将指定索引处的位设置为其当前值的补码。 |
10 | void flip(int startIndex, int endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的每个位设置为其当前值的补码。 |
11 | boolean get(int index) 返回指定索引处的位值。 |
12 | BitSet get(int startIndex, int endIndex) 返回一个新的 BitSet,它由此 BitSet 中从 fromIndex(包括)到 toIndex(不包括)范围内的位组成。 |
13 | int hashCode( ) 返回此位 set 的哈希码值。 |
14 | boolean intersects(BitSet bitSet) 如果指定的 BitSet 中有设置为 true 的位,并且在此 BitSet 中也将其设置为 true,则返回 true。 |
15 | boolean isEmpty( ) 如果此 BitSet 中没有包含任何设置为 true 的位,则返回 true。 |
16 | int length( ) 返回此 BitSet 的"逻辑大小":BitSet 中最高设置位的索引加 1。 |
17 | int nextClearBit(int startIndex) 返回第一个设置为 false 的位的索引,这发生在指定的起始索引或之后的索引上。 |
18 | int nextSetBit(int startIndex) 返回第一个设置为 true 的位的索引,这发生在指定的起始索引或之后的索引上。 |
19 | void or(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑或操作。 |
20 | void set(int index) 将指定索引处的位设置为 true。 |
21 | void set(int index, boolean v) 将指定索引处的位设置为指定的值。 |
22 | void set(int startIndex, int endIndex) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为 true。 |
23 | void set(int startIndex, int endIndex, boolean v) 将指定的 fromIndex(包括)到指定的 toIndex(不包括)范围内的位设置为指定的值。 |
24 | int size( ) 返回此 BitSet 表示位值时实际使用空间的位数。 |
25 | String toString( ) 返回此位 set 的字符串表示形式。 |
26 | void xor(BitSet bitSet) 对此位 set 和位 set 参数执行逻辑异或操作。 |
Java Bitset类
public static void main(String[] args) {
// nbits为2的倍数, 如果不是2的倍数也会转为2的倍数, 如new BitSet(200), bitSet.size()=256
BitSet bitSet = new BitSet(128);
System.out.println(bitSet.length());
System.out.println(bitSet.size());
System.out.println(bitSet.cardinality());
System.out.println("---------------");
bitSet.set(0);
bitSet.set(128); // 代码1
bitSet.set(12);
bitSet.set(8);
bitSet.set(38);
System.out.println(bitSet.length());
System.out.println(bitSet.size());
System.out.println(bitSet.cardinality());
System.out.println(bitSet.toString());
}
代码1处没注释时输出
0
128
0
---------------
129 // 为true的最大的为128
256 // 因为128已经超过初始化容量,所以2倍扩容(从0开始算, 因为放了128, 所以超过了容量进行扩容)
5 // 共有5个位数设置为true
{0, 8, 12, 38, 128}
注释掉代码1处时输出
0
128
0
---------------
39 // 为true的最大的为38
128 // 初始化容量为128
4
{0, 8, 12, 38}
Reference
- Java Bitset类