数据结构位图以及移位运算

188 阅读2分钟

这是我参与更文挑战的第11天,活动详情查看: 更文挑战

1. 定义

位图,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况,通常用来判断一个数据是否存在。

2. 位图应用

问题1:有20亿个无符号的整型数据,现在给定一个目标数字,判断这个数字是否在这20亿数据中。

解决思路

将这些数字排序好,再二分查找或者采用归并排序。

但问题并不在于查找这个数字的效率,而是这20亿个整形数据存储问题。一个int,4个字节,20亿int就需要差不多8G的内存。就算采用归并排序,也需要考虑磁盘文件多次读写的问题。

采用位图法,用一个bit位来表示一个数字。

截屏2021-05-15 上午10.26.14.png

这样,现在使用位图就存储了32个数字。

3. 设计位图

class BitMap
{
public:
	BitMap(size_t range)
	{
		_bitTable.resize((range >> 5) + 1);
	}

	//标识一个数字在位图中的位置
	void SetBit(size_t x)
	{
		size_t index = x >> 5;
		size_t num = x % 32;

		_bitTable[index] |= (1 << num);
	}

	//取消数字在位图当中的标识.
	void RemoveBit(size_t x)
	{
		size_t index = x >> 5;
		size_t num = x % 32;

		_bitTable[index] &= ~(1 << num);
	}


	bool TestBit(size_t x)
	{
		size_t index = x >> 5;
		size_t num = x % 32;

		return _bitTable[index] & (1 << num);
	}

private:
	vector<int> _bitTable;
};

截屏2021-05-15 下午2.58.37.png

4. << 左移

39 << 2

0010 0111向左移动2位,右边空出来的位置用0补满,变为

1001 1100(156)相当于乘以了2x2=4倍

5. >> 带符号右移

(1)正数

39>>2

0010 0111,向右移动2位,将低位的2个数字移出,左边空出来的地方,正数就补0.负数补1,变为

0000 1001(9),相当于除以2x2=4倍(取整)

(2)负数

-39>>2

-39原码:1010 0111

-39的补码:保证符号位不变,其余位置取反加1

​ 1101 1000

​ 1101 1001

右移2位,高位补1

​ 1111 0110

补码形式的移位完成后,结果不是移位后的结果,要根据补码写出原码才是我们所求的结果。其方法如下:

保留符号位,然后按位取反,然后加1,记得所求数的原码:

​ 1000 1001

​ 1000 1010

结果为 -10