进阶题目1005 大数加法(C实现)


前言

这是51nod进阶题库中编号为1005的一道题目,题目非常简单,但是需要考虑的细节问题有很多,我们接下来分析一下该题目如何实现。


一、题目概述

给出2个大整数A,B,计算A+B的结果。

二、实现思路

题目非常简单,读完题目以后首先我们需要知道什么是大整数?

大整数

想知道什么是大整数,不如换一个解释的方法:什么时候需要用到大整数?众所周知,int类型的范围是-2147483648~2147483647。long long类型的范围是 -2^63 ~ (2^63)-1。那当题目需要用到或需要输出比long long类型的范围还要大的数字时,我们是不是就不能用常规办法去接收这些数字了。这个时候使用大整数就可以解决上述问题。即解决接收超出long long范围数字的问题。

既然大整数无法用常规的类型来进行保存,我们就要用到另一种方式来保存大整数,对于大整数的保存一般采用字符数组的形式来进行保存。

保存之后我们进行运算,由于加法运算是从低位到高位进行相加,而我们保存的字符大整数是从高位到低位进行保存的,还存在字符首位是 “-” 的情况,所以我们需要将字符数组转化为数字数组并逆序保存,方便后面运算。

分类

大整数的加法可以分成三类:

  1. 正正相加
    两个正的大整数相加和加法运算没有区别,需要考虑的只有进位问题和相加后结果的位数。
  2. 正负相加
    一正一负的情况我们需要考虑结果的正负问题,首先我们将负大整数去掉负号以后和正大整数比较字符长度,结果的正负取长度长的数据。
    如果两个长度相等,此时我们就要逐位比较大小来确定结果正负。
    确定完正负以后,按位相减,注意借位。
  3. 负负相加
    同负的情况和同正的计算方法一样,只需将结果取负即可。

三、实现过程

1.定义大整数结构体

#define MAX     100
struct long_num
{
    char s_num[MAX]; // 字符数组
    int num[MAX];    // 数字数组
    size_t size;     // 字符长度
    bool SIGNEN_FLAG;// 正负标志 bool为正 false为负
};

2.实现相加

struct long_num add(struct long_num *f,struct long_num *s) {
     int i = 0;
     struct long_num temp={{0},{0},0,true};

     // 计算长度
     f->size = strlen(f->s_num);
     s->size = strlen(s->s_num);

     // 字符数组 转化为 数字数组 并 逆置 判断正负
     if (f->s_num[0] == '-')// 判断正负  负
     {
         f->SIGNEN_FLAG = false;
         for (i = 1; i < f->size; i++)// f
         {
             f->num[f->size - i - 1] = f->s_num[i] - '0';
         }
     }
     else// 正
     {
         f->SIGNEN_FLAG = true;
         for (i = 0; i < f->size; i++)// f
         {
             f->num[f->size - i - 1] = f->s_num[i] - '0';
         }
     }
     //同上
     if (s->s_num[0] == '-')
     {
         s->SIGNEN_FLAG = false;
         for (i = 1; i < s->size; i++)// s
         {
             s->num[s->size - i - 1] = s->s_num[i] - '0';
         }
     }
     else
     {
         s->SIGNEN_FLAG = true;
         for (i = 0; i < s->size; i++)// s
         {
             s->num[s->size - i - 1] = s->s_num[i] - '0';
         }
     }

     // 实现相加

     if(f->SIGNEN_FLAG && s->SIGNEN_FLAG)// 同正
     {
         for ( i = 0; i < max(f->size,s->size); ++i)
         {
             temp.num[i] += f->num[i] + s->num[i]; // 对应位相加
             if (temp.num[i] > 9) // 判断是否进位
             {
                 temp.num[i] -= 10;
                 temp.num[i + 1] += 1; // 高位加一
             }
         }
         temp.SIGNEN_FLAG = true;// 确定结果正负
         if(temp.num[i] != 0)//确定结果有多少位
             temp.size = max(f->size,s->size) + 1;
         else
             temp.size = max(f->size,s->size);
     }

    // 同负 原理和同正一样 结果为负
     if(f->SIGNEN_FLAG == false && s->SIGNEN_FLAG == false)
   {
         for ( i = 0; i < max(f->size,s->size) - 1 ; ++i)
         {
             temp.num[i] += f->num[i] + s->num[i];
             if (temp.num[i] > 9)
             {
                 temp.num[i] -= 10;
                 temp.num[i + 1] += 1; // 高位加一
             }
         }
         temp.SIGNEN_FLAG = false;
         if(temp.num[i] != 0)
             temp.size = max(f->size,s->size) + 1;
         else
             temp.size = max(f->size,s->size);
   }

