位運算之技巧篇


1.判斷奇偶

只要根據最未位是0還是1來決定,爲0就是偶數,爲1就是奇數。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)來判斷a是不是偶數。

2.交換兩數

可以用位操作來實現交換兩數而不用第三方變量:


    void Swap(int &a, int &b)  
    {  
        if (a != b)  
        {  
            a ^= b;  
            b ^= a;  
            a ^= b;  
        }  
    }  


第一步  a^=b 即a=(a^b);

第二步  b^=a 即b=b^(a^b),由於^運算滿足交換律,b^(a^b)=b^b^a。由於一個數和自己異或的結果爲0並且任何數與0異或都會不變的,所以此時b被賦上了a的值。

第三步 a^=b 就是a=a^b,由於前面二步可知a=(a^b),b=a,所以a=a^b即a=(a^b)^a。故a會被賦上b的值。
再來個實例說明下以加深印象。int a = 13, b = 6;

a的二進制爲 13=8+4+1=1101(二進制)

b的二進制爲 6=4+2=110(二進制)

第一步 a^=b  a = 1101 ^ 110 = 1011;

第二步 b^=a  b = 110 ^ 1011 = 1101;即b=13

第三步 a^=b  a = 1011 ^ 1101 = 110;即a=6

3.變換符號

變換符號就是正數變成負數,負數變成正數。

如對於-11和11,可以通過下面的變換方法將-11變成11

      1111 0101(二進制) –取反-> 0000 1010(二進制) –加1-> 0000 1011(二進制)

同樣可以這樣的將11變成-11

      0000 1011(二進制) –取反-> 0000 0100(二進制) –加1-> 1111 0101(二進制)


4.求絕對值

位操作也可以用來求絕對值,對於負數可以通過對其取反後加1來得到正數。對-6可以這樣:

      1111 1010(二進制) –取反->0000 0101(二進制) -加1-> 0000 0110(二進制)

來得到6。

因此先移位來取符號位,int i = a >> 31;要注意如果a爲正數,i等於0,爲負數,i等於-1。然後對i進行判斷——如果i等於0,直接返回。否之,返回~a+1。

int my_abs(int a)  
{  
    int i = a >> 31;  
    return i == 0 ? a : (~a + 1);  
}  

現在再分析下。對於任何數,與0異或都會保持不變,與-1即0xFFFFFFFF異或就相當於取反。因此,a與i異或後再減i(因爲i爲0或-1,所以減i即是要麼加0要麼加1)也可以得到絕對值。所以可以對上面代碼優化下:
int my_abs(int a)  
{  
    int i = a >> 31;  
    return ((a ^ i) - i);  
}  

5.  高低位交換

給出一個16位的無符號整數。稱這個二進制數的前8位爲“高位”,後8位爲“低位”。現在寫一程序將它的高低位交換。例如,數34520用二進制表示爲:

      10000110 11011000

將它的高低位進行交換,我們得到了一個新的二進制數:

      11011000 10000110

它即是十進制的55430。

這個問題用位操作解決起來非常方便,設x=34520=10000110 11011000(二進制) 由於x爲無符號數,右移時會執行邏輯右移即高位補0,因此x右移8位將得到00000000 10000110。而x左移8位將得到11011000 00000000。可以發現只要將x>>8與x<<8這兩個數相或就可以得到11011000 10000110

6.  缺失的數字

很多成對出現數字保存在磁盤文件中,注意成對的數字不一定是相鄰的,如2, 3, 4, 3, 4, 2……,由於意外有一個數字消失了,如何儘快的找到是哪個數字消失了?

由於有一個數字消失了,那必定有一個數只出現一次而且其它數字都出現了偶數次。用搜索來做就沒必要了,利用異或運算的兩個特性——1.自己與自己異或結果爲0,2.異或滿足交換律。因此我們將這些數字全異或一遍,結果就一定是那個僅出現一個的那個數。


原文地址:http://blog.csdn.net/morewindows/article/details/7354571

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章