题目背景
大数用内置类型是存不下的,32位操作系统中int最大存储2^31-1 = 2147483647,long:2147483648 ,logn long:9223372036854775807
所以一般用字符串来存储非常大的数据
请实现以下类的方法,完成大数的加减法
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
//题目:请实现以下类的方法,完成大数的加减法
class BigInt
{
public:
BigInt(string str): strDigit(str) {}
private:
string strDigit; //使用字符串存储大整数
friend ostream& operator<<(ostream &out, const BigInt &src);
friend BigInt operator+(const BigInt &lhs, const BigInt &rhs);
friend BigInt operator-(const BigInt &lhs, const BigInt &rhs);
};
//打印函数
ostream& operator<<(ostream & out, const BigInt &src)
{
out << src.strDigit;
return out;
}
大数加法
思路:
- 从后往前遍历两个字符串,同位相加,每次相加都要考虑进位
- 将每次相加的结果存入一个容器,最后将容器中的数据翻转输出
// 大数加法
BigInt operator+(const BigInt &lhs, const BigInt &rhs)
{
/*
遍历字符串l,r,从后往前遍历
同位置的数字相加, 进位 flag 存入一个结果当中 string result
同时完成
某个字符串先完成 都要考虑进位
*/
string result;
bool flag = false;
int i = lhs.strDigit.length() - 1;
int j = rhs.strDigit.length() - 1;
for (; i >= 0 && j >= 0; --i, --j)//两个字符串同时从后往前遍历
{
int ret = lhs.strDigit[i] - '0' + rhs.strDigit[j] - '0';
if (flag)//上次加有进位
{
ret += 1;
flag = false;
}
if (ret >= 10)//本次加需要进位
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
}
if (i >= 0)//第一个字符串还没完
{
while (i >= 0)
{
int ret = lhs.strDigit[i] - '0';
if (flag)
{
ret += 1;
flag = false;
}
if (ret >= 10)
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
i--;
}
}
else if (j >= 0)//第二个字符串还没完
{
while (j >= 0)
{
int ret = rhs.strDigit[j] - '0';
if (flag)
{
ret += 1;
flag = false;
}
if (ret >= 10)
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
j--;
}
}
if (flag)//还有进位,在最高位添加一个1
{
result.push_back('1');
}
reverse(result.begin(), result.end());//reverse泛型算法用于反转在[first,last)范围内的元素
return result; //隐式类型转换:相当于return BigInt(result);
}
大数减法
思路:
- 先找出谁大谁小,如果是大-小,直接返回结果,小减大,返回-(大-小)
- 从后往前遍历,相减,每次都要考虑是否进位,减完处理大数剩余的串
- 1234-1233 = 0001,直接输出1就可以了,所以最后要处理结果高位连续的0
// 大数减法
BigInt operator-(const BigInt &lhs, const BigInt &rhs)
{
/*
找大的字符串左减数,小的左被减数
遍历两个字符串,减法,借位(bool flag), string result 存下来
*/
string result;
bool flag = false;
bool minor = false; //最后的结果是否需要添加负号
string maxStr = lhs.strDigit;
string minStr = rhs.strDigit;
//找出谁大谁小,分别用maxStr与minStr保存
if (maxStr.length() < minStr.length())
{
maxStr = rhs.strDigit;
minStr = lhs.strDigit;
minor = true;
}
else if (maxStr.length() == minStr.length())
{
if (maxStr < minStr)
{
maxStr = rhs.strDigit;
minStr = lhs.strDigit;
minor = true;
}
else if (maxStr == minStr)
{
return string("0");
}
}
else
{
//maxStr = lhs.strDigit;默认就是这个,所以这里什么都不用做
//minStr = rhs.strDigit;
;
}
//从后往前遍历,相减
int i = maxStr.length() - 1;
int j = minStr.length() - 1;
for (; i >= 0 && j >= 0; --i, --j)
{
int ret = maxStr[i] - minStr[j];
if (flag)//上一次减有借位
{
ret -= 1;
flag = false;
}
if (ret < 0)//这次减需要借位
{
ret += 10;
flag = true;
}
result.push_back(ret + '0');
}
//大数前面还有剩余
while (i >= 0)
{
int ret = maxStr[i] - '0';
if (flag)
{
ret -= 1;
flag = false;
}
if (ret < 0)
{
ret += 10;
flag = true;
}
result.push_back(ret + '0');
i--;
}
//1234-1233 = 0001,直接输出1就可以了,所以最后要处理结果高位连续的0
string retStr;
auto it = result.rbegin();
for(; it != result.rend(); ++it)//去除高位连续的0
{
if(*it != '0')
{
break;
}
}
for(; it != result.rend(); ++it)//翻转容器中的数据
{
retStr.push_back(*it);
}
//需要添加负号
if (minor)
{
retStr.insert(retStr.begin(), '-');
}
//reverse(result.begin(), result.end());
return retStr;
}
main
int main()
{
BigInt int1("9785645649886874535428765");
BigInt int2("28937697857832167849697653231243");
BigInt int3("9785645649886874535428765");
cout << int1 + int2 << endl;
cout << int1 - int2 << endl;
BigInt int4("1234");
BigInt int5("1233");
cout << int4 - int5 << endl;
return 0;
}