BitMap位图
基础
单位换算
1 GB = 1024 MB // B: Byte 字节
1 MB = 1024 KB
1 KB = 1024 B
1 B = 8 Bit // Bit: 位
java 中的 int 和 long
int 占用 4 个字节,即 4 * 8 = 32 bit;long 占用 8 个字节,即 8 * 8 = 64 bit.使用位图, 32 位可以表示的正整数范围 0 ~ 4294967295(Long.parseLong("11111111111111111111111111111111",2) = 4294967295),由此可见,同 int 和 long 相比,使用位图映射数字,将大幅度降低对内存的占用.
10 进制和 2 进制转换
10 进制 -> 2 进制
Long.toBinaryString(10)
2 进制 -> 10 进制
Long.parseLong("1010", 2)
位运算
A = 0011 1100
B = 0000 1101
A & B = 0000 1100 // 与: 对应位都是 1,则为 1,否则为 0
A | B = 0011 1101 // 或: 对应位有一个是 1,则为 1,否则为 0
~A = 1100 0011 // 非: 取反,1 -> 0,0 -> 1
A ^ B = 0011 0001 // 异或: 对应位不相等,则为 1,否则为 0
A << 2 = 1111 0000 // 对于正整数来说,左移 n 位,相当于对应的 10 进制数乘 2 的 n 次方
问与答
问1
一个最多包含 n 个不重复的正整数的文件,每个数都小于 107,假设只有 1MB 内存可用,如何快速排序?
答1
import java.util.BitSet;
public class Test {
public static void main(String[] args) {
BitSet bitSet = new BitSet();
bitSet.set(20);
bitSet.set(10);
bitSet.set(30);
System.out.println(bitSet.cardinality());// 3
System.out.println(bitSet.size());// 64
for (int i = 0; i < bitSet.size(); i++) {
if (bitSet.get(i)) {
System.err.println(i);
}
}
}
}
问2
快速判断一个数是否存在一个集合中?
答2
使用 hutool 工具包中的 LongMap
import cn.hutool.bloomfilter.bitMap.LongMap;
public class A {
public static void main(String[] args) {
LongMap longMap = new LongMap();
for (int i = 1; i <= 1_0000_0000; i++) {
longMap.add(i);
}
System.err.println(longMap.contains(1_0000_0000));// true
System.err.println(longMap.contains(1_0000_0001));// false
System.err.println(longMap.contains(-1));// true,注意: contains 方法不能判断负数是否在集合中
}
}
问3
如何只用一个字段表示用户拥有的角色?
答3
方式1: 使用逗号分隔
比如定义一个字段 role_ids
方式2: 使用位图的方式表示
右数第 1 位表示普通用户 (0: 否,1: 是)
右数第 2 位表示管理员 (0: 否,1: 是)
右数第 3 位表示超级管理员(0: 否,1: 是)
如
00000001: 普通用户
00000010: 管理员
00000100: 超级管理员
00000011: 普通用户,管理员
定义枚举
public enum UserRoleEnum {
// 1 -> 00000001
NORMAL(1, "普通用户"),
// 2 -> 00000010
ADMIN(1 << 1, "管理员"),
// 4 -> 00000100
SUPER_ADMIN(1 << 2, "超级管理员");
// 新增角色 -> 位或操作
// oldRole -> 00000001 -> 普通用户
// addRole -> 00000010 -> 新增管理员
// newRole -> 00000011 -> 普通用户和管理员
public static Integer addRole(Integer oldRole, Integer addRole) {
return oldRole | addRole;
}
// 删除角色 -> 位异或操作
// oldRole -> 00000011 -> 普通用户和管理员
// delRole -> 00000010 -> 删除管理员
// newRole -> 00000001 -> 普通用户
public static Integer removeRole(Integer oldRole, Integer delRole) {
return oldRole ^ delRole;
}
// 是否有某种角色 -> 位与操作
// allRole -> 00000011 -> 普通用户和管理员
// qryRole -> 00000001 -> 是否有管理员角色
// resRole -> 00000001 -> 有普通用户角色
public static boolean hasRole(Integer role, Integer queryRole) {
return queryRole == (role & queryRole);
}
private Integer code;
private String description;
UserRoleEnum(Integer code, String description) {
this.code = code;
this.description = description;
}
public String getDescription() {
return description;
}
public int getCode() {
return this.code;
}
public static void main(String[] args) {
System.out.println(addRole(1, 2));
System.out.println(removeRole(3, 1));
System.out.println(hasRole(3, 1));
}
}