如何使用位邏輯運算來實現位向量的理解


這是一道非常基礎的題目,考察對位運算的理解,好看題目只覺得好眼熟,然后(手賤)瞟了一眼答案,第一遍沒看明白答案的內容,就上網查了一下,網上的人要么就是一筆帶過(大概是覺得太簡單),要么就是誤人子弟。

解決題目之前應該先搞清楚題目是干嘛的:

位向量顧名思義就是用位來存儲一個數,文中說存儲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;
}

image

大概就這樣了。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM