实现小尝试—C++ STL bitset

关于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;
}

这个和或类似。


未完待续。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值