《编程思维与实践》1063.二进制倒置
题目
思路
关键点在于求出倒置后的二进制位: 由进制知识可以知道通过do while将每次%2的结果正着存就是倒置的二进制位,
所以问题进而转化为如何进行大整数的除法和余数的记录.
由于除法的过程中可能最高位数字变为0从而导致位数应该减1,所以逆向存(从个位开始存)更方便处理.
最后再依次进行大整数的乘2+二进制位得出结果即可.
其中,除法完全模拟笔除即可: 从最高位开始除以除数和上一位的余数*10之和,再记录余数即可.
注意的点:
1.加法有可能会导致位数增加,为了方便起见复用carry进位时可以补充对位数的处理;
2.二进制位最多为334,十进制位最多位101,不妨统一取最大N为334.
代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 334
typedef struct{int cnt,v[N];}BIGINT;
BIGINT carry(BIGINT S,int n); //进位 n表示进制
BIGINT int2BIG(int x,int bin); //int 转换(to)成BIGINT
BIGINT mul(BIGINT S,BIGINT T); //两个大整数相乘
int div_(BIGINT* S,int n); //做除法同时返回余数
BIGINT trans(BIGINT S,int n); //十进制转化成n进制
BIGINT add(BIGINT S, BIGINT T); //两个大整数相加
int main()
{
int T;
scanf("%d",&T);
for(int t=0;t<T;t++)
{
BIGINT num={0,{0}};
char s[101];
scanf("%s",s);
num.cnt=strlen(s);
for(int i=0;i<strlen(s);i++)
{
num.v[num.cnt-1-i]=s[i]-'0'; //逆向存
}
printf("case #%d:\n",t);
BIGINT bin=trans(num,2); //转换成二进制
BIGINT ans={0,{0}}; //结果 answer
for(int i=0;i<bin.cnt;i++)
{
ans=mul(ans,int2BIG(2,10)); //*2
ans=add(ans,int2BIG(bin.v[i],10)); //+二进制位0
}
for(int i=ans.cnt-1;i>=0;i--) //逆向输出
{
printf("%d",ans.v[i]);
}
printf("\n");
}
return 0;
}
BIGINT carry(BIGINT S,int n) //进位 n表示进制
{
int flag=0;
for(int i=0;i<S.cnt;i++)
{
int temp=S.v[i]+flag;
S.v[i]=temp%n;
flag=temp/n;
}
if(flag) //为了加法进行的方便 可能多一位
{
S.v[S.cnt++]=flag;
}
return S;
}
BIGINT int2BIG(int x,int bin) //int 转换(to)成BIGINT
{
BIGINT R={0,{0}};
do
{
R.v[R.cnt++]=x%bin;
x/=bin;
}while(x>0);
return R;
}
BIGINT mul(BIGINT S,BIGINT T) //两个大整数相乘
{
BIGINT R={S.cnt+T.cnt,{0}}; //位数最多为两者相加
for(int i=0;i<T.cnt;i++)
{
for (int j=0;j<S.cnt;j++)
{
R.v[i+j]+=S.v[j]*T.v[i]; //依此进行普通乘法
}
}
R=carry(R,10);
while(R.v[R.cnt-1]==0&&R.cnt>1)
{
R.cnt--; //最高位0不统计在一个大整数的位数中
}
return R;
}
int div_(BIGINT* S,int n) //做除法同时返回余数
{
int ret=0;
for(int i=S->cnt-1;i>=0;i--)
{
int temp=S->v[i]+ret*10;
S->v[i]=temp/n;
ret=temp-S->v[i]*n;
}
if(S->v[S->cnt-1]==0) //最高位变为0 位数减1
{
S->cnt--;
}
return ret;
}
BIGINT trans(BIGINT S,int n) //十进制转化成n进制
{
BIGINT bin={0,{0}};
while(S.cnt>0)
{
bin.v[bin.cnt++]=div_(&S,2);
}
return bin;
}
BIGINT add(BIGINT S, BIGINT T) //两个大整数相加
{
int max=S.cnt>T.cnt?S.cnt:T.cnt;
BIGINT R={max,{0}};
for(int i=0;i<max;i++)
{
R.v[i]=S.v[i]+T.v[i]; //依次进行普通乘法
}
R=carry(R,10);
return R;
}