位运算:是把数字用二进制表示之后,对每一次是0或1的运算。
乘除效率低,实际编程中尽可能的用移位运算代替乘除法。
世界上有10中人,一种人知道二进制,而另一种人不知道二进制……
五种位运算:与、或、异或、左移和右移,分别对应&、 |、 ^、<<、 >>。
异或:相同为0, 相异为1。
左移运算符m左移n,表示把m左移n位, 最左边的n位将被丢弃。
右移要复杂些,右移时处理最左边位: 如果数字是一个无符号数值,则用0填补最左边的n位。 如果数字是一个有符号数值, 则用数字的符号位填补最左边的n位; 即如果数字原先是正数,则用数字的右移之后最左边补n个0; 若为负数补n个1。
求二进制中1的个数
题目描述:实现一个函数, 输入一个整数,输出该二进制表示中1的个数。 例如把9表示成二进制是1001, 有2位是1。因此如果输入9, 则函数输出2。
解题思路:
- 将n与0001进行或操作,为true则计数,否则右移1位,知道n为0。此方法如果输入是负数, 容易造成死循环。
- 解法1:我们不采用上面的方法。而是使用一个标记,初始化为1,对1做左移,然后与n做与&操作。知道1为0,这种解法的循环次数等于整数二进制的位数。即32位二进制循环32次。
- 解法2:此方法可以在有几个1的情况下就循环几次。原理:把一个整数减去1,再和原来整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制表示中有多少个1, 就可以进行多少次这样的操作。
测试用例:
int main(){
//整数
int number = 9;
//1的个数
int counts = 0;
//结果
counts = NumberOf1(number); //使用解法2
//输出结果
std::cout << counts; //Output: 2
return 0;
}
解法1函数实现:
int numberOf1(int number){
int counts = 0;
unsigned int flag = 1;
while(flag){
if(number & flag) //不断和左移后的1做位与操作, 为真(1)便计数
++counts;
flag = flag << 1; //32位就需要循环32次!!!
}
return counts;
}
解法2函数实现:
int NumberOf1(int number){
int counts = 0;
while(number){ //原理:将整数每次减一后与原整数做位与操作
++counts;
number = (number - 1) & number;
}
return counts;
}
总结:把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0。很多二进制的问题都可以用这个思路解决。
相关题目:用一条语句判断一个整数是不是2的整数次方。我们可以将这个整数减1再与原整数做与运算,如果值为0代表是2的整数次方,否则不是。
//判断一个整数是不是2的整数次方
bool numberOfSquare(int num){
if(!( (num - 1) & num)) //对结果取反
return true; //是2的整数次方就返回true
else
return false;
}