大整数加减问题:
大数加法:思路就是用数组模拟手算过程 a[]与b[] 保存 加数 而c[] 保存结果 但是 c[]的长度需要比a[] b[] 中的最大长度多1
c[i]=a[i]+b[i];
if(c[i]<=10)
{
c[i]-=10;
++c[i+1];
}
大数减法:思路与加法相同 如果都为负 或都为正 则转换为加法 一正一负时 保证 被减数 大于 减数 否则调换
举个例子:321-123 如果按位置来减 那么结果为 20-2 按照思路就为 198 如果 是123-321 那就调换两数 思路同上 最后添加符号
c[i]=a[i]-b[i]
if(c[i]<0)
{
c[i]+=10;
--c[i+1]
}
时间复杂度:O(n)
空间复杂度:O(n)
//大数加减 VS2013环境下运行 注释很清晰 所以文字部分比较简短
//代码可能较长 但是详细 粘贴运行无误后可慢慢阅读
#include<iostream>
#include<string>
#include<cassert>
using namespace std;
int MinusCount(string& Ref1, string& Ref2);//判断两操作数负号个数
void AddSign(string& Ref1, string& Ref2);//补充符号位
int* SupAdd(int& Ref1, string& Ref2);//相加函数
bool IsSwap(string& Ref1, string& Ref2);//判断一正一负时 是否交换符号
void Swap(string& Ref1,string& Rer2);//交换负符号
void Print(int* p, int len);//输出函数
void DeleteZero(string& Ref);//删除字符串前的0和符号
bool CheckInput(string& Ref);//判断输入是否合法
void MainCalculate(string& Ref, string& Ref2);//加减计算函数
bool CheckInput(string& Ref)//判断输入是否合法
{
bool IsLegal = true;
if (Ref.length() < 1)
{
IsLegal = false;
return IsLegal;
}
if (1 == Ref.length())
{
if (Ref[0]<'0' || Ref[0]>'9')
{
IsLegal = false;
return IsLegal;
}
}
if (('+' != Ref[0] && '-' != Ref[0])&&(Ref[0]<'0'||Ref[0]>'9'))
{
IsLegal = false;
return IsLegal;
}
for (unsigned int i = 1; i < Ref.length(); ++i)
{
if (Ref[i]<'0' || Ref[i]>'9')
{
IsLegal = false;
return IsLegal;
}
}
return IsLegal;
}
void DeleteZero(string& Ref)//删除字符串前的0
{
if ("" == Ref)
{
return;
}
//Ref.erase(0); 现在字符首位应该为+ 或 -
int i = 1;
while ('0' == Ref[i] &&( (unsigned int)i < Ref.length()))
{
++i;
}
if (Ref.length() == i)
{
Ref = "+0";
}
else
{
Ref=Ref[0]+Ref.substr(i,Ref.length()-i);//注意该函数返回值 是创建一个新的对象
}
}
int MinusCount(string& Ref1, string& Ref2)//判断两操作数负号个数
{
int Count = 0;
if ('-' == Ref1[0])
{
++Count;
}
if ('-' == Ref2[0])
{
++Count;
}
return Count;
}
void AddSign(string& Ref1, string& Ref2)
{
//assert("" != Ref1 || "" != Ref2); 应该用断言 还是 中断
if ("" == Ref1 || "" == Ref2)
{
exit(0);
}
if ('+' != Ref1[0] && '-' != Ref1[0])
{
Ref1 = '+' + Ref1;
}
if ('+' != Ref2[0] && '-' != Ref2[0])
{
Ref2 = '+' + Ref2;
}
if ('-' == Ref1[0])
{
Ref1.swap(Ref2);//希望 一正一负时 正数在前 而负数在后
}
}
bool IsSwap(string& Ref1, string& Ref2)
{
bool IsSwap = false;//现在已经保证正数在前 而负数在后 并且都有符号位 0开始字符已经删除
if (1 == MinusCount(Ref1, Ref2))
{
Ref2[0] = '+';
if (Ref1.length() < Ref2.length())
{
IsSwap = true;
}
if (Ref1.length()==Ref2.length()&&Ref1 < Ref2)
{
IsSwap = true;
}
Ref2[0] = '-';
}
return IsSwap;
}
void Swap(string& Ref1, string& Ref2)//交换符号
{
Ref1[0] = '-';//正负交换
Ref2[0] = '+';
Ref1.swap(Ref2);//这样可以保证正数在前 负数在后
}
void Print(int* p, int len)//输出函数
{
if (NULL == p||len<1)
{
return;
}
int i = len - 1;
while (i >= 0&& 0 == p[i])
{
--i;
}
if (-1 == i)
{
cout << "0" << endl;
return;
}
for (; i >= 0; --i)
{
cout << p[i];
}
cout << endl;
}
int* SupAdd(string& Ref1, string& Ref2)//相加函数()
{
//符号位均已存在 0开始的字符已经删除
//对于两数 为同号时 可设置一局部bool变量保存
//一正一负时保证正数在前 并且数组结果为正
int len1 = Ref1.length() ;
int len2 = Ref2.length() ;
int maxlen = len1 > len2 ? len1-1 : len2-1;
int *pNumber1 = new int[maxlen]();
int *pNumber2 = new int[maxlen]();
int *pResult = new int[maxlen+1]();//结果应该多一位存储空间
if (NULL == pNumber1 || NULL == pNumber1 || NULL == pResult)
{
return NULL;
}
int k = 0;
for (int i = len1 - 1; i >= 1; --i)
{
pNumber1[k++] = Ref1[i] - 48;
}
int temp = 1;
bool IsNegative = ('-' == Ref2[0])&&(1==MinusCount(Ref1,Ref2));
//当且仅当 Ref1为正 Ref2为负时成立
k = 0;
if (IsNegative)
{
temp = -1;
}
for (int i = len2 - 1; i >= 1; --i)
{
pNumber2[k++] = temp*(Ref2[i] - 48);
}
for (int i = 0; i < maxlen; ++i)// 3钟情况下都需要逐位相加
{
pResult[i] += pNumber1[i] + pNumber2[i];
}
if (!IsNegative)
{
for (int i = 0; i < maxlen; ++i)
{
if (pResult[i] >= 10)
{
pResult[i] -= 10;
++pResult[i+1];
}
}
}
else
{
for (int i = 0; i < maxlen; ++i)
{
if (pResult[i] <0)
{
pResult[i] += 10;
--pResult[i+1];
}
}
}
delete[] pNumber1;
delete[] pNumber2;
return pResult;
}
void MainCalculate(string& Ref1, string& Ref2)//加减计算函数
{
bool bIsLegal1 = CheckInput(Ref1);
bool bIsLegal2 = CheckInput(Ref2);
if (!bIsLegal1 || !bIsLegal2)
{
cout << "Input Legal" << endl;
exit(0);
}
AddSign(Ref1,Ref2);//添加符号位
DeleteZero(Ref1);//删除以0开始的字符
DeleteZero(Ref2);
bool bIsSwap = IsSwap(Ref1, Ref2);
if (bIsSwap)
{
Swap(Ref1,Ref2);//如果 a-b<0则交换变为b+(-a)>0
}
int Count = MinusCount(Ref1,Ref2);//计算负号个数
int len = (Ref1.length() > Ref2.length() ? Ref1.length(): Ref2.length());
int* pResult = SupAdd(Ref1, Ref2);
//条件表达式 条件?表达式1:表达式2
switch (Count)
{
case 0:
if (pResult != NULL)
{
cout << "+";
Print(pResult,len);
}
break;
case 1:
//int *pResult = SupAdd(Ref1, Ref2);
if (pResult != NULL)
{
if (bIsSwap)
{
cout << "-";
}
else
{
cout << "+";
}
Print(pResult, len);
}
break;
case 2:
//int* pResult = SupAdd(Ref1, Ref2);
if (pResult != NULL)
{
cout << "-";
Print(pResult, len);
}
break;
}
delete[] pResult;
}
int main(void)
{
//思路很清晰后动手 Debug三次后 得出正确结果
string Str1 = "-16651616516516865154561651651651651516513151865415151";
string Str2 = "+151";
//对于大数 一般来说 小数是可以忽略的
//如果改为小数 那么 需要将整数与小数分开 小数与整数分开相加
MainCalculate(Str1,Str2);
return 0;
}
空间复杂度:O(n)
注意点: 数据输入为字符串 那么转为 数组时 就必须倒序来赋值,因为习惯是高位在前,但是计算时却是从低位计算。(也就是从数组第0为开始计算)