1.判斷奇偶
奇偶數的特徵:如果一個數是偶數,則對於其二進制來說,最低位肯定是0;如果一個數是奇數,則對於其二進制來說,最低位肯定是1,因爲在二進制表示中,只有 會產生1
所以可以利用這一特徵來判斷奇偶數
if((num&1) == 0)
{
//偶數
}
else
{
//奇數
}
注意:不用寫爲 num&1 == 0 ,這樣的判斷是錯誤的,必須給前面帶上括號;因爲 == 優先級高於 位運算符&
2.消去一個數中的最低位
比如十進制數5(0101), 我們要消去其二進制中的最低位的1
則 操作是 (5&4) = (0101 & 0100) = 0100,從而將最低位處的1消除
典型應用:統計一個數的二進制表示中有多少個1
int hammingWeight(uint32_t n)
{
int count = 0;
while(n)
{
count++;
n &= (n-1);
}
return count;
}
3.將二進制數進行翻轉操作
可以用到C++中的bitset,它是類似於一個數組的結構,其內部元素只能是0或1,且每一位只佔1bit
bitset數組簡介:
bitset<8> bitset1; //構造長度爲4的bitset數組,每一位默認爲0
bitset<8> bitset2(12); //構造長度爲8的數組,並用12的二進制去初始化
//也可以用字符串來進行構造
string s = "11000";
bitset<8> bitset3(s);
//注:當bitset的長度大於初始化所用的二進制數長度時,則在前面用0補足
//而當初始化所用的二進制長度大於bitset長度時,對於整數則只取整數後面部分,對於字符串則只取字符串前面部分
//bitset數組支持類似數組的[]操作,可以看做數組進行處理
//bitset支持位運算的所有操作符
//bitset的屬性
bitset<8> foo ("10011011");
cout << foo.count() << endl; //5 (count函數用來求bitset中1的位數,foo中共有5個1
cout << foo.size() << endl; //8 (size函數用來求bitset的大小,一共有8位
cout << foo.any() << endl; //true (any函數檢查bitset中是否有1
cout << foo.none() << endl; //false (none函數檢查bitset中是否沒有1
cout << foo.all() << endl; //false (all函數檢查bitset中是全部爲1
//bitset的類型轉換函數
bitset<8> foo ("10011011");
string s = foo.to_string(); //將bitset轉換成string類型
unsigned long a = foo.to_ulong(); //將bitset轉換成unsigned long類型
unsigned long long b = foo.to_ullong(); //將bitset轉換成unsigned long long類型
cout << s << endl; //10011011
cout << a << endl; //155
cout << b << endl; //155
所有,進行二進制的反轉就和數組的反轉操作是一樣的
uint32_t reverseBits(uint32_t n)
{
bitset<32> bit_set(n);
int i = 0;
int j = 31;
while(i < j)
{
bool tmp = bit_set[i];
bit_set[i++] = bit_set[j];
bit_set[j--] = tmp;
}
return (uint32_t) bit_set.to_ulong();
}
4.不借助外部變量實現兩個數的交換
常規的實現兩個數的交換通常藉助外部變量來實現,比如
int a = 1;
int b = 2;
//實現兩個數的交換,藉助外部變量c
int c = a; //c = 1
a = b; // a = 2
b = c; // b = 1
不借助外部變量可以通過異或來實現
int a = 1;
int b = 2;
a ^= b; // a = 1^2 = 3
b ^= a; // b = 2 ^ 3 = 1
a ^= b; // a = 3 ^ 1 = 2
//所以最後 a = 2; b = 1;實現了兩者的交換
5.求一個數的相反數
由於補碼原理,對一個數進行取反後+1就可以得到它的相反數
6.求一個數的絕對值
由於正數的絕對值是其本身,負數的絕對值是其相反數,所以只需要判定正負,然後進行操作即可
如何判斷正負呢?
對於32位整數來言,最高位是符合位,1代表負數,0代表正數
int myabs(int num)
{
int flag = num >> 31;
return flag == 0 ? num : ~num+1;
}
在此基礎上可以進一步優化,由於 一個數與0異或相當於其本身,而與-1異或相當於 對本身進行取反操作,所以
int myabs(int num)
{
int flag = num >> 31;
return (flag^num) - flag;//如果flag = 0,則返回 num本身,若flag=-1,則返回 ~num+1
}
7.通過位運算來判斷兩個小寫單詞(字符串)是否有相同字符
由於只包含小寫字母,所以總共有26位,而int有32位,所以我們可以用int的低26位來進行表示這26個字母
比如"abc", 用位來表示可以表示爲 0111,然後由於每一位均代表一個字符,所以我們最後讓兩個位表示的字符串進行相與即可,如果結果爲1,則表示兩個字符串存在相同字符,否則兩者不存在相同字符
string s1 = "abc";
string s2 = "cde";
bool commonstr(string s1, string s2)
{
vector<int> mask(2,0);
for(char c: s1)
{
mask[0] |= 1 << (c - 'a');
}
for(char c: s2)
{
mask[1] |= 1 << (c - 'a');
}
if(mask[0]&mask[1])
{
return true;
}
return false;
}