"蓝桥杯“基础练习:十六进制转八进制

介绍一种高效的算法,用于将大规模十六进制数(不超过100,000位)转换为对应的八进制数,避免直接转换为十进制带来的计算复杂性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


问题描述
  给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
  输入的第一行为一个正整数n (1<=n<=10)。
  接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
  输出n行,每行为输入对应的八进制正整数。
注意
  输入的十六进制数不会有前导0,比如012A。
  输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
提示
  先将十六进制数转换成某进制数,再由某进制数转换成八进制。

心得:

题目有些难度,一开始想的是把16进制先转化为10进制,因为从10进制转化为8进制很容易。但是题目中输入的16进制位数规模大,不超过100000位,肯定不能化为10进制数。解法是先把16进制化为四个2进制数,然后三个二进制数一组再化为8进制。 注意 39(16进制)--〉0011    1001   (2进制) --〉111  001(8进制),是从二进制的低位开始三个一组来计算。

代码:

  1. #include <iostream>
  2. #include <string.h>
  3. #include <stack>
  4. using namespace std;
  5. int fib(int n)//计算2的多少次方
  6. {
  7. int sum=1;
  8. if(n==0)
  9. return 1;
  10. else
  11. {
  12. for(int i=1;i<=n;i++)
  13. sum*=2;
  14. return sum;
  15. }
  16. }
  17. string str[11];
  18. int two[400008];//因为16进制的位数不超过100000,所以换成二进制数位数不超过400000
  19. int main()
  20. {
  21. int n,i,j,k;
  22. cin>>n;
  23. for(int k=1;k<=n;++k)
  24. {
  25. cin>>str[k];
  26. memset(two,0,sizeof(two));
  27. for( i=0;i<str[k].length();++i)//把十六进制的每一位变成4个二进制数,注意存放的顺序
  28. {
  29. if(str[k][i]>='0'&&str[k][i]<='9')
  30. {
  31. int temp=str[k][i]-'0';
  32. int tap=4*(i+1);//把two数组每4个元素为一组,连续,当前的十六进制位为two数组的最大下标+1
  33. while(temp)
  34. {
  35. two[--tap]=temp%2;//首先要tap-1,因为two数组是从0开始的,这也解释了为什么上面说是最大下标+1
  36. temp/=2;
  37. }
  38. }
  39. else
  40. {
  41. int temp=str[k][i]-55;//A-55得10
  42. int tap=4*(i+1);
  43. while(temp)
  44. {
  45. two[--tap]=temp%2;
  46. temp/=2;
  47. }
  48. }
  49. }//到目前为止把16进制转成了二进制
  50. int count=0;//二进制数三位一组来转化为8进制
  51. int sum=0;//连续三位二进制数的值
  52. stack<int>q;
  53. for(j=4*str[k].length()-1;j>=0;--j)//从two数组的存数的最大下标开始处理,每三个为一组,转化为8进制,保存在栈中
  54. {
  55. sum+=(two[j]*fib(count++));
  56. if(count==3)
  57. {
  58. q.push(sum);
  59. sum=0;
  60. count=0;
  61. }
  62. }
  63. int sum1=0;//考虑处理的末尾,可能最后一组少于3个,有可能是一个,也可能是两个,单独处理,单独输出
  64. int c=0;
  65. for(int m=4*str[k].length()%3-1;m>=0;--m)//4*str[k].length()%3判断还剩下几个
  66. {
  67. sum1+=two[c++]*fib(m);
  68. }
  69. if(sum1!=0)
  70. cout<<sum1;//单独输出
  71. if(q.top()==0)
  72. q.pop();//去除前导0,如果有的话
  73. while(!q.empty())
  74. {
  75. cout<<q.top();//从栈中输出
  76. q.pop();
  77. }
  78. cout<<endl;
  79. }
  80. return 0;
  81. }

运行:


2014.3.4日修改

上面写的代码太复杂了,看到同学写的该题,受到了启发。十六进制转二进制不用上面代码那么麻烦。

另一种解法如下:

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. int main()
  5. {
  6. int n;
  7. cin>>n;
  8. for(int k=1;k<=n;k++)
  9. {
  10. string s1,s2;//s1为输入的原始的十六进制串,s2为转化成的二进制串
  11. cin>>s1;
  12. s2="";//初始化
  13. for(int i=0;i<s1.length();i++)//遍历,字符串上加上每一位
  14. {
  15. switch(s1[i])
  16. {
  17. case '0':s2+="0000";break;
  18. case '1':s2+="0001";break;
  19. case '2':s2+="0010";break;
  20. case '3':s2+="0011";break;
  21. case '4':s2+="0100";break;
  22. case '5':s2+="0101";break;
  23. case '6':s2+="0110";break;
  24. case '7':s2+="0111";break;
  25. case '8':s2+="1000";break;
  26. case '9':s2+="1001";break;
  27. case 'A':s2+="1010";break;
  28. case 'B':s2+="1011";break;
  29. case 'C':s2+="1100";break;
  30. case 'D':s2+="1101";break;
  31. case 'E':s2+="1110";break;
  32. case 'F':s2+="1111";break;
  33. default:break;
  34. }
  35. }
  36. int len=s2.length();
  37. if(len%3==1)//三个二进制为一位八进制,二进制串前面补0,确保二进制串的长度为3的倍数
  38. s2="00"+s2;
  39. else if(len%3==2)
  40. s2="0"+s2;
  41. int flag=0;
  42. for(int i=0;i<=s2.length()-3;i+=3)
  43. {
  44. int num=4*(s2[i]-'0')+2*(s2[i+1]-'0')+(s2[i+2]-'0');
  45. if(num)
  46. flag=1;//忽略前导0
  47. if(flag)
  48. cout<<num;
  49. }
  50. cout<<endl;
  51. }
  52. return 0;
  53. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值