二进制的探索之旅
一、二进制的特点
1. 逢一进一
- 找了张动图,嵌入进来就变静态了,不理解的手动点进去看吧:[看动图]
-5 = 1111 1011
-4 = 1111 1100
-3 = 1111 1101
-2 = 1111 1110
-1 = 1111 1111
0 = 0000 0000
1 = 0000 0001
2 = 0000 0010
3 = 0000 0011
4 = 0000 0100
5 = 0000 0101
2. 负数最高位为1,正数最高位为0
二、二进制的算法
1. 左位移运算(<<)
左位移:所有位的值向左位移,最左空位(低位)补0
- 左位移1:同等于该十进制值的两倍
- 左位移2:同等于该十进制值的四倍
1 = 0000 0001
2 = 0000 0010
4 = 0000 0100
8 = 0000 1000
16 = 0001 0000
32 = 0010 0000
64 = 0100 0000
128 = 1000 0000
- java实现方式(右位移案例自己脑补)
// 1 = 0000 0001
int num = 1;
// 2 = 0000 0010
System.out.println(num << 1);
// 4 = 0000 0100
System.out.println(num << 2);
// 8 = 0000 1000
System.out.println(num << 3);
// 16 = 0001 0000
System.out.println(num << 4);
// 32 = 0010 0000
System.out.println(num << 5);
// 64 = 0100 0000
System.out.println(num << 6);
// 128 = 1000 0000
System.out.println(num << 7);
2. 右位移运算(>>和>>>)
右位移:所有位的值向右位移,最右空位(高位)补0或补1
>>
识别负数,负数高位补1,正数高位补0
/* 结果-2
1111 1101
>>
1111 1110
*/
System.out.println(-3>>1);
/* 结果-1
1111 1110
>>
1111 1111
*/
System.out.println(-2>>1);
/* 结果-1
1111 1111
>>
1111 1111
*/
System.out.println(-1>>1);
/* 结果0
0000 0001
>>
0000 0000
*/
System.out.println(1>>1);
/* 结果1
0000 0010
>>
0000 0001
*/
System.out.println(2>>1);
/* 结果1
0000 0011
>>
0000 0001
*/
System.out.println(3>>1);
/* 结果2
0000 0100
>>
0000 0010
*/
System.out.println(4>>1);
>>>
不识别负数,高位始终补0
/* 结果为int最大值-1(2147483646)
... 1111 1101
>>>
0... 1111 1110
*/
System.out.println(-3>>>1);
/* 结果为int最大值(2147483646)
... 1111 1110
>>>
0... 1111 1111
*/
System.out.println(-2>>>1);
/* 结果为int最大值(2147483646)
... 1111 1111
>>>
0... 1111 1111
*/
System.out.println(-1>>>1);
// 正数 >> 和 >>> 都一样
System.out.println(4>>>1);
3. 或运算(|)
- 把两个值的各个位数做或运算,其中一个位数的值为1则该位数值为1
/* 结果 12
0000 0100
0000 1000
---------
0000 1100
*/
System.out.println(4 | 8);
/* 结果 9
0000 1000
0000 1001
---------
0000 1001
*/
System.out.println(8 | 9);
/* 结果 13
0000 1001
0000 1100
---------
0000 1101
*/
System.out.println(9 | 12);
4. 与运算(&)
- 把两个值的各个位数做与运算,两个位数的值都为1则该位数值为1
/* 结果 0
0000 0100
0000 1000
---------
0000 0000
*/
System.out.println(4 & 8);
/* 结果 8
0000 1000
0000 1001
---------
0000 1000
*/
System.out.println(8 & 9);
/* 结果 8
0000 1001
0000 1100
---------
0000 1000
*/
System.out.println(9 & 12);
5. 异或运算(^)
- 把两个值的各个位数做异或运算,两个位数值不相同的该位数值为1
/* 结果 12
0000 0100
0000 1000
---------
0000 1100
*/
System.out.println(4 ^ 8);
/* 结果 1
0000 1000
0000 1001
---------
0000 0001
*/
System.out.println(8 ^ 9);
/* 结果 5
0000 1001
0000 1100
---------
0000 0101
*/
System.out.println(9 ^ 12);
功能小demo
通过二进制运算,只需要一个变量 binaryFlag
实现数字是否重复出现的功能(参考数独算法)
public class Demo {
static int binaryFlag = 0;
public static void main(String[] args) {
System.out.println(exist(1));
System.out.println(exist(2));
System.out.println(exist(3));
// 数字重复,返回 false
System.out.println(exist(2));
System.out.println(exist(4));
System.out.println(exist(5));
}
public static boolean exist(int num) {
int n = (1 << num-1)|binaryFlag;
boolean res = n != binaryFlag;
binaryFlag = n;
return res;
}
}
总结
- 二进制的特性和独有的运算方式可用于特殊的算法逻辑(HashMap: 扩容、hash)
- 灵活使用二进制运算可以很好的提高算法效率
>>
和>>>
都是右位移,区别在于>>
会识别负数