【 C++ 】bitset位图的模拟实现

目录

1、框架

2、成员函数

        构造函数

        set

        reset

        test

        flip

        count

        size

        none any all

3、bitset源码链接


1、框架

  • bitset能实现对数字的位的操作,同时也能通过类似于数组的下标来访问各个位的数值,以执行相应的操作。模拟bitset就是用一个普通的数组来存储数据以达到模拟的目的。
  • 如果我们以一个整型作为比特位的容器,那么如果要求0~N范围的比特位,就需要有N/32+1 个整型来容纳这些比特位,同理如果以char为容器,则需要N/8+1个char来容纳N个比特位。这里我们用vector数组作为底层容纳比特位的容器,且其存储的数据类型为char
namespace cpp
{
	//N个比特位的位图
	template<size_t N>
	class bitset
	{
	public:
		//构造函数
		bitset();
		//把x映射的位标记成1
		void set(size_t x);
		//把x映射的位标记成0
		void reset(size_t x);
		//判断指定比特位x的状态是否为1
		bool test(size_t x);
		//翻转指定pos
		void flip(size_t x);
		//获取位图中可以容纳位N的个数
		size_t size()
		//统计set中1的位数
		size_t count();
		//判断所有比特位若无置为1,返回true
		bool none();
		//判断位图中是否有位被置为1,若有则返回true
		bool any();
		//全部NUM个bit位被set返回true
		bool all();
	private:
		vector<char> _bits;//位图
	};
}

2、成员函数

构造函数

  • 一个char类型有8个bit位,所以理想状态下N个比特位的位图就需要用到N / 8个字节,但仅限于N是8的整数倍,如果N位10,那么计算下来就会少2个比特位,因此综合考虑,我们给出N / 8 + 1个字节,这样算下来,所需的N个比特位绝对都能访问到,最多可以整除的情况下浪费了8个比特位(1字节)

而构造函数,我们只需要对这所有的比特位(N / 8 + 1)个字节的大小初始化为0即可。

//构造函数
bitset()
{
	//+1保证足够比特位,最多浪费8个比特位
	_bits.resize(N / 8 + 1, 0);
}

set

set的作用是把x映射的位置标记成1,实现规则如下:

  1. 通过x / 8计算x在第i个char类型
  2. 通过x % 8计算x在char第j个比特位
  3. 利用按位或 | 把第i个char中的第j个比特位置为1

//把x映射的位标记成1
void set(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//利用按位或|把第j位标记成1
	_bits[i] |= (1 << j);
}

 调试窗口如下:


reset

reset的作用是把把x映射的位标记成0,实现规则如下:

  1. 通过x / 8计算x在第i个char类型
  2. 通过x % 8计算x在char第j个比特位
  3. 将1左移 j 位再整体反转后与第 i 个char类型进行与运算即可。

//把x映射的位标记成0
void reset(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位再整体反转后与第 i 个char进行与运算
	_bits[i] &= (~(1 << j));
}

test

test的作用是判断指定比特位x的状态是否为1,实现规则如下:

  1. 通过x / 8计算x在第i个char类型
  2. 通过x % 8计算x在char第j个比特位
  3. 将1左移 j 位后与第 i 个char类型进行与运算得出结果
  4. 若结果非0,则该位被设置,否则该位未被设置

//判断指定比特位x的状态是否为1
bool test(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位后与第 i 个char类型进行与运算得出结果
	return _bits[i] & (1 << j);
}

flip

flip的作用是用于翻转指定位,若指定位为0,翻转后为1,若指定位为1,反转后为0,实现规则如下:

  1. 通过x / 8计算x在第i个char类型
  2. 通过x % 8计算x在char第j个比特位
  3. 将1左移 j 位后与第 i 个char进行按位异或运算^即可。

//翻转指定位x
void flip(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位后与第 i 个char进行按位异或运算^即可。
	_bits[i] ^= (1 << j);
}

count

count的作用是统计位图中被设计为1的个数,实现规则如下:

  1. n = n & (n-1) => 消去n的二进制数中最右边的1
  2. n不为零继续执行第一步
  3. 执行了几次说明n中有多少个1

//统计set中1的个数
size_t count()
{
	size_t count = 0;
	for (auto e : _bits)
	{
		int n = e;
		while (n)
		{
			n = n & (n - 1);
			count++;
		}
	}
	return count;
}

size

size的作用是获取位图中可以容纳位N的个数

//获取位图中可以容纳位N的个数
size_t size()
{
	return N;
}

none any all

1、none

  • none的作用是遍历每一个char,如果全为0,则none返回true
//判断所有比特位若无置为1,返回true
bool none()
{
	//遍历每个char
	for (auto e : _bits)
	{
		if (e != 0)//说明有位被置为1,返回false
			return false;
	}
	return true;//说明全为0,返回true
}

2、any

  • any的作用判断位图中是否有位被置为1,若有则返回true,这其实和none的作用刚好相反,因此我们直接复用none即可。
//判断位图中是否有位被置为1,若有则返回true
bool any()
{
	return !none();
}

3、all

