這是一道非常基礎的題目,考察對位運算的理解,好看題目只覺得好眼熟,然后(手賤)瞟了一眼答案,第一遍沒看明白答案的內容,就上網查了一下,網上的人要么就是一筆帶過(大概是覺得太簡單),要么就是誤人子弟。
解決題目之前應該先搞清楚題目是干嘛的:
位向量顧名思義就是用位來存儲一個數,文中說存儲N=10000000個數,每一位代表一個數。
我們可以定義一個int類型的數組int a[N],那么如果a[9]的值為1,則表明文件中存在一個值為9。
這樣的話,我們就可以用一個數組來表示這么多數。我們又知道,一個int型的數有4個字節,也就是32位,那么我們可以用N/32個int型數來表示這N個數:
a[0]表示第1~32個數(0~31)
a[1]表示第33~64個數(32~63)
…
這樣,每當輸入一個數字i,我們應該先找到該數字在數組的第幾個元素中,也就是a[?],然后再確定在這個元素的第幾位中。
舉個例子來說,比如輸入35,那么35/32為1余3,則應該將a[1]的第4位置為1。
好,有了上面的概念,可以先來看看題中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; }
大概就這樣了。