神奇的二進制

(在計算機中,數(shù)都是二進制來存儲的,所以二進制的一些運算要比普通的等價運算(+,-,*,/)更快,更簡單,所以知道他們的技巧顯得尤其重要!)

異或運算:

首先 異或(^) 表示當兩個數(shù)的二進制表示废麻,進行異或運算時,當前位的兩個二進制表示不同則為 1 相同則為 0 .該方法被廣泛推廣用來統(tǒng)計一個數(shù)的1的位數(shù)矩屁!

所以二進制中 對應二進制位數(shù)進行異或操作時, 與0異或?qū)摱M制位數(shù)值不變, 與 1 異或時對應該二進制位數(shù)值相反(即 1 變成 0 , 0 變成 1).

參與運算的兩個值遍膜,如果兩個二進制相應位相同,則結(jié)果為0扛或,否則(不同)為1绵咱。
即:
  0^0 = 0,
  1^0 = 1熙兔,
  0^1 = 1悲伶,
  1^1 = 0

按位異或的3個特點:
(1) 00=0,01=1 0異或任何數(shù)=任何數(shù) (這里的任何數(shù)是指二進制位上的那個數(shù),即任何數(shù)要么為0 ,要么為1 .)
(2) 10=1,11=0 1異或任何數(shù)-任何數(shù)取反 (同理)
(3) 任何數(shù)異或自己=把自己置0

按位異或的幾個常見用途:
(1) 使某些特定的位翻轉(zhuǎn)
例如對數(shù)10100001的第2位和第3位翻轉(zhuǎn)(不管是0 還是 1 都可以,因為上面也說了 任何數(shù)與1 異或 任何數(shù)取反 ! 所以可以進行翻轉(zhuǎn)!)住涉,則可以將該數(shù)與00000110進行按位異或運算

10100001^00000110 = 10100111

(2) 實現(xiàn)兩個值的交換麸锉,而不必使用臨時變量。
例如交換兩個整數(shù)a=10100001舆声,b=00000110的值花沉,可通過下列語句實現(xiàn):
    a = a^b;   //a=10100111
    b = b^a媳握;   //b=10100001
    a = a^b碱屁;   //a=00000110
(一句話: a=ab(b=a) ; )

再次 & (與) 二進制對應位上都是 1 結(jié)果才是1 . 否則就是 0 . (和電路開關很像,串聯(lián),同時開才開,否則就是關.)

技巧 1 : 把一個整數(shù)減去1,再和原整數(shù)做與運算,會把該整數(shù)的二進制中的最右邊一個1變成0 , 那么一個整數(shù)的二進制表示中有多少個1,就可以進行多少次這樣的操作.

技巧 2 : 二進制的最低位是1就是奇數(shù),是0就是偶數(shù).
(原因 : 二進制的位數(shù)(由低到高)分別代表著1,2,4,8,16,32,64,128,256,512,1024.只有最低位的這個是1或0,所以二進制最低位為1時,就是奇數(shù)(偶數(shù)由上面的這些基本的組成嘛!) )

技巧 3 :算一個數(shù)的二進制最低位是多少, 直接 x&1 = x的最低位是多少.

例 1: 如何用一條語句表示判斷一個整數(shù)是不是2的整數(shù)次方.
解 : 因為是整數(shù)次方,所以該數(shù)的二進制中必定只含一個 1 . 所以結(jié)合上面的技巧,就有 !(x & (x-1) ) ;

例 2 : 寫一個函數(shù),判斷一個數(shù)的二進制中多少個 1 .

int check(int x)
{
    int num=0;
    while(x)
    {
        x &= (x-1);
        num++;
    }
    return num;
}

例 3 : 輸入兩個整數(shù)m和n,計算需要改變m的二進制表示中的多少位才能得到n .
思路: 結(jié)合異或的性質(zhì)運算,首先讓 m^n 得到一個數(shù),則這個數(shù)二進制中有多少個1 , 則m,n就有多少位不同.所以統(tǒng)計得到的這個數(shù)中又多少個1就行了.

int check(int m,int n)
{
    int x=m^n;
    int num=0;
    while(x)
    {
        x &= (x-1);
        num++;
    }
    return num;
}

例 4:判斷一個數(shù)的奇偶性(結(jié)合技巧)

     if(x&1)
        是奇數(shù).
     else 
       是偶數(shù).

例 5 :算一個數(shù)二進制的補位數(shù)(比如說5的二進制是101, 所以補位數(shù)就是010, 即2,當然不能直接用~)

int sum=0,s=1;
while(t){
        int m=((t&1)^1);
        sum += s*m;   //是1才算值, 是零就不管.
        t  >>= 1;   //不斷除二.
        s <<= 1;  //s表示2的幾次方.
}

二進制的一些操作:

