C++基础(20)——位图的模拟实现

目录
bitset的接口函数总览
代码如下:
namespace xywl {
template <size_t N>
class bitset {
public:
// 构造函数
bitset();
// 反转
void flip(size_t pos);
// 设置
void set(size_t pos);
// 清空
void reset(size_t pos);
// 获取
bool test(size_t pos);
// 获取位数
size_t size();
// 获取1的位数
size_t count();
// 判断是不是所有的位都没被设置
bool none();
// 判断位图中是不是所有的位都是被设置的
bool all();
// 判断是不是有位图里面有1
bool any();
private:
vector<int> _bits;
};
}
我们这里的实现是相对简单的,并没有将我们的所有功能都实现了,只是实现了部分重要的功能。
bitset的实现
构造函数
我们在构造对象的时候,需要给出我们的位数N,并且默认将我们的位都设置成0。
我们一般的实现是使用unsigned int来存,这样可以避免int带来的负数问题,我们的32位都可以使用,所以我们的位图使用的是vector容器存unsigned int来实现的,但是我们这里开出来的大小需要使用N / 32 + 1来计算,因为我们的N有可能不是32的整数倍。
比如下面的情况:
当我们申请的位数N是35的时候,我们就需要开出来两个unsigned int类型了。

代码如下:
bitset() {
_bits.resize(N / 32 + 1, 0);
}
操作函数set、reset、test、flip的实现
set函数的实现
set使用来设置pos位置为1的。
实现的方式如下:
1、先要计算出来我们在你个unsigned int块,在计算在块里的那个位置。
2、将我们的1左移指定位置和目标或运算即可。
图示:

代码如下:
// 设置
void set(size_t pos) {
assert(pos < N);
// 算出是那个int块的
int i = pos / 32;
// 算出是块里面的那个位置
int j = pos % 32;
// 使用或操作来调整
_bits[i] |= (1 << j);
}
reset函数的实现
我们reset函数的实习方式如下:
1、和之前的操作一样,计算出我们的位置。
2、将我们的1左移指定位置取反和目标与运算即可。
图示:

代码如下:
// 清空
void reset(size_t pos) {
assert(pos < N);
int i = pos / 32;
int j = pos % 32;
_bits[i] &= (~(1 << j));
}
flip函数的实现
我们实现的步骤如下:
1、先还是找到我们的位置。
2、将我们的1左移指定位置后和目标异或运算即可。
图示:

代码如下:
// 反转
void flip(size_t pos) {
assert(pos < N);
// 算出是那个int块的
int i = pos / 32;
// 算出是块里面的那个位置
int j = pos % 32;
// 使用异或操作来调整
_bits[i] ^= (1 << j);
}
test函数的实现
实现的方式如下:
1、我们还是先要找到我们的位置。
2、将1左移指定位置的值和我们的目标值与运算返回即可。

代码如下:
// 获取
bool test(size_t pos) {
assert(pos < N);
int i = pos / 32;
int j = pos % 32;
return _bits[i] & (1 << j);
}
统计函数size、count的实现
size的实现
size就是用来返回我们的容量的也就是我们最开始传入的值了。
代码如下:
// 获取位数
size_t size() {
return N;
}
count的实现
我们的count的实现就是用来获取图中被设置了1的位的个数。
我们这里要获取所有的被设置了的1,要遍历我们的vector容器中的所有的unsigned int块。
实现方法如下:
1、获取在vector容器中的值。
2、用一个临时的变量来存一下这个值,然后让它与上我们的1,判断是不是true,是的话就计数加加,不是或者操作完了之后我们的值右移一位。
代码如下:
// 获取1的位数
size_t count() {
size_t temp = 0;
for(auto& s : _bits) {
int t = s;
while(t) {
if(t & 1) {
temp++;
}
t = t >> 1;
}
}
}
判断函数any、none、all的实现
any函数的实现
any函数是用来判断位图中的位是不是有被设置过大于等于一次。
我们这里的实现逻辑如下:
遍历我们的vector容器,判断当前值是不是不是0,不是就直接返回true即可;要是是0,就继续,最后我们返回false即可。
代码如下:
bool any() {
// 只要有一个有值就返回true
for(auto& s : _bits) {
if(s) {
return true;
}
}
return false;
}
none函数的实现
我们的none函数就是用来判断我们的所有的位是不是都没有被设置过。
实现逻辑如下:
我们可以直接复用我们的any函数,返回对于any函数的取反操作。
代码如下:
// 判断是不是所有的位都没被设置
bool none() {
// 复用我们的any
return !any();
}
all函数的实现
我们all函数就是为了判断我们的所有位是不是都被设置了,是就返回true,不是就返回false即可。
我们实现的逻辑如下:
1、先检查比较好检查的前面n - 1个unsigned int块是不是全是1,只需要判断取反之后是不是0即可。
2、再判断我们的最后一个unsigned int块的前面N % 32个比特位是不是全是1即可。
图示:

代码如下:
// 判断位图中是不是所有的位都是被设置的
bool all() {
size_t n = _bits.size();
// 先判断整块的,再判断零散的
for(size_t i = 0; i < n - 1; i++) {
if(~_bits[i] != 0) {
return false;
}
}
// 零散的
for(size_t i = 0; i < N % 32; i++) {
if((_bits[n - 1] & (1 << i)) == 0) {
return false;
}
}
return true;
}
更多推荐
所有评论(0)