如何使用位逻辑运算来实现位向量的理解

这是一道很是基础的题目,考察对位运算的理解,好看题目只以为好眼熟,而后(手贱)瞟了一眼答案,第一遍没看明白答案的内容,就上网查了一下,网上的人要么就是一笔带过(大概是以为太简单),要么就是误人子弟。html

解决题目以前应该先搞清楚题目是干吗的:ios

位向量顾名思义就是用位来存储一个数,文中说存储N=10000000个数,每一位表明一个数。数组

咱们能够定义一个int类型的数组int a[N],那么若是a[9]的值为1,则代表文件中存在一个值为9。函数

这样的话,咱们就能够用一个数组来表示这么多数。咱们又知道,一个int型的数有4个字节,也就是32位,那么咱们能够用N/32个int型数来表示这N个数:测试

a[0]表示第1~32个数(0~31)spa

a[1]表示第33~64个数(32~63)设计

code

这样,每当输入一个数字i,咱们应该先找到该数字在数组的第几个元素中,也就是a[?],而后再肯定在这个元素的第几位中。htm

举个例子来讲,好比输入35,那么35/32为1余3,则应该将a[1]的第4位置为1。blog

好,有了上面的概念,能够先来看看题中set是怎么实现的:

void set(int i)
{
    a[i>>SHIFT] |= (1<<(i &MASK));
}

根据题目的要求,咱们不能够用/运算符来设计程序,那除的话咱们能够用右移来替代:

m>>n,表示m往右移动n位

输入i,除以32至关于往右移动5位,则i>>SHIFT表明i/32获得应该放在数组的第几个元素中,而后要置相应的位置位1了:

先来看看1<<(i&MASK)是什么意思。i&MASK至关于取i右移掉的部分,说白了就是取余数。

好比35的二进制表示是:… 0010 0011

MASK的二进制是0001 1111

两个相与操做获得0 0011

而右移5位,移掉的数是0 0011,换算成10进制是3,正是余数,与上面的操做值相等,都是0 0011。

所以1<<(i&MASK)就变成了1<<3,也就是将1右移3位,变成了1000。

而后在作一个|操做就将a[1]的第4位置1了。

对于clr函数,就是找到位置,而后清零

对于test函数,就是找到位置,作一个与操做,若是存在这个数,则返回1,不存在的话,由于是&操做,因此返回0。

下面是全部的答案:

#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1+N/BITSPERWORD];
void set(int i)
{
    a[i>>SHIFT] |= (1<<(i &MASK));
}
void clr(int i )
{
    a[i>>SHIFT] &= ~(1<<(i &MASK));
}
int test(int i )
{

能够写一个main函数测试一下:

 

#include <iostream>//不要忘记它
using namespace std;//不要忘记它
int main(){
    int i = 35;
    //设置i,也就是置相应位置位1
    set(i);
    //测试是否置1了
    if(test(i))
        cout<<"ok"<<endl;
    return 0;
}

image

大概就这样了。

(本文网址:http://www.cnblogs.com/marsdu/p/3181734.html

相关文章
相关标签/搜索