all的作用是判断位图中是否所有的位都被置为1,注意这里的特殊性,先前开辟空间时我们为了避免出现N/8不能整除的情况,特地在resize时多开了一个char类型(8比特)的空间,这8比特里面只有前N%8个比特位才是有效的剩下的都是多开的空间),因此all函数需要分情况讨论。

  1. 先检查前n-1个char的二进制是否为全1。
  2. 再检查最后一个char的前N%8个比特位是否为全1。

//全部NUM个bit位被set返回true
bool all()
{
	size_t size = _bits.size();
	//先检查前N-1个char
	for (size_t i = 0; i < size - 1; i++)
	{
		if (~_bits[i] != 0)//取反应该为0,否则取反之前不全为1,返回false
			return false;
	}
	//再检查最后一个char的前 N%8 个位
	for (size_t j = 0; j < N % 8; j++)
	{
		if ((_bits[size - 1] & (1 << j)) == 0)//和test的原理一致
			return false;
	}
	return true;
}

3、bitset源码链接

位图的模拟实现

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
C++的STL中实现由一个bitset类模板,其用法如下: std::bitset bs; 也就是说,这个bs只能支持64以内的存储和操作;bs一旦定义就不能动态增长了。本资源附件中实现了一个动态Bitset,和标准bitset兼容。 /** @defgroup Bitset Bitset集类 * @{ */ //根据std::bitset改写,函数意义和std::bitset保持一致 class CORE_API Bitset: public Serializable { typedef typename uint32_t _Ty; static const int _Bitsperword = (CHAR_BIT * sizeof(_Ty)); _Ty * _Array; //最低放在[0]置,每的默认值为0 int _Bits;//最大有效的Bit个数 private: int calculateWords()const; void tidy(_Ty _Wordval = 0); void trim(); _Ty getWord(size_t _Wpos)const; public: //默认构造 Bitset(); //传入最大的数,每默认是0 Bitset(int nBits); virtual ~Bitset(); //直接整数转化成二进制,赋值给Bitset,最高低放在[0]Bitset(unsigned long long _Val); //拷贝构造函数 Bitset(const Bitset & b); Bitset(const char * str); Bitset(const std::string & str, size_t _Pos, size_t _Count); public: size_t size()const; //返回设置为1的数 size_t count() const; bool subscript(size_t _Pos) const; bool get(size_t pos) const; //设置指定置为0或1,true表示1,false表示0,如果pos大于数组长度,则自动扩展 void set(size_t _Pos, bool _Val = true); //将数组转换成整数,最低放在[0]置 //例如数组中存放的1011,则返回13,而不是返回11 unsigned long long to_ullong() const; bool test(size_t _Pos) const; bool any() const; bool none() const; bool all() const; std::string to_string() const; public: //直接整数转化成二进制,赋值给Bitset,最高放在[0]Bitset& operator = (const Bitset& b); //直接整数转化成二进制,赋值给Bitset,最高放在[0]Bitset& operator = (unsigned long long ull); //返回指定置的值,如果pos大于数组长度,自动拓展 bool operator [] (const size_t pos); //测试两个Bitset是否相等 bool operator == (const Bitset & b); bool operator != (const Bitset & b); Bitset operator<>(size_t _Pos) const; bool operator > (const Bitset & c)const; bool operator < (const Bitset & c)const; Bitset& operator &=(const Bitset& _Right); Bitset& operator|=(const Bitset& _Right); Bitset& operator^=(const Bitset& _Right); Bitset& operator<>=(size_t _Pos); public: Bitset& flip(size_t _Pos); Bitset& flip(); //将高与低互相,如数组存放的是1011,则本函数执行后为1101 Bitset& reverse(); //返回左边n,构成新的Bitset Bitset left(size_t n) const; //返回右边n,构成新的Bitset Bitset right(size_t n) const; //判断b包含的数组是否是本类的数组的自串,如果是返回开始置 size_t find (const Bitset & b) const; size_t find(unsigned long long & b) const; size_t find(const char * b) const; size_t find(const std::string & b) const; //判断本类的数组是否是b的前缀 bool is_prefix(unsigned long long & b) const; bool is_prefix(const char * b) const; bool is_prefix(const std::string & b) const; bool is_prefix(const Bitset & b) const; void clear(); void resize(size_t newSize); void reset(const unsigned char * flags, size_t s); void reset(unsigned long long _Val); void reset(const char * _Str); void reset(const std::string & _Str, size_t _Pos, size_t _Count); //左移动n,返回新的Bitset //extendBits=false "1101" 左移动2 "0100"; //extendBits=true "1101" 左移动2 "110100"; Bitset leftShift(size_t n,bool extendBits=false)const; //右移动n,返回新的Bitset //extendBits=false "1101" 右移动2 "0011"; //extendBits=true "1101" 右移动2 "001101"; Bitset rightShift(size_t n, bool extendBits = false) const; public: virtual uint32_t getByteArraySize(); // returns the size of the required byte array. virtual void loadFromByteArray(const unsigned char * data); // load this object using the byte array. virtual void storeToByteArray(unsigned char ** data, uint32_t& length) ; // store this object in the byte array. };
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三分苦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值