bitmap是高效处理海量整型数据去重与存在性查找的基础结构;基础实现用std::vector映射整数,通过位运算set/query,__builtin_popcountll统计;分段bitmap则按seg_size动态分配以支持超大值域。

如果您需要在C++中高效处理海量整型数据的去重与存在性查找,Bitmap(位图)是一种空间与时间性能俱佳的基础算法结构。以下是针对该需求的具体实现与优化方案:
一、基础Bitmap位图实现
使用连续的比特序列映射整数集合,每个bit代表一个整数是否出现过,适用于值域范围明确且相对集中的场景。其核心是将整数映射到字节数组的特定bit位置,通过位运算完成标记与查询。
1、定义Bitmap类,内部使用std::vector
2、实现set(int x)方法:计算x对应桶索引bucket = x / 64,位偏移offset = x % 64,执行data[bucket] |= (1ULL
3、实现test(int x)方法:同样计算bucket和offset,返回(data[bucket] >> offset) & 1ULL。
4、实现count()方法:遍历所有uint64_t元素,调用__builtin_popcountll统计置位总数。
二、分段Bitmap支持超大值域
当整数范围远超内存可分配连续空间(如0~2^40),单一数组不可行。分段Bitmap将值域划分为固定大小的区间,按需动态分配对应段的位图,避免预分配浪费。
1、设定段大小SEG_SIZE = 1
2、使用std::unordered_map
3、set(int x)时:计算seg_id,若segments中无该键,则插入长度为(SEG_SIZE + 63) / 64的全零vector;再在对应vector中设置bit。
4、test(int x)时:先查seg_id是否存在,不存在则返回false;存在则在其vector中执行位测试。
三、Roaring Bitmap压缩优化结构
原始Bitmap在稀疏场景下空间利用率极低。Roaring Bitmap将每个段进一步划分为65536值域的container,对不同密度采用不同编码:短数组(
1、引入roaring/roaring.hh头文件(需编译链接roaring库)。
2、声明roaring_bitmap_t* rb = roaring_bitmap_create();
3、插入整数:roaring_bitmap_add(rb, x); 支持批量add_many接口。
4、查询存在性:roaring_bitmap_contains(rb, x); 返回bool值。
5、获取去重后数量:roaring_bitmap_cardinality(rb);
四、并发安全Bitmap封装
多线程环境下直接操作共享Bitmap易引发数据竞争。采用细粒度锁或无锁结构保障线程安全,同时避免全局锁导致的性能瓶颈。
1、将整个值域划分为N个互不重叠的子区间,每个区间绑定一个std::shared_mutex与独立Bitmap子实例。
2、set(int x)时:计算子区间ID = x % N,对该子实例加写锁,执行位设置后释放。
3、test(int x)时:同样计算ID,对该子实例加读锁,执行位测试后释放。
4、构造函数中预分配N个子Bitmap,并初始化对应锁对象。
五、内存映射Bitmap持久化访问
当数据量超过物理内存,或需进程间共享Bitmap状态时,使用mmap将文件映射为内存区域,实现外存Bitmap的透明访问。
1、创建指定大小的临时文件(如size = ((max_value + 7) / 8)字节),用ftruncate设定长度。
2、调用mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)获取映射地址ptr。
3、封装Bitmap操作:set(x)转为对ptr[x/8]字节的第(x%8)位执行原子或互斥写入;test(x)转为对ptr[x/8]的位读取。
4、使用msync(ptr, size, MS_SYNC)确保修改落盘,munmap释放映射。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











