[编程珠玑]如何使用位逻辑来实现位向量

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

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

一.何为位向量?

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

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

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

二.实现代码

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

 1 #define BITSPERWORD 32  //使用的基本数据类型为32位,int类型
 2 #define SHIFT 5   //与确定位处于哪个数组元素有关
 3 #define MASK 0x1F    //与确定位处于数组元素哪一位有关
 4 #define N 10000000  //位长度
 5 int a[1+N/BITSPERWORD];  //数组长度
 6
 7 //将对应位置1
 8 void set(int i) {
 9 a[i>>SHIFT] |=(1<<(i & MASK));
10 }
11
12 //将对应位置0
13 void clr(int i){
14 a[i>>SHIFT] &=~(1<<(i & MASK));
15 }
16
17 //判断对应位
18 void test(int i){
19 return a[i>>SHIFT] & (1<<(i & MASK));
20 }

下面来分析下以上代码。

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。

时间: 2024-10-25 02:50:49

[编程珠玑]如何使用位逻辑来实现位向量的相关文章

&lt;转载&gt;编程珠玑-位排序(bitsort)

转载:http://www.cnblogs.com/shuaiwhu/archive/2011/05/29/2065039.html  维护版权 在<编程珠玑>一书上,有一题是将一堆不重复的数进行排序,这些数的值大小位于[0, 10000000).然后作者在书后给出的答案确实很精辟,利用位排序将这个问题轻而易举的解决了. 首先弄懂i>>SHIFT相当于i/32,i&MASK相当于i%32. 题目中说了 Replace above 2 lines with below 3fo

计算机科学箴言集 -- &lt;编程珠玑续&gt;

6 计算机科学箴言集 程序员常常要转换时间单位; e.g. 一个程序每秒能处理100条记录, 那处理100w条需要多久? 用除法算, 就知道要花100000秒, 按每小时3600秒算, 差不多3小时; 而一年有多少秒? 如果我直接告诉你 3.155x10^7秒, 你可能很快就忘了; 事实上, 要记住这个很简单, 在误差不超过0.5%的约束下: π秒就是一个纳世纪    --Tom Duff 贝尔实验室    [nano 1×10?9 ] 所以, 如果程序要运行10^7秒, 就要准备等上4个月;

编程珠玑番外篇

1.Plan 9 的八卦 在 Windows 下喜欢用 FTP 的同学抱怨 Linux 下面没有如 LeapFTP 那样的方便的工具. 在苹果下面用惯了 Cyberduck 的同学可能也会抱怨 Linux 下面使用 FTP 和 SFTP 是一件麻烦的事情. 其实一点都不麻烦, 因为在 LINUX 系统上压根就不需要用 FTP. 为什么呢? 因为一行简单的配置之后, 你就可以像使用本机文件一样使用远程的任何文件. 无论是想编辑, 查看还是删除重命名, 都和本机文件一样的用. 这么神奇的功能到底如何

《编程珠玑》笔记:数组循环左移

问题描述:数组元素循环左移,将包含 num_elem 个元素的一维数组 arr[num_elem] 循环左移 rot_dist 位.能否仅使用数十个额外字节的存储空间,在正比于num_elem的时间内完成数组的旋转? 一:Bentley's Juggling Alogrithm 移动变量 arr[0] 到临时变量 tmp,移动 arr[rot_dist] 到 arr[0],arr[2rot_dist] 到 arr[rot_dist],依此类推,直到返回到取 arr[0] 中的元素,此时改为从 t

一维向量旋转算法 编程珠玑 第二章

看了编程珠玑第二章,这里面讲了三道题目,这里说一下第二题,一维向量旋转算法. 题目:将一个n元一维向量(例数组)向左旋转i个位置. 解决方法:书上讲解了5种方法,自己只想起来2种最简单方法(下面讲的前两种). 1.原始方法. 从左向右依次移动一位,对所有数据平移:这样循环i次,算法最坏时间复杂度达n^2.耗时不推荐. 2.空间换时间. 顾名思义,申请一个i长度的空间,把前i半部分放到申请空间中,再把后面的所有数据向左移动i个位置,最后把申请的空间中的数据放到后半部分.浪费空间,不推荐. 3.杂技

《编程珠玑》第一章

一.题目: 如何在1MB的空间里面对一千万个整数进行排序?并且每个数都小于1千万.实际上这个需要1.25MB的内存空间(这里所说的空间是考虑用位图表示法时,每一位代表一个数,则1千万/(1024*1024*8) 约为1.25MB  ). 1MB总共有838,8608个可用位.所以估计也可以在1MB左右的空间里面进行排序了. 分析: 1)基于磁盘的归并排序(耗时间) 2)每个号码采用32位整数存储的话,1MB大约可以存储250 000 个号码,需要读取文件40趟才能把全部整数排序.(耗时间) 3)

编程珠玑第二章

编程珠玑第二章 A题 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中一32位整数. 1.在文件中至少存在这样一个数? 2.如果有足够的内存,如何处理? 3.如果内存不足,仅可以用文件来进行处理,如何处理? 答案: 1.32位整数,包括-2146473648~~2146473647,约42亿个整数,而文件中只有40亿个,必然有整数少了. 2.如果采用位数思想来存放,则32位整数最多需要占用43亿个位.约512MB的内存空间. 可以采用前一章的位处理方法.然后判断每个in

编程珠玑(一)

这是学习编程珠玑的第一章~ 问题描述: 输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7,且所有正整数都不重复. 输出:这n个正整数升序排列输出列表 约束:最多1MB的内存空间,有充足的磁盘存储空间可用,运行时间最多几分钟,运行时间为10秒则不需要优化了. 一.多通道实现: 题目中的限制为所有正整数都不重复.这代表: 输入文件中范围在1~249 999的正整数至多只有250 000个,至多占内存为1MB. 输入文件中范围在250 000~499 999的正整数至多只有250

读书笔记--编程珠玑II

学化学的应该都知道chemdraw,这是一款专门绘制化学结构的软件,什么苯环.双键各种word难以搞定的分子式,你可以轻松的用chemdraw完成,可以称得上化学工作者居家旅行必备的良药.其实早在1987年的时候,贝尔实验室的大牛Brian Kernighan(就是K&R教你写C语言中的K)和人一起设计了Chem语言,到现在还能用,似乎在书籍排版上比chemdraw的效果更好.说了这么多,咱不是给Chem做广告,而是为了引出它的另一位创作人Jon Bebtley,也是本文即将谈到的<编程珠玑