数据结构与算法--位运算
生活随笔
收集整理的這篇文章主要介紹了
数据结构与算法--位运算
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
位運(yùn)算
- 記得大學(xué)編譯原理剛開始面對(duì)的就是機(jī)器語言,而位運(yùn)算就是講數(shù)字用二進(jìn)制標(biāo)識(shí)后,對(duì)每一位上的0, 或者1 進(jìn)行運(yùn)算。二進(jìn)制以及位運(yùn)算都是計(jì)算機(jī)學(xué)科的基礎(chǔ),很多底層技術(shù)都離不開位運(yùn)算,因此我們?cè)趯?shí)際開發(fā)過程中可能會(huì)遇到。由于我們?nèi)祟愂煜さ氖鞘M(jìn)制,因此接觸到二進(jìn)制的時(shí)候可能難以適應(yīng)。
- 除了二進(jìn)制,我們還可以將數(shù)字表示成其他的進(jìn)制,比如,表示分秒的六十進(jìn)制等。針對(duì)不太熟悉的進(jìn)制,可能會(huì)有一些奇奇怪怪的問題,比如下面這種:
- 如上其實(shí)就是講A~Z理解成一個(gè)26進(jìn)制,只要理解了二進(jìn)制的計(jì)算規(guī)則,26進(jìn)制也是同樣的算法。
- 二進(jìn)制中位運(yùn)算也就只有五種與, 或,異或,左移,右移。前三種用如下規(guī)則
-左移運(yùn)算符m << n表示吧m左移n位,左移n位的時(shí)候,最左邊的n位將被丟棄,同時(shí)最右邊補(bǔ)充n個(gè)0,例如:
0000 1010 << 2 = 0010 1000 1000 1010 << 3 = 0101 0000- 右移運(yùn)算符m >> 表示把m右移n位, 右移n為的時(shí)候,最右邊的n為將被丟棄,當(dāng)右移時(shí)候,處理最左邊為的情形要稍微復(fù)雜一點(diǎn)
- 如果是無符號(hào)數(shù)值,則用0 填補(bǔ)最左邊的n為。
- 如果是有符號(hào)數(shù)值,則用數(shù)字的符號(hào)位補(bǔ)充最左邊的n位,也就是說如果數(shù)字是一個(gè)正數(shù),右移后補(bǔ)充n個(gè)0 在左邊,如果原數(shù)字是負(fù)數(shù),則右移后最左邊補(bǔ)充n個(gè)1.
- 如下對(duì)兩個(gè)8 為有符號(hào)數(shù)值做右移操作
具體案例分析
- 題目:實(shí)現(xiàn)一個(gè)函數(shù),輸入一個(gè)整數(shù),輸出該整數(shù)二進(jìn)制標(biāo)識(shí)中1 的個(gè)數(shù)。例如把 9 標(biāo)識(shí)成二進(jìn)制后四位1001,有2位是1,因此如果輸入9 ,函數(shù)輸出2
分析
- 上題中考察二進(jìn)制的知識(shí),基本思路也就是利用那五種運(yùn)算規(guī)則的組合來解答,可以先判斷二進(jìn)制數(shù)的最低位是不是1 ,將數(shù)值右移一位,接著判斷最低位是否是1 ,繼續(xù)如此直到數(shù)值為0 為止,
- 現(xiàn)在需要確定怎么確定首位是1,:將整數(shù)與1 做 與操作,看結(jié)果是否是0 ,如果是0 則表示最低位是0 ,否則是1
- 用9 為案例如下:
- 以上我們可以得到如下代碼:
- 問題,以上代碼都只考慮正數(shù)情況,正數(shù)右移是補(bǔ)充0 在最高位,所以能得出正常的解。我們用一個(gè)負(fù)數(shù)來舉例,例如 -9 。
- 首先必須要明確的是:***負(fù)數(shù)在計(jì)算機(jī)中都是以補(bǔ)碼來表示的。 負(fù)數(shù)的位運(yùn)算也是在補(bǔ)碼上進(jìn)行的。***這一點(diǎn)很重要
- 我們用int類型為案例分析,int 32位有符號(hào)整型(-9) 的二進(jìn)制標(biāo)識(shí):
- 原碼:1000 0000 0000 0000 0000 0000 0000 1001
- 反碼:1111 1111 1111 1111 1111 1111 1111 0110
- 補(bǔ)碼:1111 1111 1111 1111 1111 1111 1111 0111
- 用以上算法對(duì)-9 進(jìn)行右移的時(shí)候,在最左邊補(bǔ)充的是1 ,因此不可能為0 ,因此會(huì)有死循環(huán)。
正確解法
- 上面的算法中我們思路是通過對(duì)求解的數(shù)進(jìn)行右移來判斷首位是否是1 ,既然不能通用,那么我們是否可能逐一判斷數(shù)值的每一位二進(jìn)制位上是否是1 。我們用flag表示 甄別是否是1 的數(shù)值 ,首先取flag = 1
- 首先將數(shù)值與flag進(jìn)行與操作,判斷最低位是否是1 ,
- 將flag 左移一位,繼續(xù)與數(shù)值與操作,判斷第二位是否為1
- 繼續(xù)如上操作,直到 flag的值為 0 ,(此時(shí)移動(dòng)了32 位,超出int界限,所有位置都為0 )
- 我們可以得到如下算法實(shí)現(xiàn):
- 以上算法能統(tǒng)一解決帶符號(hào),和不帶符號(hào)的數(shù)值的問題,并且對(duì)所有數(shù)值的計(jì)算都需要循環(huán)32 次,但是其實(shí)其中只有幾次是有效的判斷,比如1001 只有2 次,我們是否有更精簡的方法。有幾個(gè)1 就幾次判斷?
最優(yōu)解
- 分析將一個(gè)數(shù)減1 , 如果是不為0 的數(shù),那么二進(jìn)制表示中必然有1 ,假設(shè)這個(gè)數(shù)最右邊一位是1,那么減1 的時(shí)候,最右邊(低位)就會(huì)1 變0,而其他所有位不變。相當(dāng)于最后一位取反。例子:
- 此時(shí)我們只能判斷出第一位是不是1,此時(shí)我們還繼續(xù)減1 ,那么假設(shè)第m位是1 ,這個(gè)時(shí)候,第m位 變?yōu)? ,第m位以后的位都從0 變1 ,如下
- 這個(gè)時(shí)候1 變多了,如果繼續(xù)減,顯然不能達(dá)到我們目的,我們需要將后面多出來的1 都變成0 ,如下
- 要達(dá)到如上目的,我們想到可以用與,或操作,兩個(gè)都試試,如下:
- 如上與,或,操作都能得到對(duì)應(yīng)的值,但是與原值操作的對(duì)象,我們?cè)趺吹玫侥?#xff0c;我們可以觀察到,與操作中的操作對(duì)象的二進(jìn)制值正好是原數(shù)據(jù)進(jìn)行 -1 操作之前的二進(jìn)制,那么問題就變的很簡單了。
- 我們將以上分析總結(jié):
- 將整數(shù)減去1,在和原整數(shù)做與操作,
- 此時(shí)能將該整數(shù)最右邊一個(gè)1 變成0 ,
- 那么二進(jìn)制表示中有多少個(gè)1 ,就可以進(jìn)行多少次這種操作
- 因此有如下算法
相關(guān)問題
- 用一條語句判斷一個(gè)整數(shù)是不是2 的整數(shù)次方
- 一個(gè)整數(shù)是2 的整數(shù)次方,那么二進(jìn)制表示中必然只有一個(gè)2,而其他所有位都是0
- 同樣依據(jù)解法三,將原數(shù)減1 后得到結(jié)果 ,將結(jié)果與原數(shù)進(jìn)行與操作必然會(huì)變成0
- 輸入兩個(gè)整數(shù)m,n。計(jì)算要改變m的二進(jìn)制表中的多少位才能得到0,。例如10 的二進(jìn)制 1010,與13的二進(jìn)制1101
- 此問題同樣考察位操作,如上案例10, 和13,有三位二進(jìn)制是不同的,我們?nèi)绾瓮ㄟ^二進(jìn)制位操作甄別
- 查看五種位操作,與,或,異或,左右移位,其中異或操作中兩個(gè)二進(jìn)制相同位數(shù)的值為0 ,不同的值為1
- 利用這個(gè)特性, m ^ n 得到一個(gè)值x,我們只需要求解x 中1 的個(gè)數(shù),就得到m與n中不同位數(shù)個(gè)數(shù)。
上一篇:數(shù)據(jù)結(jié)構(gòu)與算法–再談遞歸與循環(huán)(斐波那契數(shù)列)
下一篇:數(shù)據(jù)結(jié)構(gòu)與算法–代碼完整性案例分析
總結(jié)
以上是生活随笔為你收集整理的数据结构与算法--位运算的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iphone怎么取消app跟踪
- 下一篇: 分布式事务 -- seata框架AT模式