CC++ & Algorithm

进制转换综合:任意进制互转的通用方法

较难18
语言版本:C++Python
概述:把十进制作为“中转站”,先转成十进制,再从十进制转成目标进制,就能实现任意进制之间的转换。

进制转换大通关:任意进制互转的通用方法

你有没有想过,如果要把“八进制数”转换成“十六进制数”,该怎么做?直接算会很麻烦,但有一个超级好用的“中转站”——十进制。就像你去国外旅行,想把英镑换成日元,通常先换成通用的美元,再换成日元。同样,任意进制互转的通用方法就是:

  1. 先把原进制数转成十进制
  2. 再把十进制数转成目标进制

这样,不管原进制是2、8、16,还是5、12,我们都能搞定。下面我们一步步来看具体怎么实现。


为什么用十进制做“中转站”?

因为十进制是人类最熟悉的数制(我们每天用的0~9),而且C++的整数运算天然就是十进制的。把任何进制先转成十进制,就能用普通的数学运算(加减乘除)来处理,然后再转回任意进制。
比如:八进制数 777 先转成十进制 511,再转成二进制就是 111111111。你看,规律是不是很明显?


一、任意进制转十进制:从“位权”出发

回忆一下二进制转十进制的方法:1101(2) = 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 13。任意进制道理一样,只是把底数2换成进制基数 base
比如八进制 777:从右往左,第0位7×8⁰=7,第1位7×8¹=56,第2位7×8²=448,总和511。

代码实现:字符转数字助手

因为输入的是字符串(比如 "1A3F"),我们需要先把每个字符变成数字。比如 '0'→0,'9'→9,'A'→10,'F'→15。

// 字符转数字:'0'~'9'返回0~9,'A'~'F'返回10~15,'a'~'f'也返回10~15
int charToDigit(char c) {
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    return -1; // 非法字符(比如输入了'G'或'@')
}

任意进制转十进制的函数

// 将任意进制字符串转为十进制整数
int toDecimal(string num, int base) {
    int decimal = 0;          // 十进制结果
    for (char c : num) {      // 从左到右遍历每个字符
        decimal = decimal * base + charToDigit(c);  // 秦九韶算法,类似“累加乘底”
    }
    return decimal;
}

为什么用 decimal * base + 当前数字
举个例子:二进制 101→先处理 1,得到1;再处理 0,1×2+0=2;再处理 1,2×2+1=5。是不是跟“逐位加权”结果一样?这是计算机中常用的高效方法。

生活例子:你收到零花钱,每天妈妈给你一个数字,但不同数字代表不同面额。比如第一天给1元,第二天给0元,第三天给1元,总共多少?其实等于1×2² + 0×2¹ + 1×2⁰ = 5元。跟上面的算法一样。


二、十进制转任意进制:用“除基取余法”

还记得十进制转二进制吗?反复除以2,取余数,倒过来读。任意进制也一样,把除数换成目标进制 base
例如十进制 511 转二进制:
511÷2=255 余1
255÷2=127 余1
... 一直除到0,得到余数序列从下往上读就是 111111111

数字转字符助手

当余数超过9时,需要用字母表示:10→'A',11→'B',...,15→'F'。

// 数字转字符:0~9返回'0'~'9',10~15返回'A'~'F'
char digitToChar(int d) {
    if (d < 10) return '0' + d;      // 比如 d=3 → '3'
    return 'A' + (d - 10);           // 比如 d=11 → 'A' + 1 = 'B'
}

十进制转任意进制函数

// 将十进制转为任意进制字符串(2~16)
string fromDecimal(int decimal, int base) {
    if (decimal == 0) return "0";    // 特殊情况:0就是"0"
    string result = "";              // 存放结果的字符串
    while (decimal > 0) {
        int remainder = decimal % base;         // 取余数
        result = digitToChar(remainder) + result; // 余数拼到结果前面(注意顺序)
        decimal /= base;                        // 除以基数
    }
    return result;
}

关键点:每次把余数拼到结果的前面,这样最后得到的字符串就是正确的顺序(从高位到低位)。如果拼在后面再反转,也可以,但直接拼前面更直观。

生活例子:你有511块零花钱,想换成“2元一次”的兑换券(就像二进制)。每次换两张,看剩多少……最后得到的兑换券数量组合就是二进制表示。


三、完整程序:任意进制互转(2~16)

把上面两个函数组合起来,加上用户输入,就能实现任意进制互转了。注意:输入的数字可以包含字母(A~F,大小写都行),程序会识别。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

// 字符转数字:'0'~'9'返回0~9,'A'~'F'返回10~15
int charToDigit(char c) {
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    return -1; // 非法
}

