位运算:
位运算在c语言和c++中都有。
主要有与,或,异或,移位等运算。
基本规则:
与: 都为1结果为1.
0&1=0; 1&1=1; 0&0=0; 1&0=1
或: 只要其中一个为1,结果就是1
0|1 = 1;0|1=0;1|1=1; 0|0=0
异或: 不同则为1,相同则为0
0 ^ 1 = 1;0 ^ 1=0;1 ^ 1=0; 0 ^ 0=0
移位:
右移: 将整数的二进制表示向右移动n位。
左移: 将整数的二进制表示向右移动n位。
例如:
(1) 00001010(十进制10) -> 00000101(十进制5)
(2) 11111011(十进制 -5) -> 11111101(十进制-3)
值得注意的是,1.位运算只能应用在整数类型上,例如int, unsigned int 等其他类型无法进行移位。
2. 计算机内整数都以补码的形式表示。例如:-5就表示为11111011
3. 右移运算,左边填上符号位,例如(1)中符号位是0,(2)中符号位是1.
4. 左移运算,右边直接填上0;
5. 起到的效果:多看几个例子就知道了:
(3) 00001000(十进制8) -> 00000010(十进制2) 右移2位
(4) 11111001(十进制-8)-> 11111100(十进制-4) 右移1位
(5) 00000101(十进制5) -> 00000010(十进制2) 右移1位
(6) 11110111(十进制-5) -> 11111011(十进制-3) 右移1位
效果是右移1次就是相当于除2,左移一次就是相当于乘2.
要注意的是,如果是左移,那么正负数都是一样乘2,结果也是整数。
但是如果是除2,一个整数除2有可能会变成小数,例如5/2=2.5,那么怎么规整呢:
在c++中:
cout << -5 / 2; // 结果是 -2
cout << 5 / 2; // 结果是 2
向0靠近。
但是在这里:
cout << (5 >> 1); // 结果是 -2
cout << (-5 >> 1);// 结果是 -3
向数轴的左边靠近。具体原因看(5)(6)式子。
一些技巧:
在一些算法题,例如剑指offer,leetcode中会用到一些位运算的技巧,
这里顺便记录一下:
1. 多个位进行异或计算:
0&1&1&1&1&0 = 0
1&0&1&0&1&0 = 1
如有奇数个1结果为1,如有偶数个1结果为0;
2.去掉二进制表示中最后一个1
n = 00010100
n = n -1 = 00010011
n&(n-1) = 00010000(去掉最后一个1)
如果这个操作一直循环下去,能够一步一步把1去掉,直到结果为0,刚好可以用来统计1的个数。