1:將一個十進制的數(shù)分解為二進制表示. 
while(t){
        int m=t&1;
        a[k++]=m;
        t >>= 1;
}
2:將一個十進制數(shù)轉(zhuǎn)化成二進制的同時再算出轉(zhuǎn)化后的這個數(shù)十進制表示為多少.
int s=1,sum=0;
while(t){
        int m=t&1;
        sum += s*m;
        s <<= 1;
        t >>= 1;
}
3:取某個數(shù)的第 i 個 二進制位數(shù).
int Getbit(int x,int i)
{
    return (x >> i) & 1;
}
4:把  x  的第 i 位設置成 v .
void setbit(int & x,int i,int v)   //這樣引用的話,形參改變對應實參也會改變.
{
    if(v ){
        c |= (1 << i);  
   }
    else
        c &= ~(1 << i);
}
5:把x的第 i 位翻轉(zhuǎn).(1 翻為0 , 0 翻為 1).
void flipbit(char & c ,int i)
{ 
    c ^= (1 << i) ;
}
一大波操作 : 
去掉最后一位          |(101101->10110) |               x >> 1
在最后加一個0        |(101101->1011010) |            x < < 1
在最后加一個1        |(101101->1011011) |            x < < 1+1
把最后一位變成1     |(101100->101101) |              x | 1
把最后一位變成0     |(101101->101100) |              x | 1-1
最后一位取反          |(101101->101100) |             x ^ 1
把右數(shù)第k位變成1    | (101001->101101,k=3) |      x | (1 < < (k-1))  //k>=1, 即第一位算的是1
把右數(shù)第k位變成0    | (101101->101001,k=3) |      x & ~ (1 < < (k-1))
右數(shù)第k位取反        | (101001->101101,k=3) |       x ^ (1 < < (k-1))
取末三位               | (1101101->101) |                x & 7
取末k位                | (1101101->1101,k=5) |        x & ((1 < < k)-1)
取右數(shù)第k位           | (1101101->1,k=4) |             x >> (k-1) & 1
把末k位變成1         | (101001->101111,k=4) |       x | (1 < < k-1)
末k位取反              | (101001->100110,k=4) |      x ^ (1 < < k-1)
把右邊連續(xù)的1變成0     | (100101111->100100000) |   x & (x+1)
把右起第一個0變成1     | (100101111->100111111) |   x | (x+1)
把右邊連續(xù)的0變成1     | (11011000->11011111) |      x | (x-1)
取右邊連續(xù)的1        | (100101111->1111) |           (x ^ (x+1)) >> 1
去掉右起第一個1的左邊 | (100101000->1000) |       x & (x ^ (x-1))
判斷奇數(shù)                   (x&1)==1
判斷偶數(shù)                    (x&1)==0 
取右邊第一個1所在位置  x&-x
將右邊第一個1變?yōu)?.   x &= (x-1)
 
移位運算要點 
1:  它們都是雙目運算符蛾找,兩個運算分量都是整形娩脾,結(jié)果也是整形。  
2:  "<<" 左移:右邊空出的位上補0腋粥,左邊的位將從字頭擠掉晦雨,其值相當于乘2。  
3:  ">>"右移:右邊的位被擠掉隘冲。對于左邊移出的空位闹瞧,如果是正數(shù)則空位補0,若為負數(shù)展辞,可能補0或補1奥邮,這取決于所用的計算機系統(tǒng)。  
4:  ">>>"運算符罗珍,右邊的位被擠掉洽腺,對于左邊移出的空位一概補上0。
位運算符的應用 (源操作數(shù)s 掩碼mask)
(1) 按位與-- &
1: 清零特定位 (mask中特定位置0覆旱,其它位為1蘸朋,s=s&mask)
2: 取某數(shù)中指定位 (mask中特定位置1,其它位為0扣唱,s=s&mask)

(2) 按位或-- |  
     常用來將源操作數(shù)某些位置置為1藕坯,其它位不變团南。 (mask中特定位置1,其它位為0 s=s|mask)
(3) 位異或-- ^1 
1: 使特定位的值取反 (mask中特定位置1炼彪,其它位為0 s=s^mask)
2: 不引入第三變量吐根,交換兩個變量的值(a = a^b^(b==a); || a ^= b;  b ^= a;  a ^= b;)

二進制補碼運算公式:(不懂負數(shù)的點擊最下方)
-x = ~x + 1 = ~(x-1)  
~x = -x-1 
-(~x) = x+1
~(-x) = x-1
比較應用舉例
(1)整數(shù)的平均值對于兩個整數(shù)x,y,如果用 (x+y)/2 求平均值辐马,會產(chǎn)生溢出拷橘,因為 x+y 可能會大于INT_MAX,
但是我們知道它們的平均值是肯定不會溢出的喜爷,我們用如下
int average(int x, int y) //返回X,Y 的平均值
{     
         return (x&y)+((x^y)>>1);
}
(2) x 的 相反數(shù) 表示為 (~x+1) 

不懂負數(shù)在計算機中如何用二進制表示的請點這里

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冗疮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子贞奋,更是在濱河造成了極大的恐慌赌厅,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轿塔,死亡現(xiàn)場離奇詭異特愿,居然都是意外死亡,警方通過查閱死者的電腦和手機勾缭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門揍障,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俩由,你說我怎么就攤上這事毒嫡。” “怎么了幻梯?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵兜畸,是天一觀的道長。 經(jīng)常有香客問我碘梢,道長咬摇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任煞躬,我火速辦了婚禮肛鹏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恩沛。我一直安慰自己在扰,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布雷客。 她就那樣靜靜地躺著芒珠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搅裙。 梳的紋絲不亂的頭發(fā)上妓局,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天总放,我揣著相機與錄音,去河邊找鬼好爬。 笑死,一個胖子當著我的面吹牛甥啄,可吹牛的內(nèi)容都是我干的存炮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蜈漓,長吁一口氣:“原來是場噩夢啊……” “哼穆桂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起融虽,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤享完,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后有额,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體般又,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年巍佑,在試婚紗的時候發(fā)現(xiàn)自己被綠了茴迁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡萤衰,死狀恐怖堕义,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脆栋,我是刑警寧澤倦卖,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站椿争,受9級特大地震影響怕膛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丘薛,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一嘉竟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洋侨,春花似錦舍扰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裁僧,卻和暖如春个束,著一層夾襖步出監(jiān)牢的瞬間慕购,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工茬底, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沪悲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓阱表,卻偏偏與公主長得像殿如,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子最爬,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容