javascript
JavaScript 位运算总结拾遗
最近補充了一些位運算的知識,深感位運算的博大精深,此文作為這個系列的總結(jié)篇,在此回顧下所學(xué)的位運算知識和應(yīng)用,同時也補充下前文中沒有提到的一些位運算知識。
把一個數(shù)變?yōu)榇笥诘扔谠摂?shù)的最小的2的冪
一個數(shù)為2的冪,那么該數(shù)的二進制碼只有最高位是1。
根據(jù)這個性質(zhì),我們來舉個栗子,比如有數(shù)字10,轉(zhuǎn)為二進制碼后為:
1 0 1 0我們只需把 0 bit的位置全部用1填充,然后再把該二進制碼加1就ok了。而x | (x + 1)正好可以把最右邊的0置為1,可是問題來了,當(dāng)二進制碼變成 1 1 1 1后,我們無法判斷二進制碼已經(jīng)全是1了,繼續(xù)操作的話會變成1 1 1 1 1,于是,該法失敗...
我們可以采用類似迭代的方法,又有點分組的意思。因為最高位肯定是1,我們把init的數(shù)右移一位,和原數(shù)作與運算,這樣就能把次高位也置為1,然后繼續(xù)右移,這時最前面兩位都是1了,右移兩位后,做與運算,這時前四位都是1了:
function change2Pow(n) {if(!(n & (n-1)) && n > 0) return n;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return n + 1; }計算二進制中1的個數(shù)
leetcode中有一道這樣的題目-Number of 1 Bits,正好拿來驗證程序的正確性。
常規(guī)解法不用多說,直接上代碼:
var hammingWeight = function(n) {var ans = 0;while (n) {ans += n & 1;n >>>= 1;}return ans; };因為題目中有說是unsigned int32的整數(shù),所以要用有符號右移>>>來操作符號位。
位運算解法和求逆序一樣,也采用分組的思想。
我們以16位下的12345舉例(6個1),先寫出它的二進制碼表示:
0011000000111001第一步:每兩個為一組,組內(nèi)高低位相加
00 10 00 00 00 10 01 01第二步:每四個為一組,組內(nèi)高低位相加
0010 0000 0010 0010第三步:每8個為一組,組內(nèi)高低位相加
00000010 00000100第四步,每16個為1組,組內(nèi)高低位相加
0000000000000110最后得到的數(shù)字6即為12345二進制碼中1的個數(shù)。而實際中,因為int32是32位的,所以一共要進行5步。求解思路和求逆序類似,逆序是要交換,所以要分別左移右移,而求1的個數(shù)是相加,所以只需移動一次就夠了。
完整代碼:
var hammingWeight = function(n) {n = ((n & 0xAAAAAAAA) >>> 1) + (n & 0x55555555);n = ((n & 0xCCCCCCCC) >>> 2) + (n & 0x33333333);n = ((n & 0xF0F0F0F0) >>> 4) + (n & 0x0F0F0F0F);n = ((n & 0xFF00FF00) >>> 8) + (n & 0x00FF00FF);n = ((n & 0xFFFF0000) >>> 16) + (n & 0x0000FFFF);return n; };因為是unsigned int32,所以要用>>>如前所述。
再次擊敗100%的JavaScript code...
計算二進制中1的個數(shù)的奇偶性
我們可以先計算1的個數(shù),然后再判斷奇偶。當(dāng)然既然作為一道獨立的題目,肯定有更簡便的方法。
整個過程可以用分治來解。第1步統(tǒng)計相鄰2位的1的個數(shù)奇偶性,保存到這2位的低位中。第2步統(tǒng)計相鄰4位的1的個數(shù)奇偶性,保存到這4位的低位中。……第5步統(tǒng)計相鄰2位的1的個數(shù)奇偶性,保存到這32位的低位中,即x的最低位。
function bit1OddEven(x){ //奇數(shù)個為1,偶數(shù)個為0x ^= x >>> 1; //相鄰 2位中1的奇偶性x ^= x >>> 2; //相鄰 4位中1的奇偶性x ^= x >>> 4; //相鄰 8位中1的奇偶性x ^= x >>> 8; //相鄰16位中1的奇偶性x ^= x >>> 16; //相鄰32位中1的奇偶性return x & 1; }統(tǒng)計二進制前導(dǎo)0、末尾0的個數(shù)
先排除為0的特殊情況。然后先看前16位是否全0,如果全0,增加計數(shù),并把這個數(shù)左移16位刪除已經(jīng)計數(shù)的16個0。然后看前8位是否全0。一直到只剩一位時可以直接計算。整個過程的核心是二分思想。
統(tǒng)計末尾0的個數(shù)時思想類似,只是變成了統(tǒng)計后面16位、8位等是否全0。
function countLeading0(x) {if (!x) return 32;var n = 1;if ((x >>> 16) == 0) n += 16, x <<= 16;if ((x >>> 24) == 0) n += 8, x <<= 8;if ((x >>> 28) == 0) n += 4, x <<= 4;if ((x >>> 30) == 0) n += 2, x <<= 2;return n - (x >>> 31); }function countTrailing0(x) {if (!x) return 32;var n = 1;if ((x << 16) == 0) n += 16, x >>>= 16;if ((x << 24) == 0) n += 8, x >>>= 8;if ((x << 28) == 0) n += 4, x >>>= 4;if ((x << 30) == 0) n += 2, x >>>= 2;return n - (x & 0x01); }當(dāng)然計算末尾0的個數(shù),我們也可以這樣:
function countTrailing0(a) {return Math.log(a & (-a)) / Math.LN2; }這個系列暫時結(jié)束了,但我知道對于位運算的學(xué)習(xí),這只是起點。
附位運算系列目錄:
總結(jié)
以上是生活随笔為你收集整理的JavaScript 位运算总结拾遗的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: github中origin和upstre
- 下一篇: yii2-按需加载并管理CSS样式/JS