zoukankan      html  css  js  c++  java
  • [编程珠玑]如何使用位逻辑来实现位向量

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

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

    一.何为位向量?

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

    接下来,再考虑一点,对位向量各位的操作我们不能通过名称去访问,只能通过位的位置去操作,即我们要操作第几位的数据。在我们看来位是由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。

  • 相关阅读:
    RTP 协议
    RTSP 协议分析 (一)
    RTSP协议分析(二)
    CreateRemoteThread简单应用
    函数开始处的MOV EDI, EDI的作用
    eax,ebx,ecx,edx,esi,edi,ebp,esp寄存器的作用
    C++函数调用原理理解
    WinDBG常用断点命令
    利用bu命令下延迟断点
    Windbg 查看SSDT表
  • 原文地址:https://www.cnblogs.com/lsr-flying/p/4524515.html
Copyright © 2011-2022 走看看