[SOJ 1647 & 1659] 进制转换(一 / 二)

“进制”只是表示“量”的一种方式

关于进制转换,我们首先要理解“进制”的概念。
“进制”只是表示“量”的一种方式,同一个“量”用不同的“进制”表示,发生的应当是“等量的转换”

百度百科:“数制”只是一套符号系统来表示指称“量”的多少。我们用“1”这个符号来表示一个这一“量”的概念。自然界的“量”是无穷的,我们不可能为每一个“量”都造一个符号,这样的系统没人记得住。所以必须用有限的符号按一定的规律进行排列组合来表示这无限的“量”。符号是有限的,这些符号按照某种规则进行排列组合的个数是无限的。十进制是10个符号的排列组合,二进制是2个符号的排列组合。
在进行进制转换时有一基本原则:转换后表达的“量”的多少不能发生改变。二进制中的111个苹果和十进制中的7个苹果是一样多的。

举例:
量的计算公式:
量 = Xi * base^i (因为这里使用10进制作为中间量, 所以Xi表示某个位上的10进制数)

同一个量的衡量:
16 (10进制数) = 6 * 10^0 + 1 * 10^1 (使用10进制衡量)

进制转换分2个流程

进制转换的工作流程分为2个要步骤:
1. 从 源文本(源进制)→ 10进制数值
2. 从 10进制数值 → 目标文本(目标进制)

注:为了方便起见,我们假设“任意进制”指2到16进制中的任何一个进制。(对于10进制以上的进制, 如16进制, 需要额外指定1个字符集来标明指定的值,如A = 10, B = 11等等)

中间的10进制数 便是衡量量的一个中介值,利用该数值完成进制转换。

我们所需要完成的函数原型:

void transX2X(char src[], int srcBase, int destBase, char dest[]);
// char src[]: 源文本
// int srcBase: 源进制
// char dest[]: 目标文本
// int destBase: 目标进制
利用10进制数作为中介的任意进制转换
#include 
#include 
#include 
#include 

#pragma warning (disable:4996)

#define scale 1024

using namespace std;

int getSrcNum(int srcBase, char num) {

    if (srcBase >= 2 && srcBase <= 10) {
        return num - '0';
    }

    return 10 + (num - 'A' + 1);
}

char getDestChar(int num) {

    // 数字
    if (num >= 0 && num <= 9) {
        return '0' + num;
    }

    // 字母
    return 'A' + (num - 10);
}

void translateMagicNum(int magicNum, int destBase, char dest[]) {

    // Translate
    int i = 0;
    while (magicNum > 0) {

        int curDestNum = magicNum % destBase;

        char curDestChar = getDestChar(curDestNum);

        magicNum /= destBase;
        dest[i] = curDestChar;
        i++;
    }

    // Reverse.
    reverse(dest, dest + strlen(dest));
}

void transX2X(char src[], int srcBase, int destBase, char dest[]) {

    // Calc MagicNum.
    reverse(src, src + strlen(src));

    int magicNum = 0;

    for (int i = 0; i < strlen(src); i++) {

        int curSrcNum = getSrcNum(srcBase, src[i]);
        magicNum += curSrcNum * (pow(srcBase, i));
    }

    // Translate
    translateMagicNum(magicNum, destBase, dest);
}


int main() {

    // I.
    char src[scale] = { 0 };
    char dest[scale] = { 0 };
    printf("请输入待转换数据:\n");
    scanf("%s", &src);

    int src_base, dest_base;
    printf("请输入待转换数据的进制数:\n");
    scanf("%d", &src_base);
    printf("请输要待转换数据的进制数:\n");
    scanf("%d", &dest_base);


    // A.
    transX2X(src, src_base, dest_base, dest);

    printf("转换后的结果为:\n");
    printf("%s\n", dest);

    // O.
    return 0;
}

充分利用C语言的标准库!

由于进制转换的核心流程主要是2个步骤:
1. 将 源文本(源进制) 转换为 10进制数
2. 将 10进制数 转换为 目标文本(目标进制)

所以,我们不妨试试下面这2个C语言函数.
strtol() 将 任意进制的文本 转换为 10进制数
itoa() 将 10进制数 转换为 任意进制文本

将strtol()和iota()进行组合, 即可完成任意进制转任意进制。

利用strtol()与itoa()完成任意进行转化
// 只需要1行代码的任意进制转换.
void transX2X(char src[], int srcBase, int destBase, char dest[]) {
    itoa(strtol(src, 0, srcBase), dest, destBase);
}

到此,只需要用我们新写的transX2X()替换原来的transX2X()即可.

不妨测试几组数据叭,可以看出,这个函数工作地非常好,确实给出了正确的结果。


顺便说一下,使用strtol()和itoa()完成的任意进制转换函数,实际上不仅仅支持2-16进制的转换。它可以支持到2-36进制之间的任意转换哦。

来试试Problem1647和Problem1659叭

SOJ1647 进制转换(一) AC.c
r[];main(n,b){scanf("%d %d",&n,&b);puts(itoa(n,r,b));}
SOJ1659 进制转换(二) AC.c
a[];main(b){scanf("%s%d",&a,&b);printf("%d",strtol(a,0,b));}

发表评论

邮箱地址不会被公开。 必填项已用*标注

> 表情包