十六进制转八进制
1.问题详情
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由09、大写字母AF组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
2.解题思路
这道题提示了先转化成某进制,我一开始就会想到转换成十进制,但后来我发现某些测试用例的十六进制数的长度太长,转化为十进制后连long long都容不下,所以就转换思路,将其转换为二进制,发现如果十六进制数长度最长为100000,二进制长度也就400000,并且可以用三个string字符串来存储一个数的十六进制,二进制以及八进制。
3.解题代码
#include<iostream>
#include<string>
using namespace std;
int main(){
int n;//输入的16进制数的个数
string s1,s2,s3;//s1为输入的十六进制串,s2为转化的二进制串,s3为八进制字符串
cin>>n;
for(int i=0;i<n;i++){
cin>>s1;
s2="";//初始化s2
for(int i=0;i<s1.length();i++){//string字符串高位字符存在低位地址,故可以从下标0开始遍历字符串s1将其转化为s2
switch(s1[i]){
case '0':s2+="0000";break;
case '1':s2+="0001";break;
case '2':s2+="0010";break;
case '3':s2+="0011";break;
case '4':s2+="0100";break;
case '5':s2+="0101";break;
case '6':s2+="0110";break;
case '7':s2+="0111";break;
case '8':s2+="1000";break;
case '9':s2+="1001";break;
case 'A':s2+="1010";break;
case 'B':s2+="1011";break;
case 'C':s2+="1100";break;
case 'D':s2+="1101";break;
case 'E':s2+="1110";break;
case 'F':s2+="1111";break;
default:break;
}
}
s3="";//初始化s3
int j=0,k;
while(s2[j]=='0'){//找到第一个不是字符‘0’的位置,使转化的八进制没有前导0
j++;
}
for(k=s2.length()-3;k>=j;k=k-3){//从低位字符开始转化,即从高位地址开始,初始值k要减3是因为要截取其后的3个二进制数
string s="";//临时存储截取的字符串
s=s2.substr(k,3);
if(s=="000")
s3+="0";
else if(s=="001")
s3+="1";
else if(s=="010")
s3+="2";
else if(s=="011")
s3+="3";
else if(s=="100")
s3+="4";
else if(s=="101")
s3+="5";
else if(s=="110")
s3+="6";
else if(s=="111")
s3+="7";
}
if(k==j-1){//如果k等于j-1,说明高位字符还有两个二进制数没有转化为八进制,由于去掉了前导0,从j开始的两个二进制数只能是"10"或"11"
string s=s2.substr(k+1,2);
if(s=="10")
s3+="2";
else
s3+="3";
}
if(k==j-2){//如果k等于j-2,说明高位字符有一个二进制数没有转化为八进制,由于去掉了前导0,从j开始的一个二进制数只能是"1"
string s=s2.substr(k+2,1);
if(s=="1")
s3+="1";
}
for(int i=s3.length()-1;i>=0;i--)//由于转化时s2的低位字符转化到了s3的高位字符,故需要倒序输出正确结果
cout<<s3[i];
cout<<endl;
}
return 0;
}
需要注意的是二进制在转化为八进制时要把二进制的前导0去掉,而且若是二进制的位数不是3的倍数时,要将剩下的2个或1个二进制位数转化为八进数。