《编程思维与实践》1047.Base64编码
题目
思路
直接模拟:将每个Base64编码值都分为两部分:前半部分由上一个字符求得,后半部分由下一个字符求得.
特别地,如果字符为第一个或最后一个,则直接可以求得Base64编码.
如下图:
其中,% 2 n 2^n 2n表示取出后n位的二进制位,这是因为 N % 2 n = ( 2 k + 2 k − 1 + . . . + 2 + 2 0 ) % 2 n = 2 n − 1 + . . . + 2 + 2 0 N\,\%\,2^n=(2^{k}+2^{k-1}+...+2+2^0)\,\%\,2^n=2^{n-1}+...+2+2^0 N%2n=(2k+2k−1+...+2+20)%2n=2n−1+...+2+20;
如果字符总数不为3的倍数,则需要添加’='对应的编码(不妨记为64),
之后只需要遍历字符串即可,每读三次更新一轮.
注意的点:
1.读取前半部分时指标不需要++,读取后半部分时才++,特别地,处于开头或者最后一个字符时,需要直接++;
2.需要补’=‘的情况只有非3的倍数的情况,由于读取编码前半部分时指标没有++,所以补’='时需要++;
代码
#include<stdio.h>
#include<string.h>char chart[66]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}; //'='编码记为64int main()
{int T;scanf("%d",&T);for(int t=0;t<T;t++){char s[101];scanf("%s",s);char ans[300]; //answer 存Base64编码printf("case #%d:\n",t);int j=0,cnt=0; //j为ans指标 cnt记录读几个字符for(int i=0;i<strlen(s);i++) {if(cnt==0) //处理每三个字符中的第一个{ans[j++]=s[i]>>2; //第一个Base64 开头直接++ans[j]=(s[i]%4)<<4; //第二个Base64的前半部分}else if(cnt==1) //处理第二个{ans[j++]+=s[i]>>4; //第二个Base64的后半部分ans[j]=(s[i]%16)<<2; //第三个Base64的前半部分 }else //处理第三个{ans[j++]+=s[i]>>6; //第三个Base64的后半部分 ans[j++]=s[i]%64; //第四个Base64 最后一个也++ }cnt=(++cnt)%3; //注意这里要先自增再模3 每3次cnt更新重置为0}if(cnt==1) //剩一个字符{j++; //因为只读前半部分没有++ 所以需要人为++ans[j++]=64; //补两个'='ans[j++]=64;}else if(cnt==2) //剩两个字符{j++; //因为只读前半部分没有++ 所以需要人为++ans[j++]=64;}for(int i=0;i<j;i++){printf("%c",chart[ans[i]]); //按编码输出对应的字符}printf("\n");}return 0;
}