CC++ & Algorithm

进制转换总搞反?教你用"万能中转站"一招通吃2~16进制互转

先抛一个观点:所有进制转换题目,本质上只有两个动作——先转十进制,再转目标进制。

你信吗?八进制 777 想转成十六进制,如果直接一位位对比,脑子容易炸。但如果你先把 777 转成十进制 511,再转成十六进制,结果一眼就能看出来:1FF。整个过程不需要背任何特殊规律,只需要掌握两个方向相反的算法。

这就是“十进制中转站”的威力。

为什么偏偏是十进制?

因为十进制是你我每天用的数制,C++ 里整数运算本身就是十进制的。把任意进制先转成十进制,就能直接用 + - * / 处理;处理完再转回去。这就像出国旅行,你手里有英镑想换日元,通常先换成美元,再用美元换日元。美元就是全球通用的“中转货币”。

关键点来了:这个中转方法对任意进制都有效,不管是2、8、16,还是5、12,甚至36进制,思路完全一样。

方向一:任意进制 → 十进制

回忆一下二进制转十进制:1101 = 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 13。把底数2换成任意基数 base,公式就变成了:

十进制结果 = 每一位数字 × base的位权,累加

这个方法有个正式名称:按权展开累加法。别看名字长,它本质上就是把每一位“拆开算权值,再求和”。

在代码里,我们通常不用每次都算 base 的幂,而是用一个小技巧——秦九韶算法

int decimal = 0;
for (char c : num) {
    decimal = decimal * base + charToDigit(c);
}

比如处理二进制 101:先拿到1,decimal=1;再拿到0,decimal=1×2+0=2;再拿到1,decimal=2×2+1=5。结果完全正确,而且不用调 pow 函数。

这里插一道很典型的考题:

将任意进制字符串(如 "1011")转换为十进制整数时,通用的算法是? A. 除基取余法 B. 按权展开累加法 C. 递归分解法 D. 位运算法

答案是 B。为什么不是 A?因为除基取余法的方向正好相反——它是“十进制→其他进制”的工具。有些同学一看到“转换”就选 A,其实是被“转换”这个词骗了。方向搞反,是考试里最常见的丢分点。

至于 C 和 D,递归确实能实现转换,但不是“通用算法”;位运算只对二进制友好,遇到八进制、十六进制就束手无策了。所以 B 是唯一正确的通用思路。

方向二:十进制 → 任意进制

这一步用除基取余法。还记得十进制转二进制吗?反复除以2,取余数,倒着读。把除数换成目标进制 base,原理一模一样。

比如十进制 511 转二进制:

511 ÷ 2 = 255 余 1
255 ÷ 2 = 127 余 1
...
1 ÷ 2 = 0 余 1

把余数从下往上读:111111111

代码里有个关键顺序问题:

string result = "";
while (decimal > 0) {
    int r = decimal % base;
    result = digitToChar(r) + result;   // 拼到前面,不是后面
    decimal /= base;
}

很多新手写成 result = result + digitToChar(r),结果输出是颠倒的。比如十进制13转二进制会得到 1011,而正确答案是 1101余数必须拼在结果的前面,这样才能保证从高位到低位输出。

这里有一道判断题,正好检验你方向感:

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

这句话对吗?错。 正确的说法是:R进制→十进制用“按权展开求和法”;十进制→R进制才用“除基取余法”。这俩是互逆过程,就像上楼梯和下楼梯,不能因为都叫“走楼梯”就混为一谈。

记忆技巧:从R进制到十进制是“展开”,从十进制到R进制是“倒除”。展开就是乘位权再相加,倒除就是除R取余逆序排。

组合起来,任意互转

把两个函数拼起来,就是完整流程:

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

就这么简单。输入 FF,原进制16,目标进制10,得到 255;输入 1111,原进制2,目标进制16,得到 F

上面这两个函数的代码,核心部分就是我刚才贴的片段。完整版里面还需要处理一个特殊情况:decimal == 0 时直接返回 "0",不然 while 循环一次都不执行,结果会变成空字符串。这也是新手容易踩的坑。

关于16进制字母,别搞混

字符与数字的转换,很多同学会在 'A' 到 10 这一步卡壳。其实只需要记住:'A' - 'A' + 10 = 10,也就是 c - 'A' + 10

if (c >= 'A' && c <= 'F') return c - 'A' + 10;

同理,数字转字符,10 就要变成 'A'

if (d >= 10) return 'A' + (d - 10);

这两个助手函数是进制转换的“翻译官”,没有它们,字符串和数字根本无法交流。

我的建议

初学进制转换,别急着背八进制、十六进制的“快速转换法”。先把十进制中转这条通用路径走通,理解“按权展开”和“除基取余”这对互逆操作,后面学二进制和八进制的分组转换(2³=8,2⁴=16)才会轻松。

如果你已经能顺利实现2~16进制互转,下一步可以挑战小数部分的进制转换——用“乘基取整”法,思路和整数部分正好对称。再往后,还可以玩玩负数的补码表示,看看计算机怎么用二进制表达负数。

进制转换不只是一堆公式,它背后是“位权”这一计算机科学的核心概念。掌握了中转站思维,你就拿到了所有进制问题的万能钥匙。


关于作者

我是赵老师,持有 NOI 信息学奥赛教练证书,拥有 15 年以上的软件开发经验,从事信息学少儿编程教学已有 8 年时间。

这些年累计帮助 多名 学生通过编程特长升入自己心仪的目标学校。

如果你在编程学习上有任何疑问,欢迎联系我:18620372957(微信同号)

这篇文章对你有帮助吗?

成为第一个评价的人

想系统学习这个知识点?查看完整知识点 →