模N取余法实现大整数进制转换 ——C语言版(2-16进制均可)
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。
个人推荐先到这篇博客学习一下,大佬的思路就是不一样:大数除法——超详细讲解
我所做的就是在上面博文代码的基础上增加了循环,用一个字符数组逆序存储余数,最后再逆序输出就得到了正确结果。具体代码及注释如下,目前我本人测试无误,能够正确运行。如果有的朋友准备拿这份代码在Leetcode之类的网站进行提交的话,希望可以再优化一下(这个执行效率不算太理想)。有什么看不懂的地方或者代码里出现错误,欢迎在评论区留言,我会及时回复的。
#include<stdio.h> #include<string.h> /* * 整体思路就是模n取余,每次做完除法得到的商再次除以n,直到商小于除数 */ char a[100],b[100],z[100],m[100];//要转换的数 进制 商 进制转换后的表示数 int x[100],y[100];//被除数 除数 int digit; //大数的位数 void sub(int x[],int y[],int len1,int len2)//大数减法 { int i; for(i=0;i<len1;i++) { if(x[i]<y[i])//当前位不够减,借位 { x[i]=x[i]+10-y[i]; x[i+1]--; } else//够减,无需借位 x[i]=x[i]-y[i]; } for(i=len1-1;i>=0;i--)//判断减法结束之后,被除数的位数 { if(x[i]) { digit=i+1; break; } } } int judge(int x[],int y[],int len1,int len2) {//比较x,y数组长度的函数 int i; if(len1<len2) return -1; if(len1==len2)//若两个数位数相等 { for(i=len1-1;i>=0;i--) { if(x[i]==y[i])//对应位的数相等 continue; if(x[i]>y[i])//被除数 大于 除数,返回值为1 return 1; if(x[i]<y[i])//被除数 小于 除数,返回值为-1 return -1; } return 0;//被除数 等于 除数,返回值为0 } } int changeBase(int len1, int len2) {//进制转换 int i,j=0,k,in=0,temp;//数组下标和变量 int len;//len两个大数位数的差值 while(len1>1||a[0]!='0')//只要被除数仍然大于'0',那就继续做除法 { //将字符串中各个元素倒序储存在数组中 for(i=len1-1,j=0;i>=0;i--) { x[j++]=a[i]-'0'; } for(i=len2-1,k=0;i>=0;i--) { y[k++]=b[i]-'0'; } if(len1<len2) { //当被除数位数 小于 除数位数时 int rest=0;//变量,保存余数的值 for(i=len1;i>0;i--) {//跳过前导0 if(x[i]) break; } //算出余数并将余数转换为16进制 for(;i>=0;i--) rest=rest*10+x[i]; if(rest<10)//字符0的ASCII码值为48,存储余数小于10数字时要加48 m[in++]=rest+48; else//字符A的ASCII码值为65,存储余数对应的大于等于10的数字时要加55,即’A‘,'B'…… m[in++]=rest+55; break; } else //当被除数位数 大于或者等于 除数位数时 { len=len1-len2;//两个大数位数的差值 for(i=len1-1;i>=0;i--)//将除数后补零,使得两个大数位数相同。 { if(i>=len) y[i]=y[i-len]; else y[i]=0; } len2=len1;//将两个大数数位相同 digit=len1; //将原被除数位数赋值给digit for(j=0;j<=len;j++) { z[len-j]='0'; while(((temp=judge(x,y,len1,len2))>=0)&&digit>=k)//判断两个数的大小以及被除数位数与除数原位数的关系 { sub(x,y,len1,len2); //大数减法函数 z[len-j]++;//储存商的每一位 len1=digit;//重新修改被除数的长度 if(len1<len2&&y[len2-1]==0) len2=len1; //将len1长度赋给len2; } if(temp<0)//若被除数 小于 除数,除数减小一位。 { for(i=1;i<len2;i++) y[i-1]=y[i]; y[i-1]=0; if(len1<len2) len2--; } } for(i=len;i>0;i--)//跳过前导0 { if(z[i]!='0') break; } int t=0,rest=0; for(;i>=0;i--,t++)//把商复制给 a数组,继续做被除数 a[t]=z[i]; a[t]='\0'; for(i=len1;i>0;i--)//跳过前导0 { if(x[i]) break; } //算出余数并将余数转换为16进制 for(;i>=0;i--) rest=rest*10+x[i]; if(rest<10) m[in++]=rest+48; else m[in++]=rest+55; len1=strlen(a);//重新计算被除数位数 len2=strlen(b);//重新计算除数位数 } } return in;//返回m数组的长度 } int main() { int l1,l2,k; printf("请依次输入要转换的数和对应进制:\n"); scanf("%s %s",a,b);//a表示要转换的大整数,b代表要转换的进制 l1=strlen(a);//被除数位数 l2=strlen(b);//除数位数 //进行进制转换 k=changeBase(l1,l2); printf("转换之后对应的数为:\n"); for(k-=1;k>-1;k--)//输出转换后的进制数 printf("%c",m[k]); return 0; }
使用示范(以转换为16进制为例):