第19章 位运算与进制转换
内容已经涵盖了“第19章 位运算与进制转换”的核心知识点与典型例题,结构清晰、代码完整,非常适合作为教学笔记或学生自学资料。我可以帮你进一步优化下排版、提炼重点、补充解释或练习题,以下是一个 清晰有条理的重构建议版本:
第19章 位运算与进制转换
1. 进制转换
1.1 十进制整数转其他进制(如16进制)
例:
\((114514)_{10} = (BF52)_{16}\)
方法:除基取余法
- 每次对目标进制取余,记录余数。
- 将余数反向输出就是转换结果。

1.2 任意进制间转换例题
P1143 进制转换
P1143 进制转换
题目描述
请你编一程序实现两种不同进制之间的数据转换。
输入格式
共三行,第一行是一个正整数,表示需要转换的数的进制 \(n\ (2\le n\le 16)\),第二行是一个 \(n\) 进制数,若 \(n>10\) 则用大写字母 \(\verb!A!\sim \verb!F!\) 表示数码 \(10\sim 15\),并且该 \(n\) 进制数对应的十进制的值不超过 \(10^9\),第三行也是一个正整数,表示转换之后的数的进制 \(m\ (2\le m\le 16)\)。
输出格式
一个正整数,表示转换之后的 \(m\) 进制数。
输入输出样例 #1
输入 #1
16
FF
2
输出 #1
11111111
✅ 方法一(C++)
#include<bits/stdc++.h>
using namespace std;
int char_to_int(char a) {
return isdigit(a) ? a - '0' : a - 'A' + 10;
}
char int_to_char(int a) {
return a < 10 ? a + '0' : a - 10 + 'A';
}
int main() {
int n, m, dec = 0, num = 0;
string input;
int output[33];
cin >> n >> input >> m;
for(char ch : input) dec = dec * n + char_to_int(ch);
while(dec) {
output[num++] = dec % m;
dec /= m;
}
for(int i = num - 1; i >= 0; i--)
cout << int_to_char(output[i]);
cout << endl;
return 0;
}
1.3 十进制负数转二进制(补码)
| 类型 | 正数 | 负数 | 0 |
|---|---|---|---|
| 原码 | 符号位 0,数值位直接表示 | 符号位 1,数值位直接表示 | +0(0000...)和 -0(1000...) |
| 反码 | 与原码相同 | 符号位不变,其余位取反 | +0(0000...)和 -0(1111...) |
| 补码 | 与原码、反码相同 | 反码 + 1 | 唯一表示 0000... |
总结记忆口诀
正数:三码(原码、反码、补码)合一,直接表示。
负数:
原码:符号位为 1,数值位直写。
反码:符号位不变,数值位取反。
补码:反码加 1,符号位参与运算。
例: $-20$
- 原码(8位):
10010100 - 反码(首位不变,其它取反):
11101011 - 补码(反码+1):
11101100
1.4 十进制小数转二进制
方法: 小数部分不断乘以 2,取整数部分。
例:
\((3.14)_{10} = (11.00100011...)_2\)
\((0.8125)_{10} = (0.1101)_2\)

