二进制整数中的“1”

这里主要通过一些位运算的技巧来找出一个整数的二进制表示中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

posted @ 2015-07-12 22:25  william-cheung  阅读(568)  评论(0编辑  收藏  举报