算法-二进制
某种程度上讲,二进制也算一种算法?
前言
二进制从定义上讲只是一种数字表示方式。
与你们人类使用的十进制不同,二进制表示法中只有0和1两个数位。
例如,十进制下的 在二进制下就表示为 (注:所有二进制数均省略二进制表示法)。
十进制转换为二进制
二的幂分解
首先需要了解常用的二进制整数(即 的幂):。
对于一个十进制数,从大到小分解:,所以就表示为 。
倒序取余
这个方法更常用一些,但是原理不容易理解。具体操作过程如下:
- 对于一个数 ,取它除以 的商 和余数 。
- 对得到的 重复第一步操作,得到商 和余数 。
- 重复操作至商 。
- 找到所有余数 (共 个余数)。
- 将余数倒序书写:,得到的就是 的二进制表示法。
二进制转换为十进制
例如一个二进制数是 ,从右到左依次是第 位。
所以,十进制表示法就是:
补码表示法
为了使用0和1表示负数,我们使用补码表示法。
具体是这样的: 在二进制(一个字节)中是 ,为使 ,只需要让 用 表示(忽略溢出位)即可。
对于任意的一个正数,对其取反再加 就得到了对应负数的补码表示法。
那么反过来,一个负数先减 再取反就是对应的正数。
位操作/位运算
接下来进入程序部分!
首先,定义两个二进制数。
1 | int a = 0b11010; |
对于一般的编程语言,常见的位运算包括:
-
与:两个数都为 时,结果才为 。
1
2
3
4
5
6
7
8// Hint:
/*
11010
& 110100
--------
110000
*/
ans = a & b; // 0b110000 -
或:两个数只要有一个数为 ,结果就为 。
1
2
3
4
5
6
7
8// Hint:
/*
11010
| 110100
--------
111110
*/
ans = a | b; // 0b111110 -
非: 变成 , 变成 ,即取反。
int具有 个二进制位,需要把所有的 都取反!1
2
3
4
5
6
7// Hint:
/*
~ 00000000 00000000 00000000 00011010
--------------------------------------
11111111 11111111 11111111 11100101
*/
ans = ~a; // 0b11111111111111111111111111100101思考:如果
a的类型是short或者long long,结果会有不同吗? -
异或:两个数相同的时候结果为 ,不同则为 (最常用)。
1
2
3
4
5
6
7
8// Hint:
/*
11010
^ 110100
--------
101110
*/
ans = a ^ b; // 0b101110 -
左移:将数字整体左移 位(注意:不要让它溢出!)
1
2
3
4
5
6
7
8
9
10
11
12
13
14// Hint:
/*
11010 <- 0
---------
110100
*/
ans = a << 1; // 0b110100
// Hint:
/*
11010 <- 000
------------
110100000
*/
ans = a << 3; // 0b110100000 -
右移:将数字整体右移 位。
1
2
3
4
5
6
7
8
9
10
11
12
13
14// Hint:
/*
0 -> 11010
---------
1101
*/
ans = a >> 1; // 0b1101
// Hint:
/*
000 -> 11010
---------
11
*/
ans = a >> 3; // 0b11