位图 可以对数据进行压缩存储和快速排序,第一、要求集合中所有元素不重复(如果,要使用位图存储含重复元素的集合,需要设计更加复杂的位图结构表);第二,要求存储数据集合限制在较小的范围,如果有个别数据非常大,导致存储位图的集合也非常大,不一定节省空间;第三,对于 结合中的每条数据项,只包含单一的一个整数。
本文主要对编程珠玑第一章,使用位逻辑运算(与、或、移位)来实现位向量所给答案进行解释。
#define BITSPERWORD 32 //要存储元素所要占的位数
#define SHIFT 5//除数,十进制数在存储位图所要在的数
#define MASK 0x1F// 十六进制0x1F对应整数为31,对应二进制的5个1
#define N 100000000//待存储集合中最大数
int a[1+N/BITSPERWORD];//位图向量
void set(int i){ a[i>>SHIFT] |= (1<<(i &MASK));}//将正整数i存储在位图中
void clr(int i){ a[i>>SHIFT] &= ~(1<<(i & MASK));}//删除该数
void test(int i){ return a[i>>SHIFT] & 1<<(i & MASK));}//判断该数是否存在
1.set(int i)元素存储过程
void set(int i){ a[i>>SHIFT] |= (1<<(i &MASK));}
i<<(i&&MASK);等价于对i使用%取余数,确定要将当前int中32位中哪一位设置为1,也即i在该int二进制位图中存储的位置。
例如假设i = 34,使用%运算得到i%34=2, 应该存储在当前int的第二位。使用位运算确定存储位置的过程如下。
因为在0000 0000 0000 0000 0000 0000 0000 0010二进制中,只有1个1,所以与原int中所对应的二进制进行|或操作,只会将右边第二位设置为1。
Note: 在C++中一个int型数据占4个字节32位,最多可以存储2^5=32个数,所以掩码MASK取31,对应二进制为11111。掩码作用是使用一串二进制代码对目标字段进行位与运算,使用掩码中的0,屏蔽目标字段中的1。
2. void clr(int i)元素删除过程
1<<(i &MASK)也是确定i在当前int位图中存储位置,~表示将该位置设置为0,其余位置设置为1,再与原int中所对应的二进制位进行&与操作,只会将原位图中i存放位置设置为0。
3. void test(int i)判断元素是否存在
1<<(i &MASK)也是确定i在当前int位图中存储位置,再与原int中所对应的二进制位进行&与操作,只会将原位图中i存放位置设置为1,怎返回大于零的数,表示存在,原位图中对应位置为0,与完结果为零,表示该元素不存在。
Reference
[1]https://blog.csdn.net/eternal_tree/article/details/78699530.
[2]http://www.voidcn.com/article/p-fawcjwap-ep.html
[3]https://blog.csdn.net/qq_44443986/article/details/117359908