模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进制为例):

posted @ 2020-05-29 18:16  小柒w  阅读(622)  评论(0编辑  收藏  举报