各種位運算
位運算的操作數必須是整數,當二元位運算的操作數是不同類型的整數時,也會自動進行類型轉換。
n&(n-1)作用:將n的二進制表示中的最低位為1的改為0,先看一個簡單的例子: n = 10100(二進制),則(n-1) = 10011 ==》n&(n-1) = 10000 可以看到原本最低位為1的那位變為0。 弄明白了n&(n-1)的作用,那它有哪些應用? 1. 求某一個數的二進制表示中1的個數 while (n >0 ) { count ++; n &= (n-1); }
2. 判斷一個數是否是2的方冪 n > 0 && ((n & (n - 1)) == 0 )
3. 計算N!的質因數2的個數。 容易得出N!質因數2的個數 = [N / 2] + [N / 4] + [N / 8] + .... 下面通過一個簡單的例子來推導一下過程:N = 10101(二進制表示) 現在我們跟蹤最高位的1,不考慮其他位假定為0, 則在 [N / 2] 01000 [N / 4] 00100 [N / 8] 00010 [N / 8] 00001 則所有相加等於01111 = 10000 - 1 由此推及其他位可得:(10101)!的質因數2的個數為10000 - 1 + 00100 - 1 + 00001 - 1
= 10101 - 3(二進制表示中1的個數)
推及一般N!的質因數2的個數為N - (N二進制表示中1的個數)
目前看到只有這些應用,但只要理解了n&(n-1)的原理及作用,在碰到相關問題時也會比較容
易解決。
4.線段樹中lowbitn&(-n)表示最后一個1的基數
5.按位與運算通常用來將某變量中的某些位清0或保留某些位不變。
例如,如果需要將int型變量n的低8位全置成0,而其余位不變,則可以執行:
n = n & 0xffffff00;
也可以寫成:
n &= 0xffffff00;
如果n是short類型的,則只需執行:
n &= 0xff00;
如何判斷一個int型變量n的第7位(從右往左,從0開始數)是否是1 ?
只需看表達式 “n & 0x80”的值是否等於0x80即可
6.按位或運算符“|”是雙目運算符。
功能:將參與運算的兩操作數各對應的二進制位進行或操作,只有對應的兩個二進位都為0時,結果的對應二進制位才是0,否則為1。
例如:表達式“21 | 18 ”的值是23(即二進制數10111)。
按位或運算通常用來將某變量中的某些位置1或保留某些位不變。
例如,如果需要將int型變量n的低8位全置成1,而其余位不變,則可以執行:
n |= 0xff;
7.按位異或運算符“^”是雙目運算符。
功能:將參與運算的兩操作數各對應的二進制位進行異或操作,即只有對應的兩個二進位不相同時,結果的對應二進制位才是1,否則為0。
例如:表達式“21 ^ 18 ”的值是7(即二進制數111)。
異或運算的特點
如果 a^b=c,那么就有 c^b = a以及c^a=b。
此規律可以用來進行最簡單的加密和解密
用途:
使特定位翻轉(與0異或保持原值,與1異或取反)
例如:要使 01111010 低四位翻轉:
0 1 1 1 1 0 1 0
(^) 0 0 0 0 1 1 1 1
0 1 1 1 0 1 0 1
由於異或運算的自反性和滿足交換律、結合律,常常被用於一些技巧性較強的應用中.
void inplace_swap(int* x, int* y)
{
*y = *x ^ *y;
*x = *x ^ *y;
*y = *x ^ *y;
}
Q:1-1000放在含有1001個元素的數組中,只有唯一的一個元素值重復,其它均只出現一次.每個數組元素只能訪問一次,設計一個算法,將它
找出來;不用輔助存儲空間
方法一:
將1001個數加起來,再減去1+2+3+…+1000,不過這種方法不通用,容易溢出。
方法二:
將1001個數異或,然后和1^2^3^…^1000的結果進行異或,最后的結果就是要求的數。(a^a=0,0^a=a)
google面試題的變形:一個數組存放若干整數,一個數出現奇數次,其余數均出現偶數次,找出這個出現奇數次的數?
解法有很多,但是最好的和上面一樣,就是把所有數異或,最后結構就是要找的,原理同上!
找出數組中唯一不重復的元,數組可以很大。(和奇數次一樣)
8.按位非運算符“~”是單目運算符。
其功能是將操作數中的二進制位0變成1,1變成0。
例如,表達式“~21”的值是無符號整型數 0xffffffea,
而下面的語句: printf("%d,%u,%x",~21,~21,~21);(無符號時,直接加權加和)
輸出結果就是:-22,4294967274,ffffffea
9.例如,常數9有32位,其二進制表示是: 0000 0000 0000 0000 0000 0000 0000 1001
因此,表達式“9<<4”的值,就是將上面的二進制數左移4位,得: 0000 0000 0000 0000 0000 0000 1001 0000 即為十進制的144。
實際上,左移1位,就等於是乘以2,左移n位,就等於是乘以2n。而左移操作比乘法操作快得多。
特別注意:有符號數的左移溢出情況。
10.實際上,右移n位,就相當於左操作數除以2n,並且將結果往小里取整。
11.
1<<n=2^n;n<<1(2*n)
有兩個int型的變量a和n(0 <= n <= 31),
要求寫一個表達式,使該表達式的值和a的第n位相同。
返回結果0或者1,不是那一位的權值,a & (1 << n )是a的第n位的權值;
結果:(a & (1 << n )) >> n
12.檢測一個無符號數是否為2^n-1(^為冪): x&(x+1),或者(x+1)%2,前者是的話返回0,否則返回x,測試了下有符號的也可。
將最右側0變為1:x | (x+1),相反的是x&(x-1)。
13.二進制進補碼運算:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x&~y)-(~x&y)
x^y = (x|y)-(x&y)(異或)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//無符號x,y較
x<=y: (~x|y)&((x^y)|~(y-x))//無符號x,y較