bitset类的实现

问题:实现一个bitmap类(为避免与stl中的bitset重名),用于位图。

测试用例:

BitMap bm(20);
bm[3] = 1;
bm[5] = 0;
bool b = bm[12];

其本质上是用内存中的一位来表示某种意义。

难点在于,使用int或者unsigned int类型保存多位bool变量(也就是0或者1)后,怎么重载下标操作符。

如果不使用下标而是使用函数,例如bm.set(3);或者bm.reset(12);一般是很简单的,只需要重载[]即可。

使用下标操作符的难点在于:c++不支持bit引用。

但是就是要求使用下标操作(项目中你可以这么做,但是面试的时候,面试官就要求使用下标),how?


这里需要使用一种设计模式:代理模式。


先看代码:

#include <iostream>
#include <cassert>

/****************************************
 * 20130506 微软实习生面试时悲剧的题目
 * 当时根本没想到代理模式
 * 至于代理模式,以前也仅仅是听说过而已
*****************************************/
using namespace std;

/*****************************************
 * BitMap bm(20);
 * bm[9]=1;//set bit
 * bm[1]=0;//clear
*****************************************/
class BitMap
{
    typedef unsigned int UINT;

public:
    BitMap(size_t bitlen=0):m_len(bitlen)
    {
        nUINT=m_len/DATALEN+(m_len%DATALEN==0?0:1);
        m_data = new UINT[nUINT]();
    }
    ~BitMap()
    {
        delete[] m_data;
    }
    void set(size_t index)
    {
        assert(0<=index&&index<m_len);
        *(m_data+index/DATALEN) = *(m_data+index/DATALEN) | (1<<(index%DATALEN));
    }
    void reset(size_t index)
    {
        assert(0<=index&&index<m_len);
        *(m_data+index/DATALEN) = *(m_data+index/DATALEN)&(~(1<<(index%DATALEN)));
    }
    bool test(size_t index)const
    {
        assert(0<=index&&index<m_len);
        return *(m_data+index/DATALEN) & ( 1<<(index%DATALEN));
    }
    void flip()///~all bits
    {
        for(unsigned int i=0;i<nUINT;i++)
            *(m_data+i) ^= (~0);
    }

/****  代理模式 ****/
    class proxy
    {
    public:
        proxy(BitMap &refbm, size_t index):
            rbm(refbm),index(index)
            {
            }

        proxy & operator= (bool val)
        {
            if(val)
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }

        proxy & operator= (const proxy &rhs)
        {
            if(rhs.rbm.test(rhs.index))
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }
        operator bool()
        {
            return rbm.test(index);
        }

    private:
        BitMap &rbm;
        size_t index;

    };

    proxy operator[](size_t index)
    {
        return proxy(*this,index);
    }

    const proxy operator[] (size_t index) const
    {
        return proxy(const_cast<BitMap &>(*this), index);
    }

private:
    UINT *m_data;///实际保存bit的存储区
    size_t m_len;///位的长度,支持可变长度的位,bitset不支持。
    size_t nUINT;///实际使用的UINT的个数

    const static int DATALEN = 32;///每个UINT可以保存的bit个数

    friend ostream& operator<< (ostream& out,BitMap &bm);///用于输出,便于调试
};

ostream& operator<< (ostream& out,BitMap &bm)
{
    for(int i=bm.m_len-1;i>=0;i--)
        out<<bm.test(i);
    return out;
}


void testcase()
{
    BitMap b(40);
    cout<<b<<endl;;
    b.set(2);
    b.set(3);
    cout<<b<<endl;
    b.reset(2);
    cout<<b<<endl;

    b.flip();
    cout<<b<<endl;

    cout<<"ttt"<<endl;
    b[1]=0;
    cout<<b<<endl;
    b[1]=1;
    cout<<b[0]<<endl;
}


int main()
{
    testcase();
    return 0;
}


前面的set、reset、flip等函数的实现就是位运算,不需要多说。

关键在这里:

b[1]=0;

首先,b[1]将调用下标操作符,

    proxy operator[](size_t index)
    {
        return proxy(*this,index);
    }

这里返回的是一个proxy对象。proxy怎么构造的呢?2个参数:BitMap引用和index。这2个参数足以定位到一个具体的bit!也就是说,一个proxy对象对应一个bit。

然后将一个bool值赋值给这个对象,将调用proxy的赋值操作符:

        proxy & operator= (bool val)
        {
            if(val)
                rbm.set(index);
            else
                rbm.reset(index);
            return *this;
        }

这样就修改了BitMap对象的某一位。


还有一处需要说明的地方:

        operator bool()
        {
            return rbm.test(index);
        }

这里定义了类型转换,可以将一个proxy对象转换为一个bool变量。读取的时候,例如bool  b=bm[2];将调用这个函数。


这样,对外看来,使用下标访问的就是BitMap对象中的某一位,可以进行读或者写的操作。

很巧妙的设计。


/*********************************************分****割****线***************************************************************/

关于代理模式:

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

直接看这些定义,感觉理解起来很不方便。

有了这个例子,体会得深的多了。

有人说:

设计模式就是编程思想,很多新手觉得好像都看懂了但不会用,因为编程思想还没达到那个层次!

这个要靠点点滴滴的积累,当你积累了10W行有效代码,再回过头去看设计模式,自然会有豁然开朗的感觉

框架要用,“不要重复造轮子”,但是要关注框架的实现原理


深有体会!



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值