    // 一正一负
     if(f->SIGNEN_FLAG == false && s->SIGNEN_FLAG == true)
         temp = count(f,s);
     if(s->SIGNEN_FLAG == false && f->SIGNEN_FLAG == true)
         temp = count(s,f);

     //temp.size = max(f->size,s->size);
     if(temp.SIGNEN_FLAG == true) // 结果为正 将数字数组值逆序存入字符数组
     {
         for ( i = 0; i < temp.size; ++i)
             temp.s_num[temp.size - 1 - i] = temp.num[i] + '0';
     }
     else// 结果为负  将负号存入字符数组首位 将数字数组值逆序存入字符数组
     {
         temp.s_num[0] = '-';
         for ( i = 0; i < temp.size - 1; ++i)
             temp.s_num[temp.size - 1 - i] = temp.num[i] + '0';
     }
     return temp;
}

3正负相加的实现

struct long_num count(struct long_num *f,struct long_num *s)// 计算一正一负的类型 第一个为负 第二个为正
{
    int i;
    struct long_num temp = {{0},{0},0,true}; /// 中间值 保存结果


    if(f->SIGNEN_FLAG == false && s->SIGNEN_FLAG == true) // 第一参数为负 第二参数为正
    {
        if (f->size -1 > s->size)// 剔除负号 比较数据长度 如果 f 长度 大于 s 长度
        {
            for ( i = 0; i < (f->size - 1); ++i)
            {
                temp.num[i] += f->num[i] - s->num[i]; //做减法运算 存入temp

                if (temp.num[i] < 0) // 判断是否借位
                {
                    temp.num[i] += 10;
                    temp.num[i + 1] -= 1;
                }
            }
            temp.SIGNEN_FLAG = false; // 结果为负

            temp.size = f->size;
            for (int j = i-1; j > 0; --j)//去前置0
            {
                if(temp.num[j] != 0)
                    break;
                else
                    temp.size--;
            }
        }

        if (f->size - 1 < s->size)// 如果 f 长度 小于 s 长度 结果为正
        {
            for (i = 0; i < (s->size); ++i)
            {
                temp.num[i] += s->num[i] - f->num[i];
                if (temp.num[i] < 0)
                {
                    temp.num[i] += 10;
                    temp.num[i + 1] -= 1;
                }
            }
            temp.SIGNEN_FLAG = true;
            temp.size = s->size;
            for (int j = i-1; j > 0; --j)//去前置0
            {
                if(temp.num[j] != 0)
                    break;
                else
                    temp.size--;
            }
        }

        if (f->size -1 == s->size)// 如果 f 长度 等于 s 长度
        {
            //char * str = f->s_num+1;
            int compare = strcmp(f->s_num + 1,s->s_num);// 判断谁的值大

            if(compare == 0) // 两值相等
            {
                temp.s_num[0] = '0';
                temp.size = 1;
            }

            if(compare < 0) // f 的值小于 s 的值
            {
                for (i = 0; i < (f->size - 1); ++i)
                {
                    temp.num[i] += s->num[i] - f->num[i];

                    if (temp.num[i] < 0) // 是否借位
                    {
                        temp.num[i] += 10;
                        temp.num[i + 1] -= 1;
                    }
                }
                temp.SIGNEN_FLAG = true;
                temp.size = s->size;
                for (int j = i-1; j > 0; --j)// 剔除前置0
                {
                    if(temp.num[j] != 0)
                        break;
                    else
                        temp.size--;
                }
            }

            if(compare > 0) // f 的值小于 s 的值
            {
                for (i = 0; i < (f->size - 1); ++i)
                {
                    temp.num[i] += f->num[i] - s->num[i];
                    if (temp.num[i] < 0)
                    {
                        temp.num[i] += 10;
                        temp.num[i + 1] -= 1;
                    }
                }
                temp.SIGNEN_FLAG = false;
                temp.size = f->size;
                for (int j = i - 1; j > 0; --j)
                {
                    if (temp.num[j] != 0)
                        break;
                    else
                        temp.size--;
                }
            }
        }
    }
    return temp;// 返回结果
}

4结果测试

在这里插入图片描述


遇到的问题

在进行正负大整数相加运算时,当两个数字数组长度相同时,例如-1732和1700进行运算时,输出结果为-0032,前面的0也保存了下来,这是不需要的,这是由于结果的字符长度计算出现了问题 我们需要剔除前置0,
解决代码如下:

for (int j = i-1; j > 0; --j)//去前置0
            {
                if(temp.num[j] != 0)
                    break;
                else
                    temp.size--;
            }

到这里大整数的加法基本实现,以上是个人的一些拙见,请各位大佬指正!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值