什么是位图?
bit:计算机最小单位(0或者1),逻辑上可以表示是/否,有/无等,位图是一种用“二进制位(bit)”来表示状态的数据结构
位图的核心能力是省内存 + 查询快(O(1)),表示N个值的状态只需要N个bit,内存使用是N/8个字节,并且是一个Map,查询
应用场景
快速去重
输入:[7, 3, 7, 2, 3, 9](范围 0~9)
过程:
看到 7:第 7 位从 0->1,输出 7
看到 3:第 3 位从 0->1,输出 3
再看到 7:第 7 位已是 1,跳过
看到 2:第 2 位从 0->1,输出 2
再看到 3:跳过
看到 9:第 9 位从 0->1,输出 9
结果:[7, 3, 2, 9]
这比 HashSet 更省内存(在范围不大时尤其明显)。
成员检查(黑白名单)
你有 0~1,000,000 的 ID,频繁判断“某 ID 是否在白名单里”。
用位图预处理白名单
每次查询只查一位
时间复杂度 O(1),非常快
位图排序
如果数据是“范围已知的非负整数”,可以:
扫描一遍,把出现过的数字位置设 1
从小到大扫描位图,遇到 1 就输出数字
输出天然有序。
这在“海量整数、内存紧张”时很经典。
适合VS不适合的场景
适合:
数据是整数
值域可控(比如 0~几千万)
只关心“是否存在/是否命中”这类布尔状态
不适合:
值域极大且非常稀疏(例如最大值 10^12,只出现几百个)
需要存的不只是存在性(比如还要存次数、对象内容)
布隆过滤器核心数据结构就是使用的位图
海量QQ号去重
以腾讯的面试题为切入点来讲解位图的使用:
40亿个QQ号如何去重,只能使用1GB内存。
解析:一个整数占用4个字节,40亿个整数需要大概14.9G内存。此时可以使用位图来解决
位图一个字节能存8bit,4个字节能存32个数也就是说内存占用小32倍,完全符合条件
我使用了RoaringBitmap来实现