《编程思维与实践》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的倍数,则Base编码数为4的倍数,
所以为了满足字符总数为3的倍数,需要在不满4倍数的编码数后添加’='对应的编码(不妨记为64),
之后只需要遍历字符串即可,每读三次更新一轮.
注意的点:
1.读取前半部分时指标不需要++,读取后半部分时才++,特别地,处于开头或者最后一个字符时,需要直接++;
2.需要补’=‘的情况只有非3的倍数的情况,由于读取编码前半部分时指标没有++,所以补’='时需要++;
代码
#include<stdio.h>
#include<string.h>
char chart[66]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}; //'='编码记为64
int 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;
}