// 数字转字符:0~9返回'0'~'9',10~15返回'A'~'F'
char digitToChar(int d) {
    if (d < 10) return '0' + d;
    return 'A' + (d - 10);
}

// 将任意进制字符串转为十进制
int toDecimal(string num, int base) {
    int decimal = 0;          // 十进制结果
    for (char c : num) {      // 从左到右遍历每个字符
        decimal = decimal * base + charToDigit(c);  // 累加乘底
    }
    return decimal;
}

// 将十进制转为任意进制字符串(2~16)
string fromDecimal(int decimal, int base) {
    if (decimal == 0) return "0";   // 特殊情况
    string result = "";             // 存放结果
    while (decimal > 0) {
        int remainder = decimal % base;         // 余数
        result = digitToChar(remainder) + result; // 拼到前面
        decimal /= base;                        // 除以基数
    }
    return result;
}

int main() {
    string num;        // 原进制下的数字(字符串)
    int fromBase;      // 原进制
    int toBase;        // 目标进制

    cout << "输入原进制下的数字: ";
    cin >> num;
    cout << "输入原进制 (2-16): ";
    cin >> fromBase;
    cout << "输入目标进制 (2-16): ";
    cin >> toBase;

    int decimal = toDecimal(num, fromBase);      // 先转成十进制
    string result = fromDecimal(decimal, toBase); // 再转成目标进制

    cout << "转换结果: " << result << endl;
    return 0;
}

运行示例
输入 1111,原进制2,目标进制16 → 输出 F
输入 777,原进制8,目标进制2 → 输出 111111111
输入 FF,原进制16,目标进制10 → 输出 255


四、新手容易犯的3个错误

  1. 忽略了0的处理
    如果原数字是 "0"toDecimal 返回0,fromDecimal(0, base) 如果不加特殊判断,while循环不会执行,会返回空字符串。所以我们在 fromDecimal 一开始就判断 if (decimal == 0) return "0";

  2. 余数拼反了顺序
    有些同学会写成 result = result + digitToChar(remainder); 这样得到的结果是颠倒的,比如十进制13转二进制会输出 1011(实际应该是 1101)。一定要把新余数拼到前面

  3. 进制超过16或输入非法字符
    我们的程序只支持216进制,而且字符只能包含09和A~F(大小写)。如果用户输入了 "G" 或进制输入为 17,程序会出错(charToDigit 返回-1,导致乘法结果错误)。实际开发中需要增加输入检查,但作为基础学习,我们假设用户输入合法。


五、试试看:自己做几个练习

  1. 把八进制 777 转成十进制,再转成二进制,你发现了什么规律?
    (提示:八进制一位对应三位二进制,你转换的结果是不是全是1?)

  2. 十六进制 1A3F 转成十进制是多少?再转成二进制呢?试着用程序验证。

  3. 如果让你写一个“五进制”转“十二进制”的程序,上面的函数能直接用吗?需要修改哪里?
    (答案:不需要修改,因为我们的函数支持2~16进制,五进制和十二进制都在这范围里,直接调用即可。)


六、相关知识点指引

掌握了任意进制互转,你还可以继续学习:

  • 二进制、八进制、十六进制之间的快速转换(因为2³=8,2⁴=16,有便捷方法)
  • 负数的进制表示(原码、反码、补码)
  • 小数的进制转换(小数部分用“乘基取整”法)
  • 进制在计算机中的应用:内存地址(十六进制)、颜色值(十六进制)、权限设置(二进制)

这个“十进制中转站”的方法,是所有进制转换题的万能钥匙,以后遇到任何进制转换的题目,都可以用这个思路解决。赶快试试吧!

例题精讲

1单选题

在C++中,将任意进制字符串(如"1011"表示二进制数)转换为十进制整数时,通用的算法是?

A除基取余法
B按权展开累加法
C递归分解法
D位运算法
2判断题

将R进制数转换为十进制数,通用的方法是“除基取余法”。

3填空题
以下C++函数将十进制整数转换为任意进制(2~36)字符串,请填空完成核心逻辑。
string decimalToBase(int num, int base) {
    string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string result = "";
    while (num > 0) {
        result = digits[___] + result;
        num /= base;
    }
    return result;
}
4单选题

关于任意进制互转的通用方法,下列说法正确的是?

A从R1进制转换为R2进制,可以先将R1进制数转换为十进制,再将十进制转换为R2进制。
B从R1进制转换为R2进制,只能用位权展开法。
C从R1进制转换为R2进制,必须通过二进制作为中间进制。
D从R1进制转换为R2进制,不能直接转换,必须分步进行。
5判断题

在C++中,使用除基取余法将十进制数转换为任意进制时,依次得到的余数逆序排列即为正确结果。