運算符
- &:0&0=0 ,1&0=1,0&1=1,1&1=1
- |:0|0=0,0|1=1,1|0=1,1|1=1
- ^ :00=0,10=1,01=1,11=0
左移運算符
m"<<"n,左移n位,左邊的n位被丟棄,同時最右邊補上n個0
比如
00001010<<2==00101000
10001010<<3==01010000
右移運算符m>>n表示右移n位。右移n位的時候,最右側(cè)n位被丟棄。單右移時處理最左邊位的情形要復(fù)雜一點,如果數(shù)字是一個無符號數(shù)值,則用0填補最左邊的n位。如果數(shù)字是一個有符號數(shù)值,則右移之后再最左邊補上n個0,如果數(shù)字原先是負(fù)數(shù),則右移之后再最左邊補上n個1.
00001010>>2=00000010
10001010>>3=11110001
請實現(xiàn)一個函數(shù),輸入一個整數(shù),輸出該數(shù)的二進制中表示1的個數(shù)。例如把9表示成二進制數(shù)是10001,有2位是1,。因此如果輸入9,該函數(shù)輸出2
可能引起死循環(huán)的解法
--
先判斷整數(shù)二進制表示中最右邊數(shù)是不是1,接著把輸入的整數(shù)右移以為,此時原來處于右邊數(shù)的第二位被移到最右邊,再判斷是不是1.這樣每次移到一位,直到整個整數(shù)變?yōu)?為止。判斷是不是1 則用&符號
//尋找一個數(shù)字中的二級制中的1有幾個 可能有死循環(huán)的解法
public int tester(int n) {
int count = 0;
while (n != 0) {
if ((n & 1) == 1) {
count++;
}
n = n >> 1;
}
return count;
}
幾個面試問題:如果把整數(shù)右移一位和整數(shù)除以2在數(shù)學(xué)上是等級的,那上面的代碼可以把右移運算換成除以2么? 答案是否定的。因為觸發(fā)的效率比移位運算要低得多,在實際編程中盡可能使用移位運算符替代乘除法
如果函數(shù)中輸入一個負(fù)數(shù)如:0x80000000,則會出現(xiàn)的情況,把負(fù)數(shù)右移以為的時候,并不簡單的把高位1移到第二位變成0x4000000,而是0xC0000000。這是因為移位前是個負(fù)數(shù),仍然要保證移位后是個負(fù)數(shù)因此移位后的最高位會設(shè)為1。如果一直做右移運算,最終會變成0xfffffffff而陷入死循環(huán)
常規(guī)解法
可以不右移輸入的數(shù)字。首先把n和1做&運算,判斷最低位是不是1,然后左移
//常規(guī)解法
public static int tester2(int n) {
int count = 0;
int flag = 1;
while (n != 0) {
if ((n & flag) == 1) {
count++;
}
n = n >> 1;
}
return count;
}
另類解法
在分析算法前,先分析把一個數(shù)減去1,的情況,如果一個整數(shù)不為0,那么該整數(shù)的二進制表示中至少有一位是1。先假設(shè)這個數(shù)的最右邊一位是1,那么減去1時,最后一位變成0,而其他所有位都保持不變,也就是最后一位相當(dāng)于取反操作,由1變成0,接下來假設(shè)最后一位不是1而是0的情況,如果該整數(shù)的二進制表示中最右邊1位于第m位,那么減去1,第m位由1變成0,而第m位之后的所以0都變成1,整數(shù)中第m位之前的所以位保持不變。舉個例子:一個二級制數(shù)1100,它的第二位是從最右邊數(shù)起的一個1,減去1后,第二位變成0,它后面的兩位變成1,而前面的1保持不變,因此是1011.
在前面兩種情況下,我們發(fā)現(xiàn)把一個整數(shù)減去1,都是把最右邊的1變成0,如果它的右邊還有0的話,所以0變成1,而它左邊所以位都保持不變,接下來我們把一個整數(shù)和它減去1的結(jié)果做位與運算,相當(dāng)與它最右邊的1變成0,還是以前面的1100為例,它減去1的結(jié)果是1011,我們把1011與1100做與運算,得到的結(jié)果是1000,我們把1100最右邊的1變成0,剛好是1000
分析總結(jié)
--
把一個整數(shù)減去1,在和原整數(shù)做與運算,會吧該整數(shù)最右邊的一個1變?yōu)?,那么一個整數(shù)的二進制表示中有多少個1,就可以做多少次這樣的操作。
public static int count(int n){
int num = 0;
while(n!=0){
n = n&(n-1);
num++;
}
return num;
}
左移的循環(huán)次數(shù)等于整數(shù)二進制的位數(shù),32位的整數(shù)需要32次,而上述的次數(shù),取決于整數(shù)中有幾個1,就循環(huán)幾次