🖼️ Bitmap(位图)详解
Bitmap(位图)是一种高效的数据结构,特别适合处理大规模二进制状态数据。
1. 什么是Bitmap?
Bitmap(位图)是一种使用二进制位(0或1)来存储和表示数据的数据结构。每个二进制位代表一个状态,通常用0表示"不存在"或"假",1表示"存在"或"真"。
从计算机科学角度看,Bitmap是一种紧凑的数据结构,它通过将每个数据项映射到一个特定的位上来实现高效存储。这与传统的布尔数组形成鲜明对比——布尔数组中每个元素通常占用1个字节(8位),而Bitmap中每个元素仅占用1位,空间利用率提升8倍。
需要注意的是,术语"Bitmap"有时也指一种图像文件格式(如BMP文件),这是一种Windows操作系统中的标准图像文件格式,采用位映射存储格式。但在数据结构上下文中,我们指的是用于高效存储和操作二进制状态数据的位图结构。
2. 为什么要使用Bitmap及其应用场景
2.1 使用Bitmap的优势
- 极高的存储效率:每个元素仅占1位,相比传统布尔数组(每元素占1字节)节省87.5%的内存空间。
- 快速查询和操作:基于位运算(AND、OR、XOR、NOT等),Bitmap支持高速的批量查询和逻辑操作。
- 支持海量数据处理:可以高效处理大规模数据集,例如10亿个用户的签到状态仅需约125MB内存(而传统方法可能需要数GB)。
2.2 常见应用场景
- 用户行为统计:记录用户每日签到状态、活跃度统计以及日活/月活(DAU/MAU)计算。
- 数据去重与排序:快速识别重复数据和对无重复数据集进行排序(如使用位图排序)。
- 数据库索引:数据库管理系统使用位图索引进行快速数据筛选和查询操作,加速特定值的查询。
- 图像处理:表示二值图像(黑白图像),每个像素用一个位表示。
- 布隆过滤器(Bloom Filter):基于位图的概率型数据结构,用于快速判断元素是否可能存在集合中,解决缓存穿透等问题。
- 系统资源管理:操作系统使用位图来管理磁盘空间和内存页的分配状态。
3. Bitmap原理详解
3.1 基本存储结构
Bitmap使用一个连续的位数组(通常基于整数数组或字节数组)来存储数据。每个位代表一个独立的状态,通常0表示"假"(false),1表示"真"(true)。
位置计算:
- 索引计算:
index = pos // 32
(当使用int32数组时)或index = pos // 8
(当使用字节数组时) - 偏移量计算:
offset = pos % 32
(int32)或offset = pos % 8
(字节数组)
3.2 核心操作与位运算
Bitmap支持三种基本操作:
-
设置位(Set Bit):将指定位置为1
bits[index] |= (1 << offset)
-
清除位(Clear Bit):将指定位置为0
bits[index] &= ~(1 << offset)
-
检查位(Test Bit):检查指定位是否为1
return (bits[index] & (1 << offset)) != 0
🧠 快速理解
1 << offset
简单来说,
1 << offset
的作用是生成一个二进制数,这个数只有从右往左数第offset
位是1
,其余位全是0
。
1
:这是一个二进制表示为...00000001
的整数。<<
:这是左移位运算符。它将一个数的所有二进制位向左移动指定的位数,右侧空出的位用0
填充。从数学上看,左移n
位相当于乘以2
的n
次方(例如,1 << 3
的结果是8
,即1 * 2³
)。offset
:这是一个数字,指定了你要将1
向左移动多少位。🛠️ 在Bitmap操作中的用途
在Bitmap中,我们用一个基本类型(如
int
或byte
)的数组来表示一个很长的比特流。要操作其中某一个特定的比特位,需要两步计算:
- 确定在哪个桶(
index
):通过索引 = 位置 / 每个桶的位数
算出目标位在数组的第几个元素中。- 确定在桶的哪一位(
offset
):通过偏移量 = 位置 % 每个桶的位数
算出目标位是这个元素二进制表示中的第几位。
1 << offset
就是为了第二步服务的。它创建了一个掩码(Mask),这个掩码只有你想要操作的那一位是1
。
- 设置位(Set Bit)为1:使用
bits[index] |= (1 << offset)
。
|=
是按位或赋值操作。按位或(|
)的规则是:有1
则1
,全0
则0
。- 用这个掩码和原数进行“或”操作,无论原数那一位原来是
0
还是1
,操作后都变成了1
,而其他位则保持不变。- 清除位(Clear Bit)为0:使用
bits[index] &= ~(1 << offset)
。
- 这里
~(1 << offset)
是按位取反,生成一个只有目标位是0
,其余位全是1
的掩码。- 再用
&=
(按位与赋值) 操作。按位与(&
)的规则是:全1
则1
,有0
则0
。- 用这个取反后的掩码和原数进行“与”操作,就能将目标位强制置
0
,而其他位保持不变。- 检查位(Check Bit):使用
(bits[index] & (1 << offset)) != 0
。
- 使用
&
(按位与) 操作。如果目标位是1
,那么与操作
的结果就不为0
;如果是0
,结果就是0
。📊 举个例子
假设我们有一个
byte
类型的数组,byte
有 8 位。我们想操作第5
位(从0
开始计数)。
- 计算索引和偏移量:
index = 5 / 8 = 0
(因为一个byte
能存 8 位,所以第5位还在第0个byte
上)offset = 5 % 8 = 5
- 生成掩码:
1 << 5
:将1
(二进制00000001
)向左移动5
位。- 结果是
00100000
(十进制32
)。- 操作:
- 设置位:
bits[0] |= 00100000
- 假设
bits[0]
原来是01010010
。- 执行按位或:
01010010 | 00100000 = 01110010
。- 可以看到,第
5
位(从右往左数)被置为了1
。- 清除位:
bits[0] &= ~(00100000)
~(00100000)
得到11011111
。- 执行按位与:
01010010 & 11011111 = 01010010
。- 如果原数是
01110010
,操作后则变为01010010
,第5
位被置0
。- 检查位:
(bits[0] & 00100000) != 0
- 执行按位与:
01010010 & 00100000 = 00000000
,结果为0
,表示该位是0
。- 如果是
01110010 & 00100000 = 00100000
,结果不为0
,表示该位是1
。💡 核心优势
使用
1 << offset
生成掩码进行位操作,是非常高效和精确的方法。CPU执行位运算指令非常快,远高于进行数学运算或条件判断。这也是为什么在底层系统、算法优化(如布隆过滤器)和需要极致性能的场景中,大量使用位操作的原因。
3.3 处理流程
以下是Bitmap基本操作的处理流程:
3.4 高级优化技术
对于特定应用场景,基础的Bitmap实现可能不是最优解,以下是常见优化技术:
- 行程长度编码(RLE):对连续相同值的位进行压缩存储,特别适合具有长连续序列的数据。
- Roaring Bitmap:将位图分成小块(通常65536位为一个块),根据每个块的数据特征选择最优存储策略(数组、未压缩位图或行程编码),在稀疏和密集数据中都表现出色。
- 分层位图:解决传统位图动态扩展困难的问题,支持更灵活的大小调整。
4. Bitmap与布隆过滤器的区别
Bitmap和布隆过滤器(Bloom Filter)都是使用位操作的数据结构,但它们在设计和应用上有显著区别:
特性 | Bitmap | 布隆过滤器 |
---|---|---|
数据结构 | 简单的位数组,每个元素直接映射到一个位 | 位数组+多个哈希函数 |
存储内容 | 精确存储元素的存在与否 | 概率性存储元素的可能存在 |
误判率 | 无误判(精确存储) | 有误判率(可能误报存在) |
空间效率 | 取决于最大元素值,稀疏数据效率低 | 相对稳定,与元素数量相关 |
删除操作 | 支持直接删除(设置位为0) | 通常不支持删除(计数布隆过滤器除外) |
适用场景 | 元素范围已知且相对密集 | 元素范围大或未知,海量数据去重、缓存穿透防护 |
内存占用 | 与最大元素值成正比 | 与元素数量和可接受误判率相关 |
数据类型 | 通常适用于整数(如直接的用户ID) | 可处理任意数据类型(如字符串用户名) |
选择建议:
- 当元素范围已知且相对密集时,使用Bitmap更合适
- 当元素范围很大或未知,且可以接受一定误判率时,使用布隆过滤器更合适
5. Python实现Bitmap及环境要求
5.1 环境要求
- Python版本:Python 3.6及以上
- 必要库:仅需标准库,无需额外依赖
- 内存要求:取决于位图大小,通常N位需要约N/8字节内存
5.2 Bitmap Python实现
以下是完整的Bitmap Python实现:
# bitmap.py
class Bitmap:
def __init__(self, size):
"""
初始化Bitmap
:param size: 位图大小,即需要表示的位数
"""
self.size = size
# 计算需要的字节数: (size + 7) // 8
self.bitarray = bytearray((size + 7) // 8)
def set_bit(self, pos):
"""
设置指定位置为1
:param pos: 位置索引(0开始)
"""
if pos >= self.size:
raise IndexError("Position out of range")
# 计算字节索引和位偏移
index = pos // 8
offset = pos % 8
# 使用位或操作设置位
self.bitarray[index] |= (1 << offset)
def clear_bit(self, pos):
"""
清除指定位置(设为0)
:param pos: 位置索引(0开始)
"""
if pos >= self.size:
raise IndexError("Position out of range")
index = pos // 8
offset = pos % 8
# 使用位与操作清除位
self.bitarray[index] &= ~(1 << offset)
def get_bit(self, pos):
"""
获取指定位的状态
:param pos: 位置索引(0开始)
:return: 如果位为1返回True,否则返回False
"""
if pos >= self.size:
raise IndexError("Position out of range")
index = pos // 8
offset = pos % 8
# 使用位与操作检查位
return (self.bitarray[index] & (1 << offset)) != 0
def __len__(self):
"""
返回位图大小
"""
return self.size
def get_memory_usage(self):
"""
返回当前内存使用量(字节)
"""
return len(self.bitarray)
def __str__(self):
"""
返回位图的字符串表示
"""
return f"Bitmap(size={self.size}, memory_usage={self.get_memory_usage()} bytes)"
# 示例用法
if __name__ == "__main__":
# 创建包含100个位的位图
bitmap = Bitmap(100)
# 设置第5位
bitmap.set_bit(5)
# 检查第5位
print("Bit 5:", bitmap.get_bit(5)) # 输出: True
# 检查第6位
print("Bit 6:", bitmap.get_bit(6)) # 输出: False
# 清除第5位
bitmap.clear_bit(5)
print("Bit 5 after clear:", bitmap.get_bit(5)) # 输出: False
# 显示内存使用
print("Memory usage:", bitmap.get_memory_usage(), "bytes") # 输出: 13 bytes
# 打印位图信息
print(bitmap)
5.3 使用第三方库bitarray
对于更高级的应用,可以使用专门的第三方库bitarray
,它提供了更丰富的功能和优化:
安装bitarray:
pip install bitarray
测试bitarray:
from bitarray import bitarray
# 创建位图
bitmap = bitarray(100)
# 初始化所有位为0
bitmap.setall(0)
# 设置位
bitmap[5] = 1
# 检查位
print(bitmap[5]) # 输出: True
# 批量操作
bitmap[10:20] = 1 # 将10-19位全部设为1
6. 性能测试脚本
用于对比Bitmap与传统布尔数组在内存和速度上的表现。
6.1 性能测试脚本
# benchmark_test.py
# 需要提前安装 bitarray psutil
import time
import random
import sys
import tracemalloc
import psutil
import os
from bitarray import bitarray
from bitmap import Bitmap
def generate_test_positions(size, num_operations, seed=None):
"""
生成用于测试的随机位置序列。
使用固定的种子确保多次测试使用完全相同的随机序列。
"""
if seed is not None:
random.seed(seed)
# 生成随机位置(允许重复,更接近真实场景)
positions = [random.randint(0, size - 1) for _ in range(num_operations)]
return positions
def get_process_memory():
"""获取当前进程的内存使用量(RSS)"""
process = psutil.Process(os.getpid())
return process.memory_info().rss
def test_boolean_array(size, positions):
"""
测试布尔数组的性能
"""
# 内存跟踪开始
tracemalloc.start()
snapshot1 = tracemalloc.take_snapshot()
mem_before = get_process_memory()
# 初始化
start_time = time.perf_counter()
bool_array = [False] * size
init_time = time.perf_counter() - start_time
# 随机设置位
start_time = time.perf_counter()
for pos in positions:
bool_array[pos] = True
set_time = time.perf_counter() - start_time
# 查询位
start_time = time.perf_counter()
count = 0
for pos in positions:
if bool_array[pos]:
count += 1
get_time = time.perf_counter() - start_time
# 内存使用统计
mem_after = get_process_memory()
snapshot2 = tracemalloc.take_snapshot()
tracemalloc.stop()
# 多种内存统计方式
memory_stats = {
'process_rss': mem_after - mem_before, # 进程实际内存增长
'object_size': sys.getsizeof(bool_array) + sys.getsizeof(False) * size, # 对象理论大小
'tracemalloc_diff': sum(stat.size for stat in snapshot2.compare_to(snapshot1, 'filename')), # 内存分配差异
}
return init_time, set_time, get_time, memory_stats, count
def test_bitmap(size, positions):
"""
测试自定义Bitmap的性能
"""
# 内存跟踪开始
tracemalloc.start()
snapshot1 = tracemalloc.take_snapshot()
mem_before = get_process_memory()
# 初始化
start_time = time.perf_counter()
bitmap = Bitmap(size)
init_time = time.perf_counter() - start_time
# 随机设置位
start_time = time.perf_counter()
for pos in positions:
bitmap.set_bit(pos)
set_time = time.perf_counter() - start_time
# 查询位
start_time = time.perf_counter()
count = 0
for pos in positions:
if bitmap.get_bit(pos):
count += 1
get_time = time.perf_counter() - start_time
# 内存使用统计
mem_after = get_process_memory()
snapshot2 = tracemalloc.take_snapshot()
tracemalloc.stop()
memory_stats = {
'process_rss': mem_after - mem_before,
'object_size': bitmap.get_memory_usage(),
'tracemalloc_diff': sum(stat.size for stat in snapshot2.compare_to(snapshot1, 'filename')),
}
return init_time, set_time, get_time, memory_stats, count
def test_bitarray(size, positions):
"""
测试bitarray库的性能
"""
# 内存跟踪开始
tracemalloc.start()
snapshot1 = tracemalloc.take_snapshot()
mem_before = get_process_memory()
# 初始化
start_time = time.perf_counter()
ba = bitarray(size)
ba.setall(0)
init_time = time.perf_counter() - start_time
# 随机设置位
start_time = time.perf_counter()
for pos in positions:
ba[pos] = 1
set_time = time.perf_counter() - start_time
# 查询位
start_time = time.perf_counter()
count = 0
for pos in positions:
if ba[pos]:
count += 1
get_time = time.perf_counter() - start_time
# 内存使用统计
mem_after = get_process_memory()
snapshot2 = tracemalloc.take_snapshot()
tracemalloc.stop()
# bitarray的内存统计
memory_stats = {
'process_rss': mem_after - mem_before,
'object_size': sys.getsizeof(ba),
'tracemalloc_diff': sum(stat.size for stat in snapshot2.compare_to(snapshot1, 'filename')),
}
return init_time, set_time, get_time, memory_stats, count
def format_memory_size(bytes_size):
"""格式化内存大小为易读形式"""
for unit in ['B', 'KB', 'MB', 'GB']:
if bytes_size < 1024.0:
return f"{bytes_size:.2f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.2f} TB"
def run_performance_test():
"""运行性能测试"""
# 设置一个全局随机种子,确保测试的可重复性
test_seed = 42
test_sizes = [1000, 10000, 100000, 1000000]
operation_ratio = 0.1 # 操作10%的位
print("性能测试对比: 布尔数组 vs 自定义Bitmap vs bitarray库")
print("=" * 90)
for size in test_sizes:
num_operations = int(size * operation_ratio)
# 为当前测试规模生成固定的随机位置序列
positions = generate_test_positions(size, num_operations, test_seed)
print(f"\n测试规模: {size} 位, 操作次数: {num_operations} 次")
print("-" * 60)
# 测试三种数据结构
bool_init, bool_set, bool_get, bool_mem, bool_count = test_boolean_array(size, positions)
bm_init, bm_set, bm_get, bm_mem, bm_count = test_bitmap(size, positions)
ba_init, ba_set, ba_get, ba_mem, ba_count = test_bitarray(size, positions)
# 检查结果一致性
counts = [bool_count, bm_count, ba_count]
if len(set(counts)) > 1:
print(f"❌ 警告: 结果不一致 布尔数组={bool_count}, Bitmap={bm_count}, bitarray={ba_count}")
else:
print(f"✅ 结果一致: 统计到的'真'位数量均为 {bool_count}")
# 输出性能结果表格
print(f"\n{'性能指标':<15} | {'布尔数组':<15} | {'自定义Bitmap':<15} | {'bitarray库':<15}")
print("-" * 65)
print(f"{'初始化时间(s)':<15} | {bool_init:<15.6f} | {bm_init:<15.6f} | {ba_init:<15.6f}")
print(f"{'设置时间(s)':<15} | {bool_set:<15.6f} | {bm_set:<15.6f} | {ba_set:<15.6f}")
print(f"{'查询时间(s)':<15} | {bool_get:<15.6f} | {bm_get:<15.6f} | {ba_get:<15.6f}")
# 输出内存结果表格
print(f"\n{'内存指标':<15} | {'布尔数组':<15} | {'自定义Bitmap':<15} | {'bitarray库':<15}")
print("-" * 65)
print(f"{'进程RSS增长':<15} | {format_memory_size(bool_mem['process_rss']):<15} | {format_memory_size(bm_mem['process_rss']):<15} | {format_memory_size(ba_mem['process_rss']):<15}")
print(f"{'对象大小':<15} | {format_memory_size(bool_mem['object_size']):<15} | {format_memory_size(bm_mem['object_size']):<15} | {format_memory_size(ba_mem['object_size']):<15}")
print(f"{'内存分配差异':<15} | {format_memory_size(bool_mem['tracemalloc_diff']):<15} | {format_memory_size(bm_mem['tracemalloc_diff']):<15} | {format_memory_size(ba_mem['tracemalloc_diff']):<15}")
# 计算内存优化比
bool_rss, bm_rss, ba_rss = bool_mem['process_rss'], bm_mem['process_rss'], ba_mem['process_rss']
if ba_rss > 0:
bool_ratio = bool_rss / ba_rss
bm_ratio = bm_rss / ba_rss if bm_rss > 0 else 0
print(f"\n内存优化比 (相对于bitarray): 布尔数组={bool_ratio:.1f}x, 自定义Bitmap={bm_ratio:.1f}x")
if __name__ == "__main__":
run_performance_test()
6.2 测试结果
能测试对比: 布尔数组 vs 自定义Bitmap vs bitarray库
==========================================================================================
测试规模: 1000 位, 操作次数: 100 次
------------------------------------------------------------
✅ 结果一致: 统计到的'真'位数量均为 100
性能指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
初始化时间(s) | 0.000005 | 0.000006 | 0.000008
设置时间(s) | 0.000005 | 0.000086 | 0.000006
查询时间(s) | 0.000005 | 0.000085 | 0.000006
内存指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
进程RSS增长 | 8.00 KB | 4.00 KB | 24.00 KB
对象大小 | 31.30 KB | 125.00 B | 205.00 B
内存分配差异 | 16.07 KB | 2.15 KB | 845.00 B
内存优化比 (相对于bitarray): 布尔数组=0.3x, 自定义Bitmap=0.2x
测试规模: 10000 位, 操作次数: 1000 次
------------------------------------------------------------
✅ 结果一致: 统计到的'真'位数量均为 1000
性能指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
初始化时间(s) | 0.000036 | 0.000004 | 0.000003
设置时间(s) | 0.000021 | 0.000805 | 0.000029
查询时间(s) | 0.000191 | 0.000991 | 0.000206
内存指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
进程RSS增长 | 80.00 KB | 0.00 B | 0.00 B
对象大小 | 312.55 KB | 1.22 KB | 1.30 KB
内存分配差异 | 78.82 KB | 2.19 KB | 1.88 KB
测试规模: 100000 位, 操作次数: 10000 次
------------------------------------------------------------
✅ 结果一致: 统计到的'真'位数量均为 10000
性能指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
初始化时间(s) | 0.000367 | 0.000013 | 0.000005
设置时间(s) | 0.000628 | 0.008169 | 0.000280
查询时间(s) | 0.002882 | 0.010670 | 0.002564
内存指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
进程RSS增长 | 780.00 KB | 12.00 KB | 0.00 B
内存分配差异 | 781.83 KB | 12.93 KB | 12.87 KB
测试规模: 1000000 位, 操作次数: 100000 次
------------------------------------------------------------
✅ 结果一致: 统计到的'真'位数量均为 100000
性能指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
初始化时间(s) | 0.001428 | 0.000014 | 0.000010
设置时间(s) | 0.008289 | 0.081454 | 0.003060
查询时间(s) | 0.034225 | 0.107338 | 0.025853
内存指标 | 布尔数组 | 自定义Bitmap | bitarray库
-----------------------------------------------------------------
进程RSS增长 | 7.63 MB | 0.00 B | 0.00 B
对象大小 | 30.52 MB | 122.07 KB | 122.15 KB
内存分配差异 | 7.63 MB | 122.79 KB | 122.73 KB
6.3 实际应用测试:用户签到场景
以下是一个模拟实际应用场景的测试脚本:
# user_attendance.py
import time
import random
from bitmap import Bitmap
def test_user_attendance():
"""测试用户签到场景"""
print("\n用户签到场景测试")
print("=" * 40)
# 模拟100万用户,365天签到数据
user_count = 1000000
days = 365
# 使用Bitmap存储每个用户每年的签到数据
# 每个用户需要365位,全年约45.6字节
total_bits = user_count * days
total_memory = total_bits / 8 / 1024 / 1024 # 转换为MB
print(f"用户数量: {user_count}")
print(f"跟踪天数: {days}")
print(f"总位数: {total_bits}")
print(f"预计内存使用: {total_memory:.2f} MB")
# 创建Bitmap
attendance_bitmap = Bitmap(total_bits)
# 模拟随机签到数据(约30%的签到率)
start_time = time.time()
for user_id in range(user_count):
for day in range(days):
if random.random() < 0.3: # 30%概率签到
pos = user_id * days + day
attendance_bitmap.set_bit(pos)
storage_time = time.time() - start_time
print(f"数据存储时间: {storage_time:.2f} 秒")
# 查询特定用户签到情况
start_time = time.time()
test_user = 500000
sign_count = 0
for day in range(days):
pos = test_user * days + day
if attendance_bitmap.get_bit(pos):
sign_count += 1
query_time = time.time() - start_time
print(f"用户{test_user}签到天数: {sign_count}")
print(f"单用户查询时间: {query_time:.4f} 秒")
# 计算全局签到率
start_time = time.time()
total_signs = 0
for user_id in range(1000): # 抽样1000用户
for day in range(days):
pos = user_id * days + day
if attendance_bitmap.get_bit(pos):
total_signs += 1
global_time = time.time() - start_time
print(f"抽样签到总数: {total_signs}")
print(f"全局统计时间: {global_time:.2f} 秒")
# 运行实际场景测试
test_user_attendance()
签到测试结果:
用户签到场景测试
========================================
用户数量: 1000000
跟踪天数: 365
总位数: 365000000
预计内存使用: 43.51 MB
数据存储时间: 46.96 秒
用户500000签到天数: 120
单用户查询时间: 0.0000 秒
抽样签到总数: 109326
全局统计时间: 0.08 秒
此测试展示Bitmap在处理大规模二进制状态数据时的实际应用效果,在内存使用方面的显著优势。
7.总结
Bitmap是一种极其高效的数据结构,特别适用于处理大规模二进制状态数据。它的主要优势在于:
- 极高的存储效率,相比传统布尔数组可节省87.5%以上的内存空间。
- 快速批量操作,支持基于位运算的高效逻辑操作。
- 适合海量数据,可以处理数亿甚至数十亿条记录的状态存储。
在实际应用中,Bitmap特别适合用户行为跟踪、系统监控、数据去重和数据库索引等场景。当需要处理大量是/否状态数据时,Bitmap应该是首选的数据结构之一。
8.代码下载
点击下载:BitMapDemo.7z