[面试题] 位运算

1.判断一个数是否是2的幂次?

 (number & number - 1) == 0

 原因:因为2的N次方换算是二进制为10……0这样的形式(0除外)。与上自己-1的位数,这们得到结果为0。例如。8的二进制为1000;8-1=7,7的二进制为111。两者相与的结果为0。

 

1 public static boolean checkPow(int x) {
2         return ((x & (x - 1)) == 0);
3     }

 

2.求一个数n的二进制中1的个数?

非常巧妙地利用了一个性质,n=n&(n-1) 能移除掉n的二进制中最右边的1的性质,循环移除,直到将1全部移除,这种方法将问题的复杂度降低到只和1的个数有关系

1 public static int numOfOne(int x) {
2         int count = 0;
3         while(x != 0){
4             x &= x - 1;
5             count++;
6         }
7         return count;
8     }

http://blog.csdn.net/hackbuteer1/article/details/6681157

3.给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变多少位(bit)?也就是说,整数A和B的二进制表示中有多少位是不同的?

举例说明,为了减少复杂度,就使用八位二进制吧。设 A = 0010 1011, B = 0110 0101.
1. C = A & B = 0010 0001;
2. D = A | B = 0110 1111;
3. E = C ^ D = 0100 1110;
4. 结果E中有4个1,那么也就是说将A变成B,需要改变4位(bit)。
至于如何判断E的二进制表示中有几个1,可以采用快速移位与方法。
算法原理如下:
1. A & B,得到的结果C中的1的位表明了A和B中相同的位都是1的位;
2. A | B, 得到的结果D中的1的位表明了A和B在该位至少有一个为1的位,包含了A 与 B 都是1的位数,
经过前两步的位运算,,C 中1的位表明了A 和 B在该位都是1,D中为0的位表明了A 和 B 在该位都是0 ,所以进行第三步。
3. C ^ D,E 中为1的位表明了A 和 B不同的位。

 1 #include<iostream>
 2 using namespace std;
 3 int getNum(int n)
 4 {
 5     if(n==0) return 0;
 6     int count=0;
 7     while(n)
 8     {
 9         n&=(n-1);
10         count++;
11     }
12     return count;
13 } 
14 int main()
15 {
16     int A=43,B=101;
17     int C=A&B;
18     int D=A|B;
19     int E=C^D;
20     cout<<getNum(E)<<endl;
21     system("pause");
22     return 0;
23 }

http://www.cnblogs.com/sooner/archive/2013/04/02/2994940.html

4.快速判断一个数是否是4的幂次方,若是,并判断出来是多少次方?

将4的幂次方写成二进制形式后,很容易就会发现有一个特点:二进制中只有一个1(1在奇数位置),并且1后面跟了偶数个0; 因此问题可以转化为判断1后面是否跟了偶数个0就可以了。

       4的整数次幂的二进制数都为 (4)100、(16)10000、(64)1000000......

        另外,4的幂次方4^n也可以写为2^(2*n),即也可以写为2的幂次方,当然就满足2的幂次方的条件了,即num & num-1==0。

        思路:首先用条件num & num-1==0来判断是否为2的幂次方,若不满足,则不是。若满足,在用条件num & 0x55555555来判断,若为真,则这个整数是4的幂次方,否则不是。

 1 bool fn(unsigned int x)      //判断x是否是4的幂次方
 2 {
 3   if ( x & (x - 1) )         //判断x是否为2的幂次方
 4       return false;
 5   return x & 0x55555555;     //判断1是否在奇数位置上
 6 }
 7 
 8 int log4(int value)      //递归判断一个数是4的多少次方
 9 {
10     if (value == 1)
11         return 0;
12     else
13     {
14         value>>=1;       //往右移位
15         return 1+log4(value>>1);       //往右移位
16     }
17 }

 5. 将一个整数的所有bit反转?

The XOR swap trick:
Reversing bits could be done by swapping the n/2 least significant bits with its most significant bits. The trick is to implement a function called swapBits(i, j), which swaps the ith bit with the jth bit. If you still remember how XOR operation works: 0 ^ 0 == 0, 1 ^ 1 == 0, 0 ^ 1 == 1, and 1 ^ 0 == 1.

We only need to perform the swap when the ith bit and the jth bit are different. To test if two bits are different, we could use the XOR operation. Then, we need to toggle both ith and jth bits. We could apply the XOR operation again. By XOR-ing the ith and jth bit with 1, both bits are toggled.

 1 typedef unsigned int uint;
 2 uint swapBits(uint x, uint i, uint j) {
 3   uint lo = ((x >> i) & 1);
 4   uint hi = ((x >> j) & 1);
 5   if (lo ^ hi) {
 6     x ^= ((1U << i) | (1U << j));
 7   }
 8   return x;
 9 }
10  
11 uint reverseXor(uint x) {
12   uint n = sizeof(x) * 8;
13   for (uint i = 0; i < n/2; i++) {
14     x = swapBits(x, i, n-i-1);
15   }
16   return x;
17 }

The run time complexity using the XOR trick to reverse bits is O(n), where n is the total number of bits in an unsigned integer.

The divide and conquer approach:
Remember how merge sort works? Let us use an example of n == 8 (one byte) to see how this works:

      01101001
    /         \
   0110      1001
  /   \     /   \
 01   10   10   01
 /\   /\   /\   /\
0 1  1 0  1 0  0 1

The first step is to swap all odd and even bits. After that swap consecutive pairs of bits, and so on…

Therefore, only a total of log(n) operations are necessary.

The below code shows a specific case where n == 32, but it could be easily adapted to larger n‘s as well.

1 uint reverseMask(uint x) {
2   assert(sizeof(x) == 4); // special case: only works for 4 bytes (32 bits).
3   x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);
4   x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);
5   x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4);
6   x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8);
7   x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16);
8   return x;
9 }

 

posted @ 2013-10-09 16:38  feiling  阅读(382)  评论(0编辑  收藏  举报