不同进制下的乘法表

题目:给定 p,请输出p进制下的乘法表。(输出p进制下的乘法表。p进制中大于等于10的数字用大写字母 A、B、C、··· 表示。2≤p≤36)

例:

输入:4

输出:

1*1=1

2*1=2 2*2=10

3*1=3 3*2=12 3*3=21

输入:8

输出:

1*1=1

2*1=2 2*2=4

3*1=3 3*2=6 3*3=11

4*1=4 4*2=10 4*3=14 4*4=20

5*1=5 5*2=12 5*3=17 5*4=24 5*5=31

6*1=6 6*2=14 6*3=22 6*4=30 6*5=36 6*6=44

7*1=7 7*2=16 7*3=25 7*4=34 7*5=43 7*6=52 7*7=61

题目很简单,就是打印一个乘法数表在屏幕上,与以往写的打印9*9乘法表类似,只需要修改打印行数和列数、再对最后结果进行进制转换即可。

关于进制转换,我在令人头疼的进制转换一文中有详细介绍,在这里就不再详细介绍了。

在进行打印时,因为只有p>10时才会涉及到字母的打印,因此可以设计两个不同的进制转换函数,对p进行分情况讨论后调用不同的函数进行运算。

代码如下:

#include<stdio.h>
#include<math.h>
int Base_con_10(int x, int y)//进制转换,x为要转换的数,y为要转换的进制,十进制以内的
{
    int i = 0;
    int sum = 0;
    while (x)
    {
        int k = x % y;
        sum += k * pow(10, i++);
        x /= y;
    }
    return sum;
}
void Base_con(int x, int y)//大于十进制的转换
{
    int k = 0;
    char a[100]={0};
    char arr[36] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
    while (x)//逆序存储
    {
        a[k++] = arr[x % y];
        x /= y;
    }
    for (--k; k >= 0; k--)//逆序打印
    {
        printf("%c", a[k]);
    }
    printf(" ");
}
int main(int argc, char* argv[])
{
    int p = 0;
    scanf("%d", &p);
    int i = 1, j = 1;
    for (i = 1; i < p; i++)
    {
        for (j = 1; j <= i; j++)
        {
            if (p < 10)//小于十进制不涉及字母转换
            {
                printf("%d*%d=%d ", i, j, Base_con_10(i * j, p));
            }
            else if (p == 10)//十进制直接打印
            {
                printf("%d*%d=%d ", i, j, i * j);
            }
            else
            {
                printf("%d*%d=", i, j);
                Base_con(i * j, p);
            }
        }
        printf("\n");
    }
    // 请在此输入您的代码
    return 0;
}

运行结果:

可以发现,打印结果与题目实例相同,但是一组结果对上了,代码就没问题了吗?

当p>10时再试一下:

 有没有发现什么问题?

数表中出现了10、11,题目明确要求“大于等于10的数字用大写字母 A、B、C、··· 表示。”

再观察10、11出现的位置,可以发现全在‘ = ’左边,而‘ = ’右边全部符合要求。

观察代码可以发现,我们仅在打印最后结果时进行了进制转换,但在打印i、j时没有进行进制转换,因此问题应该出在打印i,j的时候,打印i、j时也应该进行进制转换才行。且只有p>10时i、j才有可能超过9,才需要进行转换,所以只需要对p>10时i、j的打印进行转换即可。

改进代码:

int Base_con_10(int x, int y)//进制转换,x为要转换的数,y为要转换的进制,十进制以内的
{
    int i = 0;
    int sum = 0;
    while (x)
    {
        int k = x % y;
        sum += k * pow(10, i++);
        x /= y;
    }
    return sum;
}
void Base_con(int i,int j,int x, int y)//大于十进制的转换
{
    int k = 0;
    char a[100] = { 0 };
    char arr[36] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
    printf("%c*%c=", arr[i], arr[j]);//打印“i*j=”
    while (x)//逆序存储
    {
        a[k++] = arr[x % y];
        x /= y;
    }
    for (--k; k >= 0; k--)//逆序打印
    {
        printf("%c", a[k]);
    }
    printf(" ");
}
int main(int argc, char* argv[])
{
    int p = 0;
    scanf("%d", &p);
    int i = 1, j = 1;
    for (i = 1; i < p; i++)
    {
        for (j = 1; j <= i; j++)
        {
            if (p < 10)//小于十进制不涉及字母转换
            {
                printf("%d*%d=%d ", i, j, Base_con_10(i * j, p));
            }
            else if (p == 10)//十进制直接打印
            {
                printf("%d*%d=%d ", i, j, i * j);
            }
            else
            {
                //printf("%d*%d=", i, j);
                Base_con(i, j, i * j, p);//直接和结果一起在函数里边打印
            }
        }
        printf("\n");
    }
    // 请在此输入您的代码
    return 0;
}

