位逻辑运算:打造高性能位图

开篇

本文是使用位逻辑(如与、或、移位)来实现位向量,对应的是《编程珠玑》第1章的课后习题2。本文中主体代码在课后习题答案中均有提及,但介于没有详细的注释,以及用于测试main函数,所以很多小白刚看到代码的时候,可能会有点懵,所以本文提供了对代码详细的解释,这些解释均被写在了代码注释里,同时,还提供了测试用的代码。

关键词:《编程珠玑》、位逻辑实现位向量、第1章课后习题2

分析

在C语言中,通常使用整数数组来模拟位向量,使用位操作来设置、查询、清除单个位。

设置位:将目标位设置为1(设置前为0);

清除位:将目标位设置为0(设置前为1);

查询位:查询校验目标位是否为1或0.

具体实现逻辑在代码中有及其详细的注释,此处不再赘述。

代码实现

#include <stdio.h>
#include <string.h>

//  定义每个数组元素可以表示的位数 
#define BITSPERWOD 32
// 用于快速计算除以32的结果,2的5次方=32
#define SHIFT 5  
 // 用于 获取除以32的余数,0x1F是十六制,等于二进制的11111,即32-1,用于位操作中取余 
#define MASK 0x1F
// 定义位图可以表示的最大的范围,此处是1000万 
#define N 10000000

// 定义一个整型数组,用于容纳N个位 
int a[1 + N/BITSPERWOD];

/**
*	i>>SHIFT等同于除以32,用于计算i位于数组的哪个元素
*	1<<(i & MASK)计算i在该元素的哪一位
*	|= 用于将那一位设置为1
*
*	举例: i = 63, 此时63/32 = 1,即62处于a[1]的位置 (即第2个元素) 
*	63%32=31,即在第32为设置为1,此处i & MASK就相当于取余的操作,1<<(i & MASK)中左移的动作就是把第32位设置为了1
*	a[i>>SHIFT] |= (1<<(i & MASK)); 这个操作总的来说,就是把a[1]的第32位赋值为1
*/ 
void set(int i) {
	a[i>>SHIFT] |= (1<<(i & MASK));
}

/**
* 接着上面说,此处如果i = 63
* 此处 1<<(i & MASK) 生成了一个第32位为1,其余31位为0的掩码,
* 然后使用~取反,生成一个在32位为0,其余位为1的掩码,
* 随后,和 a[i>>SHIFT] 进行按位与操作(此时, a[i>>SHIFT]为第32位为1,其余位为0的掩码), 
* 操作后,a[i>>SHIFT]就变成了全部位为0的掩码,达到了清除位的目的 
*/ 
void clr(int i) {
	a[i>>SHIFT] &= ~(1<<(i & MASK));
}

/**
此处作用是检查目标位是否被设置为了1
还是以上面的63为例,首先,a[i>>SHIFT] 确定了是a[1],如果被设置了,则此时它为第32位1,其余位为0的掩码,
 1<<(i & MASK)使用这句代码,将第32位设置为了1,随后与 a[1]的掩码进行按位与操作,此时因为第32位为1,所以结果不是0
 于是就返回true 
*/
int test(int i) {
	return (a[i>>SHIFT] & (1<<(i & MASK))) != 0;
}

int main() {
	// 将所有位初始化为0 
	memset(a, 0, sizeof(a));
	
	// 设置位
	set(100);
	set(100000);
	set(1000000);
	
	// 测试
	printf("Test bit 100: %d\n", test(100));
	printf("Test bit 100000: %d\n", test(100000));
	printf("Test bit 1000000:%d\n", test(1000000));
	
	// 清除其中一个位
	clr(100000);
	
	// 测试被清除的位
	printf("Test cleared bit 100000: %d\n", test(100000));
	
	// 测试一个未被设置的位
	printf("Test unset bit 10000: %d\n", test(10000));
	
	return 0;
}

本文添加的注释,是为了能让小白(像我一样的小白哈哈)也能很很清楚的明白代码中的逻辑,但本人毕竟能力有限,若有谬误的地方,还请指正,以防止我的注释误导别人。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值