有趣的位运算
编程中逻辑运算是再常见不过了,针对二进制的逻辑运算是位运算(bitwise-operations),使用位运算经常可以实现一些非常geek的操作。
取反(NOT)
1变0,0变1
NOT 0111
= 1000
取反可以用于翻转,比如对于一个无符号的8位整数,表示范围是0-255
a = 100, 则~a = 155,也就是255-100=155
符号取反,正数变成负数,负数变成正数
a = 7, ~a+1 = -7
本来求补码符号位不参与,但是这里取反+1正数正好变成负数的补码表示
与(AND)
两个都是1则取1,否则为0
0101 (decimal 5)
AND 0011 (decimal 3)
= 0001 (decimal 1)
按位与经常用作标志位或者掩码
因为二进制的最后一个为0是偶数,1为奇数,所以
if (0 == a & 1) {
//偶数
}
ip地址掩码确定网络号
255.255.255.0 & 192.168.1.3
或(OR)
只要有1则为1,否则为0
0001 (decimal 1)
OR 0010 (decimal 2)
= 0011 (decimal 3)
按位或可以用于组合标志位,比如提取分量后用来组合
异或 (XOR)
相同则为0,不同则为1
0101 (decimal 5)
XOR 0011 (decimal 3)
= 0110 (decimal 6)
最经典就是不使用第三个变量来交换a,b的值
a = 5; b=3;
a ^= b
b = a ^ b
a ^= b
一个无序数组有一个唯一的数,其它都是2个数,如何找出唯一的那个数?如[1,2,3,2,3]
因为x ^ x = 0, x ^ 0 = x, x ^ y ^ z = x ^ (y ^ z),所以依次把每个数xor运算最后就可以得到唯一的一个数
移位 (SHIFT)
左移一位表示乘 2,右移一个表示 除2
00010111 (decimal +23) LEFT-SHIFT
= 00101110 (decimal +46)
10010111 (decimal −105) RIGHT-SHIFT
= 11001011 (decimal −53)
可以用来进行2、4、8的整除
位运算应用例子
1. 判断n是否是2的幂
n & (n-1) == 0
2. 高低字节交换
对于一个无符号的16位数
unsigned short a = 12345;
a = a >> 8 | (a & 0x00FF) << 8); //14640
3. 颠倒给定的 32 位无符号整数的二进制位
00000010100101000001111010011100 => 00111001011110000010100101000000
1 | function reverseBits(n: number): number { |
4. 无符号整数中位数为1的个数 (汉明重量)
1 | function hammingWeight(n: number): number { |
n & n-1 每次会把n的最后一位1变成0
更有o(1)的算法可以体会位运算的强大
1 | function hammingWeight(n: number): number { |