您的位置:首页 > 其它

noj1011 大数加法 思路分析

2017-02-12 06:01 441 查看
题目链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1011

题目简介:大数加法,求两个非负整数(1000位以内)的和。

输入: 两个非负整数(1000位以内),以空格分隔。

输出:两个非负整数的和。

样例输入:111111111111 222222222222

样例输出:333333333333

分析

首先想到不能使用普通的数据类型int或double来存数据,需要自己写一个数据结构来满足超多位数数字的存储与运算。

于是想到可以用字符数组来存储超长数字:两个这样的大数相加时,我们从两个数字的个位开始相加,判断进位后再进行十位的相加,以此类推。这里两个数字不一样长的情况也要考虑进去。

class BigNum
{
public:
char str[1002];

BigNum(char strArr[]);
BigNum();
BigNum Add(BigNum a);
void ReadIn();
void PrintOut();
void Reserve();
};


其中char str[1002]是用来存放整个大数的,往下两个是构造函数,再往下是加法,读入,输出函数,最后一个是反转函数,用来将str的字符串整个倒置。

为什么需要这个Reserve函数呢?我们分析一下。

在加法计算中,需要从个位开始。比如

1 2 3 4
+ 5 6 7 8
-------------


我们需要先计算4+8。

如果我们将1234正向存入数组中,那么str[0]==1,str[1]==2,str[2]==3,str[3]==4,加法计算时需要从str[3]开始,并向str[2]进位。如果两个数字位数相同的话,处理起来还算方便;但是如果两个数字位数不同(如1234+567),处理起来又会多了很多麻烦。所以为什么不从一开始就省去这些麻烦呢?

所以我们采取这样的方式:数字在类中的存储与计算全部是倒置进行的,只有输出的时候逆序输出就好了。 比如我们计算1234+567时有

bignum1     str[0] str[1] str[2] str[3]
4       3       2       1
+
bignum2     str[0] str[1] str[2]
5       6       7
-----------------------------------------
bignum3     9       9       9       1


bignum3中存的数据是9991,在输出时倒序输出为1999就可以了。这样子计算过程会简单很多。

接下来是两个构造函数,只要初始化就可以了

BigNum::BigNum()
{
memset(this->str,'\0',sizeof(this->str));
}

BigNum::BigNum(char strArr[])
{
memset(this->str,'\0',sizeof(this->str));
strcpy(this->str,strArr);
}


接下来是输入函数,输入字符串,并且将字符串倒置。

void BigNum::ReadIn()
{
cin>>this->str;
this->Reserve();
}


输出函数,倒序输出即可:

void BigNum::PrintOut()
{
for(int i=strlen(this->str)-1;i>=0;i--)
cout<<this->str[i];
cout<<endl;
}


倒置的函数:

void BigNum::Reserve()
{
int i=0;
int j=strlen(this->str) -1;
while(i<j)
{
char c=this->str[i];
this->str[i]=this->str[j];
this->str[j]=c;
i++;
j--;
}
}


最后是加法函数了

BigNum BigNum::Add(BigNum a) //返回值为BigNum类型
{
char strArr[1002]; //this + a 结果存在 strArr
memset(strArr,'\0',sizeof(strArr));
int flag=0;   //进位 if carry (at one position the add result >=10,so the next position need to add a extre 1)
for(int i=0;i<1002;i++)
{
//the two num both stop and flag==0,break
if(a.str[i]=='\0' && this->str[i]=='\0' && flag==0) break;

//the two num both not stop
if(a.str[i]!='\0' && this->str[i]!='\0')
{
int aa=(int)a.str[i]-48; //字符串中int数据提取
int bb=(int)this->str[i]-48;
int cc=aa+bb+flag; //该位进行加法运算,进位不能忘
if(cc>9) //该位的进位判断
{
flag=1;
cc-=10;
}
else
{
flag=0;
}
strArr[i]=cc+48; //使用int型计算完了,再转换为char型存储
}

//a not stop,大数a比较长
else if(a.str[i]!='\0')
{
if(flag==1)
{
int aa=(int)a.str[i]-48;
aa+=1;
flag=0;
if(aa==10)
{
flag=1;
aa=0;
}
strArr[i]=aa+48;
}
else
strArr[i]=a.str[i];
}
//this not stop,this大数比较长
else if(this->str[i]!='\0')
{
if(flag==1)
{
int aa=(int)this->str[i]-48;
aa+=1;
flag=0;
if(aa==10)
{
flag=1;
aa=0;
}
strArr[i]=aa+48;
}
else
strArr[i]=this->str[i];
}
//both two num stop, but flag==1,两个数到这一位都没了,但是进位上还有1. 比如90+10=100
else if(flag==1)
{
strArr[i]='1';
flag=0;
}

}
BigNum rst(strArr); //使用计算得到的strArr来构造大数BigNum
return rst; //返回该大数
}


main函数

int main()
{
BigNum a,b;
a.ReadIn();
b.ReadIn();
BigNum c=a.Add(b);
c.PrintOut();
return 0;
}


当很久之后回过头来看看曾经解决过的问题,会发现曾经的自己解决的方法是那么蠢。哈,发现过去的自己蠢,才说明自己成长了吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息