本文最后更新于:2021年4月16日 上午
位图原理以及C++实现
位图
位图就是一个数组的每一个数据的每一个二进制位来表示一个数据,0表示数据不存在,1表示数据存在。
例如136这个数字,
136 / 32 = 4
,一个int的二进位制可以存放32个数,136存放于第4个区间,(区间从0开始)
136 % 32 = 8
,表示136存放于8号位置,(位置从0开始)
然后将那个位置置为1即可。
位图代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <iostream> #include <string> #include <vector> #include <algorithm>
using namespace std;
class BitMap { public: BitMap(int size) { m_bitmap.resize(size / 32 + 1); }
void Set(int x) { int block = x / 32; int index = x % 32; m_bitmap[block] |= (1 << index); }
void Reset(int x) { int block = x / 32; int index = x % 32; m_bitmap[block] &= ~(1 << index); }
bool Test(int x) { int block = x / 32; int index = x % 32; if (m_bitmap[block] & (1 << index)) return true; else return false; }
private: vector<int> m_bitmap; };
|
代码实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| int main() {
BitMap bitmap(136); bitmap.Set(136); if (bitmap.Test(136)) cout << "136位于位图之中" << endl; else cout << "136不在位图中" << endl;
if(bitmap.Test(120)) cout << "120位于位图之中" << endl; else cout << "120不在位图中" << endl;
bitmap.Reset(136); if (bitmap.Test(136)) cout << "136位于位图之中" << endl; else cout << "136不在位图中" << endl;
vector<int> nums(10000); for (int i = 0; i < 10000; i++) { nums[i] = i + 1; }
nums[3546] = 0; nums[9856] = 0;
random_shuffle(nums.begin(), nums.end());
BitMap bits(10000); for (int i = 0; i < 10000; i++) { bits.Set(nums[i]); }
cout << "被删除的元素: "; for (int i = 1; i <= 10000; i++) { if (!bits.Test(i)) { cout << i << " "; } } cout << endl;
return 0; }
|
输出结果:
1 2 3 4
| 136位于位图之中 120不在位图中 136不在位图中 被删除的元素: 3547 9857
|
实例
一个文件无序存放了1万个数字,每行1个,数字范围1-1w,不重复,现在随机删除两个数字,请把两个数字找出来。
- 使用hash,遍历文件,每遍历到一个数字,就以该数字为下标的数组元素置1
- 然后再遍历一遍hash,值为0的元素对应的下标就是所求的数字。
内存优化
使用bitmap,每一个bit可以代表一个数字。这样可以压缩到内存。
压缩率
bit表示一位数字,而之前一个数字就是int,压缩率32倍
适用bitmap的场景
若数据有重复
- 使用2-bitmap。00表示不出现、01表示出现1次,10表示出现2次,11表示无定义
- 若是随机统计一个数具体出现了多少次呢?
- 最多出现1万次,那么二进制就是14位
- 用14位来记录一个数,也比32位记录一个数开销小。