位图:
概念:

由于位图是通过一个比特位来判断是不是在范围里面的,所以其对应的时间复杂度都是O(1)的。
位图的实现:

如上图所示:
上图对应的就是3个字节,即24个比特位
要想实现位图,就得知道我们要记录的这个数应该存储到哪个位置,假设这个数是x
那么对应:
x / 32 所得的值就是该数字应该存在第几个字节上
x % 32 所得的值就是对应在此字节的第几位上,这样一来位图就简单了
我们主要实现 set,reset,test这三个借口,代码如下:
- #pragma once
- #include
- using namespace std;
-
- namespace bit
- {
- template<size_t N>
- class bitset
- {
- public:
-
- bitset()
- {
- _a.resize(N / 32 + 1);
- }
-
- // x映射的那个标记成1
- void set(size_t x)
- {
- size_t i = x / 32;
- size_t j = x % 32;
-
- _a[i] |= (1 << j);
- }
-
- // x映射的那个标记成0
- void reset(size_t x)
- {
- size_t i = x / 32;
- size_t j = x % 32;
-
- _a[i] &= (~(1 << j));
- }
-
- // 判断 x 是否在位图里面
- bool test(size_t x)
- {
- size_t i = x / 32;
- size_t j = x % 32;
-
- return _a[i] & (1 << j);
- }
-
- private:
- vector<int> _a;
- };
- }
注意这里模板的应用,是为了开出大小适中的位图出来。
测试代码:

位图的应用:
1. 给定100亿个整数,设计算法找到只出现一次的整数?
要找到只出现一次的整数,就要让出现一次和出现多次的数有所区别,
而位图只能存储0或1,所以没法区别,这是就需要用到两个位图:
只要出现多次,就将其记成10,这样就得以区分
对应的代码实现:
- template<size_t N>
-
- class TwoBitSet1
- {
- public:
- void set(size_t x)
- {
- // 00 -> 01
- if (!_bs1.test(x) && !_bs2.test(x))
- {
- _bs2.set(x);
- }
-
- //01 -> 10
- else if (!_bs1.test(x) && _bs2.test(x))
- {
- _bs1.set(x);
- _bs2.reset(x);
- }
- }
-
- bool is_once(size_t x)
- {
- return !_bs1.test(x) && _bs2.test(x);
- }
-
- private:
- bitset
_bs1; - bitset
_bs2; - };
测试代码:

2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
解法:
将两个文件分别映射到两个位图,再将两个位图的值与一下即可:
对应的代码实现如下:
- int main()
- {
- int a1[] = { 1, 2, 3, 3, 4, 4, 4, 4, 4, 2, 3, 6, 3, 1, 5, 5, 8, 9 };
- int a2[] = { 8, 4, 8, 4, 1, 1, 1, 1 };
-
- bit::bitset<10> bs1;
- bit::bitset<10> bs2;
-
- for (auto e : a1)
- {
- bs1.set(e);
- }
-
- for (auto e : a2)
- {
- bs2.set(e);
- }
-
- for (int i = 0; i < 10; i++)
- {
- if (bs1.test(i) && bs2.test(i))
- {
- cout << i << " ";
- }
- }
- cout << endl;
- return 0;
- }
代码测试:

3.位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
其实做法与第一题很像,直接上代码:
- template<size_t N>
-
- class TwoBitSet2
- {
- public:
- void set(size_t x)
- {
- // 00 -> 01
- if (!_bs1.test(x) && !_bs2.test(x))
- {
- _bs2.set(x);
- }
-
- //01 -> 10
- else if (!_bs1.test(x) && _bs2.test(x))
- {
- _bs1.set(x);
- _bs2.reset(x);
- }
- //10 -> 11
- else if (_bs1.test(x) && !_bs2.test(x))
- {
- _bs2.set(x);
- }
- }
-
- bool is_once(size_t x)
- {
- return !_bs1.test(x) && _bs2.test(x);
- }
-
- bool is_twice(size_t x)
- {
- return _bs1.test(x) && !_bs2.test(x);
- }
-
-
-
- private:
- bitset
_bs1; - bitset
_bs2; - };
测试代码:

库里面的位图接口:

概念:

只能确定其一定不存在或者可能存在,注意可能二字
所以说布隆过滤器不能准确判断一个东西是否存在。
应用:
1.不需要精确的场景,快速判断昵称是否存在
2.精确的场景,布隆过滤器