大整数加减 加减运算

大整数加减问题:

大数加法:思路就是用数组模拟手算过程  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为开始计算)                

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值