题目——进制转换3
锲而不舍——先给自己立一个纪念碑
思路
- 根据输入信息,将输入值从m进制转换成10进制
- 将10进制数据转换成n进制数据输出
输入值从m进制转换成10进制
-
将输入值视作字符串
-
依次取出字符串字符,
- 如果是数字: 减去‘0’得到真实值
- 如果是字母:减去‘A’+10到真实值,注意,这里要减去10,我提交了一万遍才过很大程度上就是忘记了这个10
-
计算每一位真实值*所在位数权值(例如1000中的1,位于千位,权值是1000),对于m进制数,相应 位的权值 = 该位真实值 ∗ m 该位在第几位 位的权值=该位真实值*m^{该位在第几位} 位的权值=该位真实值∗m该位在第几位
-
算出每一位的值求和即可转为实际的10进制值
将10进制数据转换成n进制数据输出
- 将10进制数据每次对n取余,得到的数字转换成相应的字符存到字符串内
- 将字符串当作字符数组,倒序输出,即为所要的n进制数据
上述方法在计组等书中有描述,类似下图(注意,他除2没有写出来,其实是不太规范的):(来自知乎作者@chee【十进制转成二进制的两种方式】)
数字和字母的输入输出问题
显然,输入进制由2~36进制不等,囊括了从0到1,从a到z的所有组合,那么输入和输出必定是字符串形式
这就带来两个问题,一个是输入接收字母转换成数字,另一个是输出数字转换成字母,这两个问题关键就是字母和数字相互转换问题,有两种解决思路:
思路一:用map
设置两个map,一个从char到int,另一个从int到char,看上去无比便捷,但问题是要自己一个个对应地去写,总共要写36*2=72个对,非常麻烦,因此不可行。
当然我一开始没想这么多,还真用的这个办法,如下图,但是写了一半就不想写了,真麻烦!!!
思路二:用函数计算然后返回
众所周知,ascii中0到1和a到z和A到Z都是有顺序关系的,计算一下就能够得到真实的数值,因此可以设置一个函数输入并返回,但是要注意,数字的字符和字母的字符计算有所不同,字母计算时候要相应的加减10,因为a代表的是10,数字字符就没有这些要考虑的。
就是这个10,让我一步步debug了半天,好消息是我会用codeblock来debug了,原本感觉丑陋的codeblock界面用多了发现也是风韵犹存。
int mymap(char num){
if(num>='0'&&num<='9'){
return num-'0';
}else{
return num-'A'+10;
}
}
char M_map(int num){
if(num>=0&&num<=9){
return num+'0';
}else{
return num+'a'-10;
}
}
思路叙述完毕,接下来让我们恭迎100%AC的代码驾到!!!!
#include <cstdio>
#include <map>
#include <string>
using namespace std;
int mymap(char num){
if(num>='0'&&num<='9'){
return num-'0';
}else{
return num-'A'+10;
}
}
char M_map(int num){
if(num>=0&&num<=9){
return num+'0';
}else{
return num+'a'-10;
}
}
int main(){
int m,n;
char num[10000];
scanf("%d%d",&m,&n);
scanf("%s",num);
string str = num;
unsigned long long t_10 = 0;
for(int i=0;i<str.length();i++){
unsigned long long temp = mymap(str[i]);
for(int j=0;j<str.length()-i-1;j++){
temp *= m;
}
t_10 += temp;
}
//现在t10是十进制数了
string target = "";
while(t_10>=n){
unsigned long long number = t_10%n;
target += M_map(number);
t_10 /= n;
}
target += M_map(t_10);
for(int i=target.length()-1;i>=0;i--){
printf("%c",target[i]);
}
return 0;
}
AC情况——最后再立一个纪念碑
最后总结一下,这里面遇到的坑(我是一踩一个准,爬坑爬半天)
- 输入输出数字和字母,如何转换字母和数字的ascii
- 转换高进制极易出现数值过大的情况,必须采用long long,我直接用unsigned long long