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));
	}

}

参考

posted @ 2021-07-01 14:34  凛冬雪夜  阅读(226)  评论(0)    收藏  举报