再开始说明算法实现之前 , 我们还需要一些前期的知识储备
如何把数字转换为string类型?
stringstream temp;
int a=123456;
string s;
temp<<a;
temp>>s;
cout<<"s : "<<s<<endl;
stringstream temp;
int a;
string s("-250");
temp<<s;
temp>>a;
cout<<"a :"<<a+1<<endl; //-249
再开始写代码之前 , 先要进行构思.
那么编者就来说说自己的思路 :
编者将框架放在这里 , 如有不同思路 , 可以互相交流
class BigInt
{
public:
BigInt(string str) :strDigit(str){}
private:
string strDigit; // 使用字符串存储大整数
};
// 打印函数
ostream& operator<<(ostream &out, const BigInt &src);
// 大数加法
BigInt operator+(const BigInt &lhs, const BigInt &rhs);
// 大数减法
BigInt operator-(const BigInt &lhs, const BigInt &rhs);
int main()
{
BigInt int1("28937697857832167849697653231243");
BigInt int2("9785645649886874535428765");
cout << int1 + int2 << endl;
//28937707643477817736572188660008
cout << int1 - int2 << endl;
//28937688072186517962823117802478
return 0;
}
#include
#include // 使用vector容器
#include // 使用泛型算法
#include
#include
#include
using namespace std;
class BigInt
{
public:
BigInt(string str) :strDigit(str){}
private:
string strDigit; // 使用字符串存储大整数
//友元函数声明
friend BigInt operator+(const BigInt &lhs, const BigInt &rhs);
friend ostream& operator<<(ostream &out, const BigInt &src);
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)
{
bool flag = false; //进位
stringstream tmpL; // 数字 字符 转换所需的中间变量
stringstream tmpR;
string tmp; //计算完成插入Fin 所需要的临时量
string Lhs = lhs.strDigit;
string Rhs =rhs.strDigit;
int lenL = Lhs.length();
int lenR = Rhs.length();
if(lenL < lenR)
{
Lhs.swap(Rhs);
int tmp = lenL;
lenL = lenR;
lenR = tmp;
}
string Fin ;
//Fin.resize(0); // sizeof(char) 最后会比计算结果长度多一个字节长度 Fin.resize(sizeof(0)); 丢失最后一个 , e = Fin.length()-1 会崩溃
int i = 0 , j = 0 , k = 0;
j = lenL-1;
int R , L ,sum = 0;
for(i = lenR-1 ; i >= 0; --i ,--j)
{
tmpR.clear(); //再重复使用时 , 要清空原有数据
tmpL.clear();
tmpR<<Rhs[i]; //字符 -> 数字
tmpL<<Lhs[j];
tmpR>>R;
tmpL>>L;
if(flag)
{
sum = L + R + 1;
}
else
{
sum = L + R;
}
if(sum >= 10)
{
flag = true;
sum %= 10;
tmpL.clear();
tmpL << sum; //数字 -> 字符
tmpL >>tmp;
Fin.insert(k++,tmp); // 使用尾插 Fin.insert(0,tmp); 采用头插的方式 , 效率低 push_back(sum + '0');
}
else
{
flag = false;
tmpL.clear();
tmpL << sum;
tmpL >>tmp;
Fin.insert(k++,tmp);
}
}
if(flag) //较短字符串的最高位 相加 有无进位
{
if(i == j) //如果两个数等长
{
tmpL.clear();
tmpL<<1;
tmpL>>tmp;
Fin.insert(k++,tmp);
//字符串反转
reverse(Fin.begin(),Fin.end());
return BigInt(Fin);
}
while(j >=0) //有进位则写入
{
tmpL.clear();
tmpL<<Lhs[j];
tmpL>>L;
sum = L + 1;
if(sum >= 10)
{
flag = true;
sum %= 10;
tmpL.clear();
tmpL << sum;
tmpL >>tmp;
Fin.insert(k++,tmp);
}
else
{
flag = false;
break;
}
--j;
}
tmpL.clear();
tmpL << sum;
tmpL >>tmp;
Fin.insert(k++,tmp);
--j;
}
while(j >= 0) //无进位 , 则摘抄
{
tmpL.clear();
tmpL<<Lhs[j--];
tmpL>>tmp;
Fin.insert(k++,tmp);
}
//字符串反转
reverse(Fin.begin(),Fin.end());
i = 0;
//结果全为零 , 则只显示一个
while(Fin[i++] == '0')
{ }
if((i - 1) == k)
{
return (string)"0";
}
return BigInt(Fin);
}
// 大数减法
BigInt operator-(const BigInt &lhs, const BigInt &rhs)
{
bool flag = false; //借位
bool mark = false; //最终结果的正负 false -> 正 ; true -> 负
stringstream tmpL; // 数字 字符 转换所需的中间变量
stringstream tmpR;
string tmp; //计算完成插入Fin 所需要的临时量
string Lhs = lhs.strDigit;
string Rhs =rhs.strDigit;
int lenL = Lhs.length();
int lenR = Rhs.length();
if(lenL < lenR)
{
Lhs.swap(Rhs);
int tmp = lenL;
lenL = lenR;
lenR = tmp;
mark = true;
}
string Fin ;
// Fin.resize(0);
int i = 0 , j = 0 , k = 0;
j = lenL-1;
int R , L ,dif = 0;
for(i = lenR-1 ; i >= 0; --i ,--j)
{
tmpR.clear(); //再重复使用时 , 要清空原有数据
tmpL.clear();
tmpR<<Rhs[i]; //字符 -> 数字
tmpL<<Lhs[j];
tmpR>>R;
tmpL>>L;
if(flag)
{
dif = L - R - 1;
}
else
{
dif = L - R;
}
if(dif < 0 )
{
flag = true;
dif += 10;
tmpL.clear();
tmpL<<dif;
tmpL>>tmp;
Fin.insert(k++,tmp);
}
else
{
flag = false;
tmpL.clear();
tmpL<<dif;
tmpL>>tmp;
Fin.insert(k++,tmp);
}
}
if(flag) //较短字符串的最高位 相加 有无借位
{
if(i == j) //如果两个数等长
{
tmpL.clear();
tmpL<<'-';
tmpL>>tmp;
Fin.insert(k++,tmp);
reverse(Fin.begin(),Fin.end());
return BigInt(Fin);
}
while(j >=0) //有借位则写入
{
tmpL.clear();
tmpL<<Lhs[j];
tmpL>>L;
dif = L - 1;
if(dif < 0)
{
flag = true;
dif += 10;
tmpL.clear();
tmpL << dif;
tmpL >>tmp;
Fin.insert(k++,tmp);
}
else
{
flag = false;
break;
}
--j;
}
tmpL.clear();
tmpL << dif;
tmpL >>tmp;
Fin.insert(k++,tmp);
--j;
}
while(j >= 0) //无借位 , 则摘抄
{
tmpL.clear();
tmpL<<Lhs[j--];
tmpL>>tmp;
Fin.insert(k++,tmp);
}
//判断最终的符号
if(mark)
{
tmpL.clear();
tmpL<<'-';
tmpL>>tmp;
Fin.insert(k++,tmp);
}
reverse(Fin.begin(),Fin.end());
i = 0;
//结果全为零 , 则只显示一个
while(Fin[i++] == '0')
{ }
if((i - 1) == k)
{
return (string)"0";
}
return BigInt(Fin);
}
int main()
{
BigInt int1("28937697857832167849697653231243");
BigInt int2("9785645649886874535428765");
BigInt int3("4785645649886874535428765");
BigInt int4("12222222222222222222222222");
BigInt int5("92222222222222222222222222");
BigInt int7("92222222222222222222222222");
cout << int2 + int1 << endl;
cout << int1 - int2 << endl;
cout << int4 + int5 << endl;
cout << int3 - int2 << endl;
cout << int2 - int1 << endl;
cout << int5 - int7 << endl;
return 0;
}
在代码中 , 在容器插入元素 , 可以使用insert()进行头插(效率太低) , 也可以使用push_banck()进行尾插(高效) ; 如果进行尾插的话 , 则要在最后进行字符串的逆置(泛型算法 reverse());而编者在写时 , 使用了insert() , 设置了一个 k 来记录插入位置(如果看过源码的话 , 不算析构和重新构造 , 其余代码insert和push_back是相同的,即 k 永远是最后元素的下一个位置 , 也算是尾插 );