看到剑指Offer中二进制中1的个数这个题目,才感觉到位运算的强大。原来整数不用换成二进制,遇到位运算符会自动变成二进制进行计算。所以当输入的数为负数时,也不用考虑负数的表示问题,因为在进行二进制运算时,系统会自动将其以补码形式表示。
num & 1 为真则说明num是奇数,为0则说明num是偶数
例如二进制:num = 0110 1011 中含有多少个1呢,当num & 0000 0001 结果为1说明num右边第一位为1,当num & 0000 0010 结果为1,说明右边数第二位也为1;
所以定义 int flag = 1;flag << 1左移一位与num进行与计算 判断二进制每一位是否为1,当flag结果为0时,循环结束
具体代码如下所示:
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
int flag = 1;
while(flag)
{
if(n&flag)
count++;
flag = flag << 1;
}
return count;
}
};
位运算的优先级:
下面列举了一些常见的二进制位的变换操作。
功能 | 示例 | 位运算
----------------------+---------------------------+--------------------
去掉最后一位 | (101101->10110) | x>>1
在最后加一个0| (101101->1011010) | x<<1
在最后加一个1| (101101->1011011) | x<<1+1
把最后一位变成1| (101100->101101) | x|1
把最后一位变成0| (101101->101100) | x| 1-1
最后一位取反 | (101101->101100) | x^ 1
把右数第k位变成1 | (101001->101101,k=3) | x|(1<< (k-1))
把右数第k位变成0 | (101101->101001,k=3) | x& ~(1<<(k-1))
右数第k位取反 | (101001->101101,k=3) | x^(1 shl (k-1))
取末三位 | (1101101->101) | x&7
取末k位 | (1101101->1101,k=5) | x&(1<<(k-1)
取右数第k位 | (1101101->1,k=4) | x>>(k-1)&1
把末k位变成1| (101001->101111,k=4) | x|(1<<k-1)
末k位取反| (101001->100110,k=4) | x^ (1<<k-1)
把右边连续的1变成0 | (100101111->100100000) | x&(x+1)
把右起第一个0变成1 | (100101111->100111111) | x| (x+1)
把右边连续的0变成1 | (11011000->11011111) | x| (x-1)
取右边连续的1 | (100101111->1111) | (x^ (x+1))>>1
去掉右起第一个1的左边| (100101000->1000) | x&(x^(x-1))(或x&(-x))