运行结果:

 进行改进后,不管是‘ = ’左边还是右边都没有出现10、11等大于9的数,而是以字母‘A’、‘B’代替了。达到了题目要求的效果。

虽然到这里已经解决了题目,但是,观察代码会发现,要用两个函数、还要分类讨论,太过麻烦,因此可以对其进行改进,使其更简洁。

改进思路:可以把不同情况合并,全部在函数内、用字符形式打印,可以达到更简洁的目的。

改进代码:

void Base_con(int i,int j,int x, int y)//进制转换
{
    int k = 0;
    char a[100] = { 0 };
    char arr[36] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
    printf("%c*%c=", arr[i], arr[j]);
    while (x)//逆序存储
    {
        a[k++] = arr[x % y];
        x /= y;
    }
    for (--k; k >= 0; k--)//逆序打印
    {
        printf("%c", a[k]);
    }
    printf(" ");
}
int main(int argc, char* argv[])
{
    int p = 0;
    scanf("%d", &p);
    int i = 1, j = 1;
    for (i = 1; i < p; i++)
    {
        for (j = 1; j <= i; j++)
        {
            //if (p < 10)//小于十进制不涉及字母转换
            //{
            //    printf("%d*%d=%d ", i, j, Base_con_10(i * j, p));
            //}
            //else if (p == 10)//十进制直接打印
            //{
            //    printf("%d*%d=%d ", i, j, i * j);
            //}
            //else
            //{
            //    //printf("%d*%d=", i, j);
            //    Base_con(i, j, i * j, p);
            //}
            Base_con(i, j, i * j, p);//全部在函数内、以字符形式打印
        }
        printf("\n");
    }
    // 请在此输入您的代码
    return 0;
}

运行实例:

 运行结果没问题,且代码更加简洁了。

但是呢,程序中还是用到了打印数表必须的两层循环以外的循环结构,且还要创建多余数组,那么能不能不使用多余循环结构、也不用创建多余数组呢?

答案是:能。

深度优化:首先要知道乘法表中‘ = ’左边均由两个数(均小于进制数)组成,‘ = ’右边的结果除以一次p后,所得结果必定小于p,因为,‘ = ’右边的结果是由‘ = ’左边两个小于p的数相乘得到的。因此,在对结果进行进制转换时只需要对p取一次模、再除以一次p即可。

改进代码:

#include<stdio.h>
void Base_con(int i,int j,int x, int y)//进制转换
{
    //int k = 0;
    //char a[100] = { 0 };
    //char arr[36] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
    //printf("%c*%c=", arr[i], arr[j]);
    //while (x)//逆序存储
    //{
    //    a[k++] = arr[x % y];
    //    x /= y;
    //}
    //for (--k; k >= 0; k--)//逆序打印
    //{
    //    printf("%c", a[k]);
    //}
    //printf(" ");
    char arr[36] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
    int m = x % y;
    int n = x / y;
    if (n == 0)//n为0,说明‘=’右边仅有一位
    {
        printf("%c*%c=%c ", arr[i], arr[j], arr[m]);
    }
    else//n不为0,说明‘=’右边有两位
    {
        printf("%c*%c=%c%c ", arr[i], arr[j], arr[n], arr[m]);
    }
}
int main(int argc, char* argv[])
{
    int p = 0;
    scanf("%d", &p);
    int i = 1, j = 1;
    for (i = 1; i < p; i++)
    {
        for (j = 1; j <= i; j++)
        {
            Base_con(i, j, i * j, p);
        }
        printf("\n");
    }
    // 请在此输入您的代码
    return 0;
}

运行结果:

 结果完全符合要求,且把代码改进到了最简,代码运行效率也能有所提升,最主要的是,能锻炼自己发现问题、改正问题、在此基础上再优化的能力。

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值