Bitmap不适用于海量数据去重,仅适合值域已知且密集的整数场景;超出寻址范围、含负数/浮点/字符串、或值域极度稀疏时会导致内存爆炸或不可行。

Bitmap 本身不适用于“海量数据去重”这个目标——它只适合整数范围已知且密集的场景;一旦数据超出 size_t 可寻址范围(如 > 4GB 位空间)、存在负数、浮点数、字符串,或值域极度稀疏(比如只有 10 个数分布在 [0, 1e18]),直接用单层 Bitmap 就会内存爆炸或根本不可行。
为什么 std::bitset 或手写 uint64_t 数组不能直接用于“海量”去重
常见误判是认为“Bitmap 内存省”,但没算清楚位宽代价:std::bitset 在编译期就报错(模板参数太大);运行时动态分配 new uint8_t[1250000000](10G 字节)在多数服务环境已越界。更关键的是:Bitmap 的下标即数值,意味着你必须能把任意输入映射成一个非负整数索引,且冲突必须为零——这要求哈希后仍保持唯一性,而普通哈希做不到。
- 值域为 [0, N) 且 N ≤ 1e8 → 单层
std::vector或boost::dynamic_bitset可行 - 值域含负数/字符串/超大整数 → 必须先做无冲突哈希 + 分桶,Bitmap 只能作为底层存储单元
- 去重后还需遍历所有唯一值 → Bitmap 不支持高效枚举,得额外维护链表或 offset 表
分层 Bitmap 模型:用两级哈希 + 小 Bitmap 实现可落地的海量整数去重
核心思路是把“全局唯一 ID”拆成高位桶号 + 低位偏移,每桶内用固定大小 Bitmap(如 64KB)管理局部值域。这样总内存 = 桶数量 × 单桶 Bitmap 大小,可线性扩展。
假设处理 10 亿个 64 位整数,希望单桶 Bitmap 占 64KB(524288 bit),则每桶可覆盖 524288 个连续整数。取高位 32 位作桶号(支持约 42 亿桶),低位 19 位作 Bitmap 索引(2^19 = 524288):
uint64_t x = ...; uint32_t bucket_id = x >> 19; // 高 45 位?不对——要确保低位刚好 fit 进 Bitmap uint32_t offset = x & 0x7FFFF; // 19 bits → max 524287
实际中更稳妥做法是用 std::unordered_map 懒加载桶,避免预分配空桶。
- 插入前检查
buckets.find(bucket_id),不存在则 new 一个vector(524288) - 设位:
buckets[bucket_id]->operator[](offset) = true - 查重:先查桶是否存在,再查 offset 是否为 true
- 内存优势:只加载实际出现过桶号的 Bitmap,稀疏数据下节省巨大
查找加速:Bitmap 自带 O(1) 查重,但“找第 K 个去重值”必须额外建索引
Bitmap 支持 O(1) 判重,但无法回答“去重后第 100 万个数是多少”。若业务需要顺序访问去重结果,不能靠扫全量 Bitmap(太慢),得在插入时同步维护稀疏索引:
- 每个桶额外记录
popcount(当前桶内已设位数),用std::vector存各桶累计计数 - 查第 K 个值:二分找到落在哪个桶,再在该桶 Bitmap 中用
std::bitset::_Find_first(GCC)或手动 __builtin_popcount + 逐字扫描定位 offset - 注意:跨桶索引需原子更新,多线程插入时建议用
std::atomic维护桶级计数
没有银弹——你要的是“去重结果集”,Bitmap 只是中间结构;最终交付往往还得导出到 std::vector,此时真正耗时的是枚举逻辑,不是判重本身。
真实工程取舍:什么时候该放弃 Bitmap,改用 roaring bitmap 或 unordered_set
当你的数据满足以下任一条件,硬上自研 Bitmap 反而更慢、更难维护:
- 去重后还要支持交/并/差集运算 → 直接用
roaring::Roaring64Map,它内部就是分层+压缩+缓存友好 - 数据量 std::unordered_set
实测更快,cache miss 更少 - 需要持久化或跨进程共享 →
mmap+roaring比自己序列化一堆 vector安全得多 - 团队没人力长期维护位操作边界(如
offset >= bitmap_size溢出)→ 越简单越可靠
Bitmap 的价值不在“炫技”,而在精准控制内存布局和访存模式。如果连 __builtin_ctzll 和 cache line 对齐都没调优过,所谓“深度优化”只是给 bug 加速。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











