【转】编程珠玑之第一题:如何使用位逻辑运算(如与、或、移位)来实现位向量?

编程珠玑开篇的一道题目是这样的:

如何使用位逻辑运算(如与、或、移位)来实现位向量?

 

一.何为位向量?

在许多情况下(如对象为满足或不满足某条性质的情况),用一个二进制位就足够表示一个对象了。但是,不能用一个变量名直接表示一个位(不存在单独为一位的数据类型)。于是,就考虑将多个位组成一个基本数据类型,通过对这个基本数据类型的操作,达到使用位的方法。同时,为了方便,把由位组成的基本数据类型组成数组,这样,就可以对一定范围的位数据集合进行操作。我们把这种形式的数据结构称为位向量。

 

接下来,再考虑一点,对位向量各位的操作我们不能通过名称去访问,只能通过位的位置去操作,即我们要操作第几位的数据。在我们看来位是由0——n连续的,实际上因为我们是用基本数据类型的数组进行存储的,因为,这些位是分割在不同的数组元素当中,处在不同数组元素的不同位置当中。假设我们以int类型做为基本数据类型,则一个int类型(c++)中,可以存储32个位。则对于特定的一个位(位置为:pos),我们首先考虑它处在哪个int数组元素当中(pos/32,即知道处在哪个数组元素当中),然后考虑该位处在该数组元素的哪个位置(即pos mod 32)。

 

对位向量的操作主要有三个:对特定位置1,对特定位清0,判断特定位。

 

二.实现代码

有了以上知识,我们看下编程珠玑中对该问题的实现代码。

#define BITSPERWORD 32  //使用的基本数据类型为32位,int类型
#define SHIFT 5   //与确定位处于哪个数组元素有关
#define MASK 0x1F    //与确定位处于数组元素哪一位有关
#define N 10000000  //位长度
int a[1+N/BITSPERWORD];  //数组长度

//将对应位置1
void set(int i) {
a[i>>SHIFT] |=(1<<(i & MASK));
}

//将对应位置0
void clr(int i){
a[i>>SHIFT] &=~(1<<(i & MASK));
}

//判断对应位
//void test(int i){
//此函数应该返回int,返回非0说明i存在,否则不存在。【转者注】
int test(int i){
return a[i>>SHIFT] & (1<<(i & MASK));
}

下面来分析下以上代码。

1)确定数组元素,即i/32,对于2的倍数的整除,我们可以使用位移运算,因为32=2^5,所以i/32=i>>5,故a[i>>SHIFT]确定了数组元素。

2)确定数组元素后,我们要确定位的相对位置,即为i mod 32,观察,当对i执行右移(5位)运算时,把低5位消除了,而这低5位正是余数,因此可以通过i&0x1F,获得低5位的值,进而得到位的相对位置,故如i & MASK。

3)确定位置后,我们进一步转成对应的位位置掩码,即1<<(i&MASK)。

通过以上三步,我们完成了定位的工作。

 

分析三条语句:

1)set():因为是置1操作,所以只需要把原数组元素与位位置掩码进行或操作即可;

2)clr():因为是置0操作,所以先把位位置掩码取非,使特定位位0,再与原数组元素进行与操作即可。

3)test():判断特定位,只需要原始数组元素与位位置掩码进行与操作,即可判断当前位是否为1。

转自:https://www.cnblogs.com/lsr-flying/p/4524515.html

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值