位图

位图

今天介绍的数据结构叫做位图,在介绍之前,首先看一道“简单”的题目,

给出40亿个数据,给出一个四位数字,判断该数字是否在这四十亿个数字中。

这道题难点并不在思路,之前我们使用的链表红黑树等算法思想都能解决这个问题,但是有一点无法解决,40亿个数太太太太大了,换算成int类型大约16G大小的空间,计算机的内存可不一定够,聪明的读者可能想到了char类型来出错结构,从16G的需求降低到4G的需求,但是仍然不够,继续拆分,1个byte可以拆成8bit,假如我们用每一个bit储存数字的存在状态,只需要500M的内存就够用了。
位图就是基于这种思想实现的。

位图模型

下面是比特位映射数字的模型
在这里插入图片描述
1个int可以拆成32个bit,假如我们使用32个bit来映射数据,节省了32倍的空间,具体的实现,请往下看

设计位图

为了方便,我们使用vector来替我们管理空间,我们只要做到数字的插入和删除就足够了

位图的构造函数


class BitMap
{
public:
	BitMap(const int& size = 0)
	{
		_bit.resize((size >> 5) + 1);
		/*将传入的数字除32,+1是因为假如不是整除,要给余数留一个位置*/
	}
private:
	vector<int> _bit;
};

位图的插入

	void insert(const int& size)
	{
		int _bitsize = size % 32;//第几个比特位
		int index = size / 32;

		_bit[index] |= (1 << _bitsize);
	}

这里说明一下,int _bitsize = size % 32int index = size / 32的功能,假设我们要插入两个数字5和32,第一步找到对应字节所在的int,第二步在int中找到,bit位的位置。

在这里插入图片描述
**_bit[index] |= (1 << _bitsize)**用位运算将对应bit置为1.

位图的删除

和位图的插入思想相同

	void erase(const int& size)
	{
		int _bitsize = size % 32;
		int index = size / 32;

		_bit[index] &= ~(1 << _bitsize);
	}

**_bit[index] &= ~(1 << _bitsize)**将对应位置为0.

位图的查找

	bool findbit(const int& size)
	{
		int _bitsize = size % 32;
		int index = size / 32;
		return _bit[index] & (1 << _bitsize);
	}

**_bit[index] & (1 << _bitsize)**判断对应bit是否为1.

位图的完整代码

完成了上面的函数的实现,已经将位图实现的七七八八了,下面是位图的完整代码可供参考。

namespace bit
{
class BitMap
{
public:
	BitMap(const int& size = 0)
	{
		_bit.resize((size >> 5) + 1);
	}

	void insert(const int& size)
	{
		int _bitsize = size % 32;//第几个比特位
		int index = size / 32;

		_bit[index] |= (1 << _bitsize);
	}

	void erase(const int& size)
	{
		int _bitsize = size % 32;
		int index = size / 32;

		_bit[index] &= ~(1 << _bitsize);
	}
	bool findbit(const int& size)
	{
		int _bitsize = size % 32;
		int index = size / 32;
		return _bit[index] & (1 << _bitsize);
	}
private:
	vector<int> _bit;
};
}

拓展

现在将问题修改为查找该数字在40亿数据中是否出现两次,需要将位图进行修改,用2个比特位来储存数字的出现情况。
N位位图的实现如下

class BitMap
{
public:
	BitMap(const int& size = 0)
	{
		_bit.resize((size >> 4) + 1);
	}

	void insert(const int& size)
	{
		int _bitsize = size % 16;//计算第几组比特位
		int index = size / 16;
		bool first = _bit[index] &(1<<_bitsize*2);
		bool second = _bit[index] & (1 << _bitsize * 2+1);
		if (!(first && second))
		{
			_bit[index] += (1 << _bitsize * 2);
		}
	}

	void erase(const int& size)
	{
		int _bitsize = size % 16;
		int index = size / 16;
		bool first = _bit[index] & (1 << _bitsize * 2);
		bool second = _bit[index] & (1 << _bitsize * 2 + 1);
		if (!(first && second))
		{
			_bit[index] -= (1 << _bitsize * 2);
		}

	}

	bool find(const int& size)
	{
		int _bitsize = size % 16;
		int index = size / 16;
		return _bit[index] & (1 << _bitsize*2+1);
	}

private:
	vector<int> _bit;
};

总结

位图的思想和哈希表的思想类似,但是比哈希表实现简单
优点

  • 实现简单
  • 缺点
  • 可读性差,
  • 位图对有符号类型数据的存储,需要 2 位来表示一个有符号元素。这会让位图能存储的元素个数,元素值大小上限减半。 比如 8K 字节内存空间存储 short 类型数据只能存 8K*4=32K 个,元素值大小范围为 -32K~32K 。

我们实现的位图只能实现数字的映射,对于string字符串等数据结构的映射就显得无从下手了,不过已经有大佬提前考虑到了这种情况,用一种数据结构解决了这个问题,这个数据结构叫做布隆过滤器,具体的情况请看下一篇博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值