標籤:
這裡主要通過一些位元運算的技巧來找出一個整數的二進位表示中1的個數或其中某些特殊的1的位置。
1 的個數
求二進位表示中1的個數存在時間複雜度為O(n)(n為1的個數)的演算法。 其要點是 若整數 x 不為0, 運算式(指C語言運算式) x&(x-1) 的運算結果是將 x 的二進位表示中最右側的1消除後的值, 若x為0, 運算式的值為0。 這樣, 若 x 不為0, 我們就可以通過運算式 x = x&(x-1) 反覆消除 x 最右側的1直到x為0, 消除的次數即為所求1的個數。
C語言代碼(輸入為32位無符號整型)
1 int number_of_ones(uint32_t x) {2 int result = 0;3 while (x) {4 x = x & (x - 1);5 result++;6 }7 return result;8 }
最右側1的位置
最右側1的位置通過運算式 x ^ (x & (x-1))計算, 如, x: 0x12345678, x ^ (x & (x-1)) : 0x00000008
1 uint32_t right_most_one(uint32_t x) {2 return x ^ (x & (x - 1));3 }
最左側1的位置
求最左側1的位置相對比較複雜, 下面是一種比較直接的演算法。
1 uint32_t left_most_one(uint32_t x) {2 uint32_t test = x & (x - 1);3 while (test) {4 x = test;5 test = x & (x - 1);6 }7 return x;8 }
在Java ArrayDeque 的 allocateElements 源碼中看到一種比較有意思的演算法, 它用來計算大於一個數的2的整數次冪。 我們可以對所求2的次冪按位右移一位來求最左側1的位置。
下面給出原始碼 ps: 自行思考一下演算法的原理 :)
1 uint32_t left_most_one2(uint32_t x) { 2 uint32_t tmp = x; 3 tmp |= (tmp >> 1); 4 tmp |= (tmp >> 2); 5 tmp |= (tmp >> 4); 6 tmp |= (tmp >> 8); 7 tmp |= (tmp >> 16); 8 tmp++; 9 return tmp ? (tmp >> 1) : (0x80000000);10 }
參考
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayDeque.java
二進位整數中的“1”