一、进制转换核心原理
1. N进制转十进制(按权展开法)
算法步骤:
- 将N进制数的每一位字符转换为对应的十进制数值(A-F对应10-15)
- 从高位到低位依次计算:
十进制值 = 当前值 × N^权 + 前一步结果
- 权值规律:第i位的权值为N<sup>i</sup>(i从右往左计数,起始为0)
数学公式:
代码模板(以十六进制转换为10进制为例):
string s = "2021ABCD"; // 十六进制数
ll x = 0;
for (char c : s) {
int val = isdigit(c) ? c-'0' : toupper(c)-'A'+10;
x = x * 16 + val; // 累加计算:ml-citation{ref="1,3" data="citationList"}
}
cout << x; // 输出539080141
2. 十进制转N进制(除基取余法)
算法步骤:
- 用十进制数反复除以N,记录余数
- 逆序排列余数(最后得到的余数为最高位)
- 余数>9时用字母A-F表示10-15
代码模板(以十进制转换为16进制为例):
int x = 1478; // 十进制数
string ans;
while(x > 0) {
int rem = x % 9; // 当前余数
ans += (rem < 10) ? rem+'0' : rem-10+'A';// 如果小于10,就直接减去0
// 如果大于10的话,就先减去10再加上'A'
x /= 9;
}
reverse(ans.begin(), ans.end()); // 逆序输出
cout << ans; // 输出2022(九进制)
二、经典例题解析
例题1:十六进制转十进制
链接:蓝桥账户中心
题目:计算十六进制数 2021ABCD
的十进制值
题目解析:
1.直接用OX20221ABCD输出
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("%d",0X2021ABCD);
return 0;
}
2.使用模板进行进制的转换:
#include <iostream>
using namespace std;
using ll = long long;
int digit[50]; // 转化之后的各个位数的值
int main()
{
// 请在此输入您的代码
string s = "2021ABCD"; // 十六进制数
for (int i = 0; i < s.length(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
digit[i] = s[i] - '0'; // 如果是0-9的数字,就让它转换为整形
}
else if (s[i] >= 'A' && s[i] <= 'Z') {
digit[i] = s[i] - 'A' + 10; // A-Z的数字都是从10开始的
}
}
ll x = 0;
for (int i = 0; i < s.length(); i++) {
x = x * 16 + digit[i];
}
cout << x << endl;
return 0;
}
例题2:九进制转十进制
链接:蓝桥账户中心
计算过程:
(2022)9=2×93+0×92+2×91+2×90=1478
代码亮点:
- 直接处理字符到数值的转换
- 这个不能像上一题使用Ox来做,因为9进制在C++中没有合适的快捷方式输出
- 无需处理字母字符(九进制无字母)
#include <iostream>
#include <cctype>
using namespace std;
using ll = long long;
int digit[50]; // 转化之后的各个位数的值
// 九进制转换为十进制
int main()
{
string s = "2022";
for (int i = 0; i < s.length(); i++) {
if (s[i] >= '0' && s[i] <= '9') { // 把0-9的字符转化为0-9
digit[i] = s[i] - '0';
}
else if (isalpha(s[i])) { // 把A-Z转换为10-35,不过这道题不用
digit[i] = toupper(s[i]) - 'A' + 10;
}
}
ll x = 0;
for (int i = 0; i < s.length(); i++) {
x = x * 9 + digit[i];
}
cout << x << endl;
return 0;
}
例题3:通用进制转换
链接:蓝桥账户中心
需求:实现N进制到M进制的任意转换
代码设计:
- N进制→十进制:循环累加计算
- 十进制→M进制:反向存储余数
代码如下:
#include <iostream>
#include <cctype>
#include <algorithm>
using namespace std;
using ll = long long;
char ch[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
'D', 'E', 'F' }; // 0-15的表示
int digits[15]; // 十进制数位
// 进行进制转换的函数
void solve(int N, int M) {
// 先将N进制转换为M进制
string s; // N进制数
cin >> s;
for (int i = 0; i < s.length(); i++) {
if (isdigit(s[i])) {
// 判断如果是数字的话,进行转换
digits[i] = s[i] - '0';
}
else if (isalpha(s[i])) {
// 如果是A-F的字符,就变成超过10的数字
digits[i] = toupper(s[i]) - 'A' + 10;
}
}
ll x = 0; // 十进制数
for (int i = 0; i < s.length(); i++) { // N进制转换为十进制
x = x * N + digits[i];
}
if (M == 10) {
// 如果是N进制转换为10进制,就不用再转换了,直接输出
cout << x << endl;
return;
}
// 再将十进制转换为M进制
string ans; // M进制数
while (x) {
ans += ch[x % M];
x /= M; // 用m整除
}
// 整除完之后进行翻转
reverse(ans.begin(), ans.end());
cout << ans << endl;
}
int main()
{
int T; // 测试数据数量
cin >> T;
while (T--)
{
int N, M; // 初始进制数和结果进制数
cin >> N >> M;
solve(N, M);
}
// 请在此输入您的代码
return 0;
}
三、算法复杂度对比
转换类型 | 时间复杂度 | 空间复杂度 | 核心操作 |
---|---|---|---|
N进制→十进制 | O(n) | O(1) | 按权累加 |
十进制→N进制 | O(logN x) | O(logN x) | 除基取余 |
通用进制转换 | O(n + logM x) | O(n + logM x) | 双重转换 |
四、高频考点与易错点
-
字符转换错误
- 必须正确处理
A-F/a-f
的ASCII转换(toupper()
统一大小写)67 - 错误示例:
'A'-'0'
(应使用'A'-'A'+10
)
- 必须正确处理
-
权值计算方向错误
- 十六进制数
"1A2B"
应从左往右计算,而非从右往左13
- 十六进制数
-
余数逆序问题
- 十进制转N进制必须反转余数序列45
写在最后:
我们可以在这里学习C++知识: