题目:给定 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;
}
运行结果:
结果完全符合要求,且把代码改进到了最简,代码运行效率也能有所提升,最主要的是,能锻炼自己发现问题、改正问题、在此基础上再优化的能力。