日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与算法--位运算

發(fā)布時(shí)間:2023/12/4 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--位运算 小編覺得挺不錯(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ì)有一些奇奇怪怪的問題,比如下面這種:
/**在Excel中,用A表示第一列,B表示第二列......Z表示第26 列,AA表示27 列,AB表示28列......以此類推那么我們用一個(gè)函數(shù),輸入字母,輸出列的編碼是多少號(hào)*/ /*** @author liaojiamin* @Date:Created in 16:30 2021/3/17*/ public class NumberOfBit {//字母轉(zhuǎn)數(shù)字 A-Z :1-26public static int letterToNumber(char letter) {int num = (int)(letter - 'A' + 1) ;return num;}public static Long base26(String baseStr){if(baseStr == null){return -1L;}char[] charArray = baseStr.toCharArray();Long baseNumber = 26L;Long resultNum = 0L;double position = 0;for (int i = charArray.length -1; i >=0; i--) {Double temp = Math.pow(baseNumber, position) * letterToNumber(charArray[i]);resultNum += temp.longValue();position++;}return resultNum;}public static void main(String[] args) {System.out.println(base26("AA"));System.out.println(base26("AB"));System.out.println(base26("AZ"));System.out.println(base26("ZZ"));System.out.println(base26("AAA"));} }
  • 如上其實(shí)就是講A~Z理解成一個(gè)26進(jìn)制,只要理解了二進(jìn)制的計(jì)算規(guī)則,26進(jìn)制也是同樣的算法。
  • 二進(jìn)制中位運(yùn)算也就只有五種與, 或,異或,左移,右移。前三種用如下規(guī)則
與(&):0&0 = 01&0 = 00&1 = 01&1=1 或(|):0|0 = 01|0 = 1. 0|1=11|1 = 1 異或(^):0^0 = 01^0=10^1=11^1 = 0

-左移運(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ù)值做右移操作
0000 1010 >>2 == 0000 0010 1000 1010 >>3 = 1111 0001
具體案例分析
  • 題目:實(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 為案例如下:
1001 & 1 = 1 1001 >> 1 = 0100 0100 & 1 = 0 0100 >> 1 = 0010 0010 & 1 = 0 0010 >> 1 = 0001 0001 & 1 = 1 0001 >> 1 = 0000
  • 以上我們可以得到如下代碼:
/*** 正整數(shù)n 二進(jìn)制表示中 1 的個(gè)數(shù)* */public static int numberOf1(int n){int count = 0;while (n > 0){int andOne = n & 1;if(andOne == 1){count ++;}n = n>>1;}return count;}
  • 問題,以上代碼都只考慮正數(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):
/*** 通用二進(jìn)制表示中 1 個(gè)數(shù)* */public static int numberOf1_1(int n){int count = 0;int flag = 1;while (flag > 0){if((n & flag) > 0){count ++;}flag = flag << 1;}return count;}
  • 以上算法能統(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)于最后一位取反。例子:
0000 1000 0010 0000 0110 0000 0000 0001 - 1 = 0000 1000 0010 0000 0110 0000 0000 0000
  • 此時(shí)我們只能判斷出第一位是不是1,此時(shí)我們還繼續(xù)減1 ,那么假設(shè)第m位是1 ,這個(gè)時(shí)候,第m位 變?yōu)? ,第m位以后的位都從0 變1 ,如下
0000 1000 0010 0000 0110 0000 0000 0000 - 1 = 0000 1000 0010 0000 0101 1111 1111 1111
  • 這個(gè)時(shí)候1 變多了,如果繼續(xù)減,顯然不能達(dá)到我們目的,我們需要將后面多出來的1 都變成0 ,如下
0000 1000 0010 0000 0101 1111 1111 1111 --> 0000 1000 0010 0000 0100 0000 0000 0000
  • 要達(dá)到如上目的,我們想到可以用與,或操作,兩個(gè)都試試,如下:
//或操作 0000 1000 0010 0000 0101 1111 1111 1111 | 0000 1000 0010 0000 0100 0000 0000 0000 = 0000 1000 0010 0000 0100 0000 0000 0000 //與操作 0000 1000 0010 0000 0101 1111 1111 1111 & 0000 1000 0010 0000 0110 0000 0000 0000 = 0000 1000 0010 0000 0100 0000 0000 0000
  • 如上與,或,操作都能得到對(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)行多少次這種操作
    • 因此有如下算法
public static int numberOf1_2(int n){int count = 0;while (n != 0){n = n&(n-1);if(n != 0){count ++;}}return count;}
相關(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。