按位取反~
即0变为1,1变为0
按位与&
0&0=0,0&1=0,1&0=0,1&1=1
- 用于计算n的二进制表示中最低位1出现的位置
int lowbit(int n){
return n&(-n);
}
//0000 0001 & 0111 1111
//查看某一个数是不是2的平方数
n&(n-1)==0 //等于0表示n为2的平方数
a & b <= min(a,b)
按位与最大的最长子数组
关于负数的二进制问题:
负数的二进制用补码表示:原码取反为反码,反码加一变成补码。
1:
0000 0001
-1:
1000 0001
反码:
0111 1110
补码:
0111 1111
正数的原码、反码、补码相同
实现原理:
负数表示是通过取反再加1的形式,原本为1的取反后都变为0,与加1进行&运算,则得到最低为1出现的位置。
- 计算n的二进制表示中有几个1
int numOfOne(int n){
int count=0;
while(n){
count++;
n=n&(n-1);
}
return count;
}
实现原理:
每一次执行n&(n-1)都会消掉一个“合理的1”
- 用来截取n的最低几位
按位异或^
0^0=1,0^1=0,1^0=0,1^1=1
相同为1,不同为0
- 统计出现个数为奇数个的数字
按位或 |
0|1=1,1|0=1,1|1=1,0|0=0
只要有0出现时结果就是1,否则为0
-
将二进制中的某几位位置为1
n=n|1
将最后一位变成1
左移运算符<<(在补码上面操作)
左移就是将二进制的每一个数都往左移动一位,高位舍去,低位补0
- 左移一位相当于是*2,左移n位,相当于是2的n次方
- 有符号数不完全适用,因为左移有可能导致符号变化
**1<<1**
原码:000000001
第一步:反码:00000001
第二步:补码:00000001
第三步:移动:00000010
第四步:反码:00000010
第五步:原码:00000010
也就是1*(2^1)=2
**-3<<2** 把-3左移两位
原码:10000011
第一步:反码:11111100
第二步:补码:11111101
第三步:移动:11110100(得到的是补码)
第四步:反码:11110011
第五步:原码:10001100
(因为负数的补码是最后+1,所以再往原码转化的时候应该-1)
也就是-3*(2^2)=-12
右移运算符>>(在补码上面操作)
右移就是将二进制的每一个数都往右移动一位,高位的空位补符号位,即正数补零,负数补1,低位舍去
- 右移一位相当于/2
15>>2
原码:00001111
第一步:反码:00001111
第二步:补码:00001111
第三步:移动:00000011
第四步:反码:00000011
第五步:原码:00000011
也就是15/(2^2)=3
-4>>2
原码:10000100
第一步:反码:11111011
第二步:补码:11111100
第三步:移动:11111111
第四步:反码:11111110
第五步:原码:10000001
(因为负数的补码是最后+1,所以再往原码转化的时候应该-1)
也就是-4/(2^2)=-1
应用
- 判断奇偶性
x&1
值为1是奇数,因为奇数的最后一位一定是1 - 获取二进制位是1还是0
- 把1左移到第i位,与x做与运算,就可以得出第i位是1还是0
- 交换两个整型变量的值
- 求整数的绝对值