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