关于bitset
bitset是C++ STL中的一种容器,用以标记一种0、1的位状态,可以声明一定长度的二进制位,然后每一位只能是0或者1。需要包含头文件<bitset>
。
如何小实现一下?
一、数据部分
可以使用一个unsigned long long的数组来保存,每一个数长度为64位,根据声明的长度来确定数组的长度。
于是数据结构的存储如下:
class BitState
{
protected:
unsigned int bitlen;
unsigned int numlen;
unsigned long long *bits;
};
我称其为BitState,有一个bitlen来保存声明的二进制位数,numlen保存数组的长度,bits指针指向存储数组。
二、操作部分
首先,我们需要构造函数:
可能需要包含以下几种:
BitState();//无参构造函数
BitState(unsigned int len);//带参数len的构造函数,声明一个二进制长度为len的BitState
BitState(unsigned int len, unsigned long long val);//传入len的同时,传入一个无符号64位整形数,用这个数初始化BitState。
BitState(const BitState &tmp);//拷贝构造函数,实现深拷贝
对于BitState();
实现:
BitState::BitState()
{
bitlen = 8*sizeof(unsigned long long);
numlen = 1;
bits = new unsigned long long[numlen];
}
默认就让它占一个unsigned long long大小,用sizeof防止不同编译器unsigned long long大小不一样,不过貌似都是64位的。
对于BitState(int len);
实现:
BitState::BitState(unsigned int len)
{
bitlen = len;
numlen = (len+8*sizeof(unsigned long long)-1)/sizeof(unsigned long long)/8;
bits = new unsigned long long[numlen];
}
由于此处计算numlen应该使用上取整,对于x/y,上取整应该是(x+y-1)/y。
对于BitState(unsigned int len, unsigned long long val);
实现:
BitState::BitState(unsigned int len, unsigned long long val)
{
bitlen = len;
numlen = (len+8*sizeof(unsigned long long)-1)/sizeof(unsigned long long)/8;
bits = new unsigned long long[numlen];
if (len) bits[0] = val;
}
这里需对len为0的情况进行判断,防止bits[0]越界。
对于BitState(const BitState &tmp);
实现:
BitState::BitState(const BitState &tmp)
{
bitlen = tmp.bitlen;
numlen = tmp.numlen;
bits = new unsigned long long[numlen];
for (int i = 0; i < numlen; ++i) bits[i] = tmp.bits[i];
}
这里需要遍历bits来进行深拷贝。
然后,我们需要析构函数:
~BitState();
如下实现:
BitState::~BitState()
{
delete bits;
}
需要删除bits防止内存泄漏。
其次,我们还有实现一些bitset拥有的功能
bool any();//是否存在置为1的二进制位?
bool none();//不存在置为1的二进制位吗?
unsigned int count();//置为1的二进制位的个数
unsigned int size();//二进制位的个数
b[pos]//访问b中在pos处的二进制位
bool test(unsigned int pos);//在pos处的二进制位是否为1?
void set();//把所有二进制位都置为1
void set(unsigned int pos);//在pos处的二进制位置为1
void reset();//把所有二进制位都置为0
void reset(unsigned int pos);//在pos处的二进制位置为0
void flip();//把所有二进制位逐位取反
void flip(unsigned int pos);//在pos处的二进制位取反
unsigned long long to_ulong()//返回一个unsigned long值
接下来逐个实现,除了下标运算符用get函数实现,其余不变:
bool BitState::any()
{
for (int i = 0; i < numlen; ++i)
if (bits[i]) return true;
return false;
}
这个比较简单,判断是否有数为非负即可。
bool BitState::none()
{
for (int i = 0; i < numlen; ++i)
if (bits[i]) return false;
return true;
}
这个和any正好相反
unsigned int BitState::count()
{
unsigned all = 0, tmp;
for (int i = 0; i < numlen; ++i)
{
tmp = bits[i];
while (tmp)
{
all++;
tmp = tmp&(tmp-1);
}
}
return all;
}
这里使用x&(x-1)这个来每次消掉x最低位1,来计算其中1的个数。
unsigned int BitState::size()
{
return bitlen;
}
这个直接返回即可。
bool BitState::get(unsigned int pos)
{
if (pos >= bitlen) return 0;
int numsize = 8*sizeof(unsigned long long);
int x = pos/numsize, y = pos%numsize;
return bits[x]&(1ULL<<y);
}
这个先计算出x在那个数中,然后计算出y在哪一位中,最后通过位运算取到结果。
bool BitState::test(unsigned int pos)
{
if (pos >= bitlen) return false;
int numsize = 8*sizeof(unsigned long long);
int x = pos/numsize, y = pos%numsize;
return bits[x]&(1ULL<<y);
}
和get一样。
void BitState::set()
{
if (bitlen == 0) return;
for (int i = numlen-2; i >= 0; --i)
{
bits[i] = 0;
bits[i] = ~bits[i];
}
unsigned int rest = bitlen-(numlen-1)*sizeof(unsigned long long);
bits[numlen-1] = ((1ULL<<(rest-1))-1)<<1|1;
}
首先对bitlen为0的情况特判,然后将低的numlen-1个数赋值为全1的二进制,最后的最高的rest位进行特殊处理。因为高出rest的位理论上应该是0。操作是先将1向左位移rest-1位(不位移rest位是防止溢出),然后减一,得到rest-1位全为1,然后左移一位,末尾补1。当然可以一位一位直接或1得到结果。
void BitState::set(unsigned int pos)
{
if (pos >= bitlen) return;
int numsize = 8*sizeof(unsigned long long);
int x = pos/numsize, y = pos%numsize;
bits[x] |= 1ULL<<y;
}
这个就是对这一位或一个1。
void BitState::reset()
{
for (int i = 0; i < numlen; ++i)
bits[i] = 0;
}
全部置为0。
void BitState::reset(unsigned int pos)
{
if (pos >= bitlen) return;
int numsize = 8*sizeof(unsigned long long);
int x = pos/numsize, y = pos%numsize;
bits[x] |= 1ULL<<y;
bits[x] ^- 1ULL<<y;
}
这个就是先对该位或1,让他变成1,然后用抑或取反。
void BitState::flip()
{
if (bitlen == 0) return;
for (int i = 0; i < numlen; ++i)
bits[i] = ~bits[i];
unsigned int rest = bitlen-(numlen-1)*sizeof(unsigned long long);
bits[numlen-1] &= ((1ULL<<(rest-1))-1)<<1|1;
}
这个先全部取反,对于高rest位,与上一个rest位全1的,消掉剩余高位。
void flip(unsigned pos)
{
if (pos >= bitlen) return;
if (test(pos)) reset(pos);
else set(pos);
}
通过判断该位是0还是1,来进行设置。
unsigned long long to_ulong()
{
if (bitlen == 0) return 0;
else return bits[0];
}
返回第0个数,高出的全部算作溢出吧。
最后,我们还需要重载一些运算符:
BitState operator&(const BitState &tmp) const;
BitState operator|(const BitState &tmp) const;
BitState operator^(const BitState &tmp) const;
BitState operator~() const;
BitState operator&(const BitState &tmp) const
{
BitState ans(tmp.bitlen>bitlen ? tmp.bitlen : bitlen);
ans.reset();
int minlen = tmp.numlen<numlen ? tmp.numlen : numlen;
for (int i = 0; i < minlen; ++i)
ans.bits[i] = tmp.bits[i]&bits[i];
return ans;
}
直接抑或,直到到达某一个的最大长度。
BitState operator|(const BitState &tmp) const
{
BitState ans(tmp.bitlen>bitlen ? tmp.bitlen : bitlen);
ans.reset();
int minlen = tmp.numlen<numlen ? tmp.numlen : numlen;
for (int i = 0; i < minlen; ++i)
ans.bits[i] = tmp.bits[i]|bits[i];
for (int i = minlen; i < tmp.numlen; ++i)
ans.bits[i] = tmp.bits[i];
for (int i = minlen; i < numlen; ++i)
ans.bits[i] = bits[i];
return ans;
}
这个和与不同的是,高出的部分全部赋值。由于只可能一长一短,所以最后两个for循环只会执行一个。
BitState operator|(const BitState &tmp) const
{
BitState ans(tmp.bitlen>bitlen ? tmp.bitlen : bitlen);
ans.reset();
int minlen = tmp.numlen<numlen ? tmp.numlen : numlen;
for (int i = 0; i < minlen; ++i)
ans.bits[i] = tmp.bits[i]^bits[i];
for (int i = minlen; i < tmp.numlen; ++i)
ans.bits[i] = tmp.bits[i];
for (int i = minlen; i < numlen; ++i)
ans.bits[i] = bits[i];
return ans;
}
这个和或类似。
未完待续。