算法笔记练习 5.6 大整数运算 问题 D: 进制转换
题目
题目描述
将M进制的数X转换为N进制的数输出。
输入
输入的第一行包括两个整数:M和N(2<=M,N<=36)。
下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出。
输出
输出X的N进制表示的数。
样例输入
10 2
11
样例输出
1011
提示
注意输入时如有字母,则字母为大写,输出时如有字母,则字母为小写。
思路
整体步骤:
- 用
m
,n
接收两个整数,字符串buffer
接收数 X; - 通过
baseChange
函数将m
进制的buffer
字符串转换成bign
类型的a
; - 用
basePrint
函数输出a
的n
进制形式。
函数的思路:
关于大整数运算的基础(包括bign
类型,大整数的四则运算等),参考算法笔记 P170。
这里仅描述数学上的思路,具体实现请看代码。
baseChange
函数:
- 接收两个参数:字符串的首地址
str
,用base
进制来解读; - 从
str
的低位(即字符串末尾)开始遍历,第i
位(记字符串末尾为第0
位)代表的十进制数值是 ,但是str[i]
是字符类型,所以就需要一个函数char_to_int
来做转换; - 用步骤 2 把
str
上所有位置代表的十进制数值相加就得到了十进制的a
。
basePrint
函数:
- 接收两个参数:
bign
类型的十进制数字a
,用base
进制来输出; - 和普通的进制转换思路一样,只要
a
大于零,就不断地用base
去除a
,令a
等于商并记录余数。由于先算出来的是高位,最后算出来的是低位,需要一个栈(普通数组)来存放结果; - 最后不断弹出栈中的内容输出即可,需要一个
int_to_char
函数把数字转换成对应的字符。
细节:注意输入的字母是大写,输出是小写。
代码
#include <cstdio>
#include <cstring>
#define MAX 2000
struct bign {
int d[MAX];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
};
int char_to_int(char c); // 把数字字符或者大写字母转为对应的十进制 int
char int_to_char(int n); // 把十进制 int 转为对应的小写字母
bign baseChange(char *str, int base); // 把 base 进制的输入字符串转为十进制的 bign
void basePrint(bign a, int base); // 以 base 进制输出 a
bign add(bign a, bign b); // 高精度加高精度
bign multi(bign a, int b); // 高精度乘低精度
bign divide(bign a, int b, int &r); // 高精度除以低精度,r为余数
int main() {
int m, n;
char buffer[MAX];
while (scanf("%d %d", &m, &n) != EOF) {
scanf("%s", buffer);
bign a = baseChange(buffer, m);
basePrint(a, n);
putchar('\n');
}
return 0;
}
int char_to_int(char c) { // 把数字字符或者大写字母转为对应的十进制 int
int ret;
if (c >= '0' && c <= '9')
ret = c - '0';
else if (c >= 'A' && c <= 'Z')
ret = c - 'A' + 10;
return ret;
}
char int_to_char(int n) { // 把十进制 int 转为对应的小写字母
char ret;
if (n >= 0 && n <= 9)
ret = n + '0';
else if (n >= 10 && n <= 35)
ret = 'a' + n - 10;
}
bign baseChange(char *str, int base) { // 把 base 进制的输入字符串转为十进制的 bign
bign a;
a.len = 1;
int len = strlen(str);
int i;
for (i = 0; i != len; ++i) {
bign power;
power.d[0] = 1;
power.len = 1;
for (int j = 0; j != i; ++j) // 得到了 base 的 i 次方
power = multi(power, base);
// 得到了数位上的字符对应的十进制数数值
power = multi(power, char_to_int(str[len - i - 1]));
a = add(a, power);
}
return a;
}
void basePrint(bign a, int base) { // 以 base 进制输出 a
int output[MAX];
int index = 0;
while (a.len != 1 || a.d[0] != 0) {
a = divide(a, base, output[index]);
++index;
}
for (--index ; index >= 0; --index)
putchar(int_to_char(output[index]));
}
bign add(bign a, bign b) {
bign c;
int carry = 0;
int len = (a.len > b.len) ? a.len : b.len;
for (int i = 0; i != len; ++i) {
int temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
if (carry)
c.d[c.len++] = carry;
return c;
}
bign multi(bign a, int b) {
bign c;
int carry = 0;
for (int i = 0; i != a.len; ++i) {
int temp = b * a.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while (carry) {
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
bign divide(bign a, int b, int &r) {
r = 0;
bign c;
c.len = a.len;
for (int i = a.len - 1; i >= 0; --i) {
r = r * 10 + a.d[i];
if (r < b)
c.d[i] = 0;
else {
c.d[i] = r / b;
r %= b;
}
}
while (c.len - 1 >= 1 && c.d[c.len - 1] == 0)
--c.len;
return c;
}