之前考研复试机试的时候就碰到了涉及十进制和二进制转换的问题,当时没做出来,心态很崩溃,现在要认真沉淀。经过这两天的学习,我总结了一下进制转换的要点,与大家分享,共勉!!!
进制转换类题型可以分为两种:
1.十进制转换成K进制
2.K进制转换成十进制
这类题主要涉及的数据结构类型有:int变量,int数组,char变量,char数组等。
主要涉及的知识点有:/运算、%运算、对字符数组的理解、字符与数字的相互转化、对ASCII码的理解等等。
——————————————————————————————————————————
对于十进制转换成K进制的题:
首先考虑基本方法,使用除K取余法。然后选取算法需要的数据结构类型,这里主要需要考虑的是输入输出的数据结构。输入的话,就是一个十进制的整型数,根据题目选择int或者long long即可。输出的话,我们选择一个字符数组或者整型数组(比如十六进制涉及‘A','B','C','D','E','F'可以使用字符数组,当然也可以选择使用整型数组先存储,等到输出时再将整数输出为对应的A,B,C,D,E,F即可,而二进制则只涉及0,1,可以使用整型数组)。
以《算法笔记》中的一道练习题为例。题目如下:
下面是我的解题代码:
#include <cstdio>
#include <cstring>
using namespace std; //**************多余了
char a[15];
int main(){
int n,k;
scanf("%d%d",&n,&k);
int i = 0;
memset(a,'a',sizeof(a)); //*****************有更好的写法
do{
if(n%k < 10){a[i++] = n % k + '0';}
if(n%k == 10){a[i++] = 'A';} //************有更好的写法
if(n%k == 11){a[i++] = 'B';} //************同上
if(n%k == 12){a[i++] = 'C';} //*************同上
if(n%k == 13){a[i++] = 'D';} //*************同上
if(n%k == 14){a[i++] = 'E';} //*************同上
if(n%k == 15){a[i++] = 'F';} //*************同上
n /= k;
}while(n > 0);
for(int i=14; i >= 0; i--){
if(a[i] != 'a'){
printf("%c",a[i]);
}
}
return 0;
}
后来查看了题解的参考代码以及做了一些字符串的练习之后,发现我的代码虽然运行通过,但是简洁性很差,对字符数组的理解也不是很够。
题解代码如下:
#include <cstdio>
const int MAXN = 11;
int radixK[MAXN], len = 0;
int main() {
int radix10, k;
scanf("%d%d", &radix10, &k);
do {
radixK[len++] = radix10 % k;
radix10 /= k;
} while (radix10 > 0);
for (int i = len - 1; i >= 0; i--) {
if (radixK[i] <= 9) {
printf("%d", radixK[i]);
} else {
printf("%c", radixK[i] - 10 + 'A');
}
}
return 0;
}
首先,我采取的输出字符数组的方法是循环判断条件,如本体,K进制里不可能有小写字母,所以我先将字符数组所有元素初始化为小写字母a,输出是将非a字符输出。当然,以我的方法也可以优化,不需要在一开始将字符数组所有元素初始化为小写字母a,一开始定义它的类型时,字符数组中的每个元素就已经有值了,是‘\0’即空字符NULL。后面输出就将非'\0'输出即可。
题解采用的是计数输出法,即在除K取余过程将模存入数组时就对下标进行计数,(其实我的代码中也计数了,a[i++]中的i可以充当计数器,不过我后来代码中又用了i,还重新赋值了,也没有想到跳出循环后的i值还有实际用处,说明我的代码其实挺乱的,对每个变量的使用也不是很充分)然后用for循环输出所求的字符即可。
对下面这部分代码:
if(n%k < 10){a[i++] = n % k + '0';}
if(n%k == 10){a[i++] = 'A';} //************有更好的写法
if(n%k == 11){a[i++] = 'B';} //************同上
if(n%k == 12){a[i++] = 'C';} //*************同上
if(n%k == 13){a[i++] = 'D';} //*************同上
if(n%k == 14){a[i++] = 'E';} //*************同上
if(n%k == 15){a[i++] = 'F';} //*************同上
也可以优化为:
if(n%k < 10){a[i++] = n % k + '0';} //<1>
else{a[i++] = n % k - 10 + 'A';} //<2>
这里我对一些我之前不熟悉的字符及字符数组相关知识点总结如下:
1.字符数组定义之后(如char a[15];)会自动将所有元素初始化为空字符'\0'(也就是NULL)。
顺嘴一提,空字符仍然是字符,不是空格,它常用来作为字符串的结束标志。
2. 字符可以比较,也可以加减计算。需要知道0~9数字的ASCII码是连续的,A~Z大写字母的ASCII码是连续的, a~z小写字母的ASCII码是连续的。再记住0~9数字的ASCII码 整体小于 A~Z大写字母的ASCII码 整体小于 a~z小写字母的ASCII码。也不用记得什么大写字母比小写字母ASCII码小32,直接用'a'-'A'就出来了。
因为字符就是用ASCII码存储和进行加减计算的,因此数字0~9转化为字符‘0’~‘9’只需要+‘0’就行了,这个‘0’虽然我们看作‘0’字符,但它在计算机里是ASCII码(十进制表示为48,二进制表示为00110000),因此48+0还是48,也就是‘0’+0还是‘0’。同理,将字符‘0’~‘9’转换为数字0~9只需要-‘0’就行了,比如字符‘1’的ASCII码是49,49-48就是1。那你可能会好奇,为什么这里的1就是数字1呢而不是ASCII码的1呢。其实我也好奇。然后我想通了。就是你用于存储的数据结构是int,计算机就会将00110000解释为48,你用于存储的数据结构是char,计算机就会将00110000看作ASCII码通过ASCII码对照表将它解释为字符‘0’。
那么数字10转换为字符'A',数字11转换为字符'B',...你会了吗?请思考一下。
没错 char c = number - 10 + 'A';即可实现上面所有啦。(当然也可以char c = number - 11 + 'B';...)
小技巧:想看哪个字符的ASCII码直接运行一下下面一行代码就可以了:
如printf(" %d",'A');就会显示字符‘A’的ASCII码。其中%d代表将'A'以整型输出,相当于把该字符用int型数据结构解释。
——————————————————————————————————————————
对于K进制转换为十进制的题:
首先依然先思考基本方法,可以使用逐位累加法。以2进制1011为例,十进制等于1*2的3次方 + 0*2的2次方 + 1*2的1次方 + 1*2的0次方。
然后考虑输入输出所需要用到的数据类型,输入使用整型变量或者字符数组(如果是二进制用1个整型变量就行了,不需要使用数组;如果是十六进制,则需要使用字符数组,因为整型变量无法存储A,B,C,D,E,F)。再就是输出的数据结构类型,输出一个十进制数,因此只需要使用一个整型变量即可。
由于这里输入有两种情况,整型变量or字符数组,因此这里我分开说:
1.对于一个整型如int数据结构存储的值,我们要获取它的某一位数字需要用到两个知识点:
一是计算机整型的除法运算‘/’;二是计算机整型的模运算‘%’
除法运算‘/’就是获取除法的商,如5/3等于1,2/3等于0。
模运算‘%’就是获取除法的余数,如5%3等于2,2%3等于2。
考虑一个数 123456789
123456789 / 10 等于 12345678;
123456789 % 10 等于 9。
你看出什么来了吗?12345678|9,对一个数,模10得最后1位数,除10得其余前面所有位。
那么取1位数就可以这样。(除取左,模取右)
取9:123456789 % 10 —— 12345678|9
取8:(123456789 / 10)%10——1234567|8
取7:(123456789 / 100)% 10——123456|7
取6:(123456789 / 1000)% 10——12345|6
......
取2:123456789 / 10000000)% 10——1|2
取1:123456789 / 100000000——1|
2.对于字符数组,我们获取它的1个字符很简单,遍历数组就可以访问到数组的每一位字符。对于十六进制数,将它存在字符数组中后,将各个字符取出时转化为对应整型数字在进行累加计算即可。
对整型变量or字符数组取1位数的总结:
1.整型变量,循环用模运算取个位数。(不管你规定它是二进制还是十进制还是什么K进制,我们计算机除法和模运算都是十进制运算,把它看作十进制来处理)
2.字符数组,访问数组元素转化为对应数字即可。
这篇文章就写到这里啦~希望下次遇到涉及进制转换的题,我们都能成功做出来哦。