位图
Step 1
- 位图的功能
位图是拿每一个比特位来做图。
位图的功能就是可以确定一个集合,如果给出数值的范围是确定的(给出确定的最大值),可以使用位图来记录是否存在的功能。 - 位图的好处
极大的压缩空间。
比如 0 - 1023,存储数字是否存在
(1024b / 32b) = 32
从而可以通过存储 32位整型数组,来记录1024个状态。 - 位图的实现
见后面代码。
PS: 位运算的速度比算数运算速度快得多 (10倍以上)
位图的核心:
- 确定元素在数组的位置:bits[num/64] -> bits[num >> 6]
- 确定对应位 在对应元素的位置: (1L << (num % 64)) --> (1L << (num & 63)); 这个一定要是64,32等 2 的 n 次幂
- 最后就是 将对应位置 置为1,其余位不变(做或运算)
或者 将对应位置置为0,其余为不变(做与运算,涉及取反操作)
package class05;
import java.util.HashSet;
public class BitMap {
private long[] bits;
public BitMap(int max) {
max = ((max + 1) >> 6);
if (((max + 1) & 63) != 0) {
max += 1;
}
bits = new long[max];
}
public void add(int num) {
bits[num >> 6] |= (1L << (num & 63));
}
public void delete(int num) {
bits[num >> 6] &= ~(1L << (num & 63));
}
public boolean contains(int num) {
return (bits[num >> 6] & (1L << (num & 63))) != 0;
}
}
class Test{
public static void main(String[] args) {
System.out.println("测试开始!");
int max = 10000;
BitMap bitMap = new BitMap(max);
HashSet<Integer> set = new HashSet<>();
int testTime = 10000000;
for (int i = 0; i < testTime; i++) {
int num = (int) (Math.random() * (max + 1));
double decide = Math.random();
if (decide < 0.333) {
bitMap.add(num);
set.add(num);
} else if (decide < 0.666) {
bitMap.delete(num);
set.remove(num);
} else {
if (bitMap.contains(num) != set.contains(num)) {
System.out.println("Oops!");
break;
}
}
}
for (int num = 0; num <= max; num++) {
if (bitMap.contains(num) != set.contains(num)) {
System.out.println("Oops!");
}
}
System.out.println("测试结束!");
}
}
位运算实现加减乘除
- 加法
异或运算就是无进位相加。
进位信息 运算为 (a & b) << 1;
(计算机底层不认加号的,底层只认逻辑门,也就是位运算。)
所以 a + b = (a ^ b) + ((a & b) << 1)
也就是 无进位相加 + 进位信息的结果
- 减法
a-b --> a + (-b) --> 相反数怎么表示 —> b 的相反数 -b = ~b + 1; (也不是说完全的跟补码相同了,因为这里的取反是全部位包括符号位取反,从而取得相反数)
除法 特殊考虑 除数和被除数 是 系统最小值问题
!= 等于 ^ (异或)