实现小尝试—C++ STL bitset

来源:互联网 发布:java ssh linux 编辑:程序博客网 时间:2024/05/30 05:40

关于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的BitStateBitState(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();//把所有二进制位都置为1void set(unsigned int pos);//在pos处的二进制位置为1void reset();//把所有二进制位都置为0void reset(unsigned int pos);//在pos处的二进制位置为0void 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 0
原创粉丝点击