1.5 十进制数转负进制
注意: 余数可能为负,需调整:
while(input != 0) {
int k = input % r;
int c = input / r;
if (k < 0) {
k -= r;
c++;
}
input = c;
output[num++] = k;
}
2. 位运算(C/C++)
位运算是对二进制位直接进行操作的运算方式。
2.1 按位与 &
- 同真为真(1 & 1 = 1)
2.2 按位或 |
- 一真为真(1 | 0 = 1)
2.3 按位异或 ^
- 相同为0,不同为1
- 性质:
a ^ b ^ a = b(常用于找唯一一个出现奇数次的数)
2.4 取反 ~
~a相当于对所有二进制位取反(有符号数会变成负数)
2.5 左移 <<
a << n相当于a × 2^n
2.6 右移 >>
a >> n相当于a ÷ 2^n
3. 典型练习
3.1 高低位交换(16位)
P1100 高低位交换
P1100 高低位交换
题目描述
给出一个小于 \(2^{32}\) 的非负整数。这个数可以用一个 \(32\) 位的二进制数表示(不足 \(32\) 位用 \(0\) 补足)。我们称这个二进制数的前 \(16\) 位为“高位”,后 \(16\) 位为“低位”。将它的高低位交换,我们可以得到一个新的数。试问这个新的数是多少(用十进制表示)。
例如,数 \(1314520\) 用二进制表示为 \(0000\,0000\,0001\,0100\,0000\,1110\,1101\,1000\)(添加了 \(11\) 个前导 \(0\) 补足为 \(32\) 位),其中前 \(16\) 位为高位,即 \(0000\,0000\,0001\,0100\);后 \(16\) 位为低位,即 \(0000\,1110\,1101\,1000\)。将它的高低位进行交换,我们得到了一个新的二进制数 \(0000\,1110\,1101\,1000\,0000\,0000\,0001\,0100\)。它即是十进制的 \(249036820\)。
输入格式
一个小于 \(2^{32}\) 的非负整数
一个小于 \(2^{32}\) 的非负整数。
输出格式
将新的数输出
将新的数输出。
输入输出样例 #1
输入 #1
1314520
输出 #1
249036820
unsigned int n;
cin >> n;
cout << ((n << 16) + (n >> 16)) << endl;
3.2 负进制转换(如 base -2)
#include<bits/stdc++.h>
using namespace std;
char int_to_char(int a) {
return a <= 9 ? '0' + a : a - 10 + 'A';
}
int main() {
int output[105], input, r, num = 0;
cin >> input >> r;
cout << input << "=";
while(input) {
int k = input % r;
int c = input / r;
if(k < 0) {
k -= r;
c++;
}
input = c;
output[num++] = k;
}
for(int i = num - 1; i >= 0; i--) cout << int_to_char(output[i]);
cout << "(base" << r << ")" << endl;
}
3.3 找筷子(异或找只出现一次的数)
P1469 找筷子(位运算)异或的性质
P1469 找筷子
题目描述
经过一段时间的紧张筹备,电脑小组的“RP 餐厅”终于开业了,这天,经理 LXC 接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题:筷子!
CX 小朋友找出了餐厅中所有的筷子,但遗憾的是这些筷子长短不一,而我们都知道筷子需要长度一样的才能组成一双,更麻烦的是 CX 找出来的这些筷子数量为奇数,但是巧合的是,这些筷子中只有一只筷子是落单的,其余都成双,善良的你,可以帮 CX 找出这只落单的筷子的长度吗?
输入格式
第一行是一个整数,表示筷子的数量 \(n\)。
第二行有 \(n\) 个整数,第 \(i\) 个整数表示第 \(i\) 根筷子的长度 \(a_i\)。
输出格式
输出一行一个整数表示答案。
输入输出样例 #1
输入 #1
9
2 2 1 3 3 3 2 3 1
输出 #1
2
说明/提示
数据规模与约定
- 对于 \(30\%\) 的数据,保证 \(n \leq 10^5\)。
- 对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 10^7 + 1\),\(1 \leq a_i \leq 10^9\)。
提示
- 请注意数据读入对程序效率造成的影响。
- 请注意本题的空间限制为 \(4\) Mb。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, x, ans = 0;
cin >> n;
while(n--) {
cin >> x;
ans ^= x;
}
cout << ans << endl;
}
八进制转十六进制的步骤总结(以(3703)₈为例)
方法一:八进制 → 二进制 → 十六进制
步骤1:将八进制每位转换为3位二进制
八进制的每1位对应二进制的3位:
3→0117→1110→0003→011
拼接后得到二进制数:
011 111 000 011 → 即 0111 1100 0011(按4位分组)
步骤2:将二进制按4位分组,转换为十六进制
每4位二进制对应1位十六进制:
0111→71100→C0011→3
最终结果:(3703)₈ = (7C3)₁₆
方法二:八进制 → 十进制 → 十六进制
步骤1:八进制转十进制
按权展开求和:
[
3 \times 8^3 + 7 \times 8^2 + 0 \times 8^1 + 3 \times 8^0 = 3 \times 512 + 7 \times 64 + 0 + 3 = 1536 + 448 + 3 = 1987
]
步骤2:十进制转十六进制
不断除以16取余数:
- (1987 \div 16 = 124) 余 3
- (124 \div 16 = 7) 余 12 (C)
- (7 \div 16 = 0) 余 7
倒序排列余数得:7 C 3 → 即 (7C3)₁₆
验证过程示例
八进制 (3703)₈ → 二进制 → 十六进制
[
\begin{align}
3 &\rightarrow 011 \
7 &\rightarrow 111 \
0 &\rightarrow 000 \
3 &\rightarrow 011 \
\hline
\text{二进制} &= 011\ 111\ 000\ 011 \
&= 0111\ 1100\ 0011 \quad (\text{按4位分组}) \
&= 7\ \ C\ \ 3 \quad (\text{对应十六进制}) \
\end{align}
]
关键总结
- 推荐方法:八进制 → 二进制 → 十六进制(更高效,避免大数运算)
- 转换规则:
- 八进制→二进制:1位 → 3位
- 二进制→十六进制:4位 → 1位
- 易错点:
- 二进制分组时需注意位数不足补零(如
011补为0011)。 - 十六进制中
10-15需用字母A-F表示。
- 二进制分组时需注意位数不足补零(如
通过上述步骤,(3703)₈ 最终转换为 (7C3)₁₆。
更多参考:https://blog.csdn.net/m0_46549425/article/details/113954831

浙公网安备 33010602011771号