大数加减法(洛谷的P1601、P2142)

大数加法:
原题连接
对于一些范围比较小的数据,利用C/C++自带的数据类型就可以解决。但是对于一些数据比如10^1000000这样的数据,我们如何处理呢?
这时,我们就要用到大数运算了。
大数运算的根本在于要用字符串或是数组对每一位进行保存。下面介绍一下大数加法。由于大数加法比较简单,我们直接对字符串进行操作,不在用数组了。
第一步是以字符串的形式输入两个整数

 string a, b;
    cin >> a >> b;
    string resa = a;
    string resb = b;
    for (int i = 0; i < a.size(); i++)
        resa[i] = a[a.size() - 1 - i];
    for (int i = 0; i < b.size(); i++)
        resb[i] = b[b.size() - 1 - i];
    int maxSize = a.size() > b.size() ? a.size() : b.size();

resa,resb是a,b的反转字符串。为什么反转?我们模拟一下我们做加法,是列一个竖式从个位加到最高位。所以我们反转一下字符串便于运算。

  string ans;
    int i = 0, j = 0;
    bool flag = 0;
    while (resa[i] != '\0'|| resb[j] != '\0') {
        if (resa[i] != '\0' && resb[j] != '\0') {
            int x = resa[i] + resb[j] - '0' - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
            j++;
        }

这里有几个变量ans是答案,flag是进位(因为进位不可能为2,所以我们直接用bool变量),因为可能存在要进位的情况。接下来进入循环。循环的终止条件是什么呢?就是两个字符串都加到最高位了,也就是此时为’\0’状态。那么我们考虑一下可能存在的情况。第一种情况:两个字符串都没有到达最高位。int x = resa[i] + resb[j] - ‘0’ - ‘0’ + flag这条语句就是就是计算此时该位相加的结果,注意要减去’0’,而且要加上进位的结果。如果x>=10说明要进位了,我们在ans后添加x的各位数字(要加上’0’),并把flag赋值为1,代表要进位;否则就直接把x添加上去,flag赋值为。然后i++,j++,移动至下一个字符。

else if (resa[i] != '\0' && resb[j] == '\0') {
            int x = resa[i] - '0'+ flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
        }
        else {
            int x = resb[j] - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            j++;
        }

我们想,加法会有两个数位数不一致的情况。那么还需要处理一下这种情况。但其实实质与两位相加相同。这可以理解为其中一位为零。

 if (flag)
        ans.push_back('1');
    for (int i = ans.size() - 1; i >= 0; i--)
        cout << ans[i];

当然还有一种情况,举个栗子,50+50,最后肯定要再添一位。但是在循环中有进位有延后。所以我们还要再判断一下是否要进位。最后逆序输出。
完整代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{
    string a, b;
    cin >> a >> b;
    string resa = a;
    string resb = b;
    for (int i = 0; i < a.size(); i++)
        resa[i] = a[a.size() - 1 - i];
    for (int i = 0; i < b.size(); i++)
        resb[i] = b[b.size() - 1 - i];
    int maxSize = a.size() > b.size() ? a.size() : b.size();
    string ans;
    int i = 0, j = 0;
    bool flag = 0;
    while (resa[i] != '\0'|| resb[j] != '\0') {
        if (resa[i] != '\0' && resb[j] != '\0') {
            int x = resa[i] + resb[j] - '0' - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
            j++;
        }
        else if (resa[i] != '\0' && resb[j] == '\0') {
            int x = resa[i] - '0'+ flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
        }
        else {
            int x = resb[j] - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            j++;
        }
    }
    if (flag)
        ans.push_back('1');
    for (int i = ans.size() - 1; i >= 0; i--)
        cout << ans[i];
    return 0;
}

大数减法:
原题链接
大数减法与之类似,但略微复杂一些,这里用数组会好处理一些。

const int MAX = 100000;
int main()
{
 int a_num[MAX] = { 0 }, b_num[MAX] = { 0 };
 string a, b;
 cin >> a >> b;
 int alen = a.size();
 int blen = b.size();
 if (alen < blen || alen == blen && a < b) {
  swap(a, b);
  swap(alen, blen);
  cout << "-";
 }
 for (int i = 0; i < alen; i++) {
  a_num[alen - i] = a[i] - '0';
 }
 for (int i = 0; i < blen; i++) {
  b_num[blen - i] = b[i] - '0';
 }

与大数加法类似,我们先以字符串形式输入数据。我们要用a_num这个数组储存答案,我们就要判定一下是否要把a,b交换。为什么呢?举个栗子,计算15-20,我们是用20-15再添负号的。所以这就要求a要大于b。a大于b的条件是a的长度小于b,或是长度一样但是a的字典序大于b。当a小于b时,我们就要交换a,b。同时由于a<b,我们要在输出一个负号。然后把a的逆序赋给a_num数组。在这之中,a_num[1]储存的是个位数字。b同理。

for (int i = 1; i <= alen; i++) {
  if (a_num[i] < b_num[i]) {
   a_num[i] += 10;
   a_num[i] -= b_num[i];
   a_num[i + 1] -= 1;
  }
  else
   a_num[i] -= b_num[i];
 }

然后我们开始逐位处理,如果a_num[i]<b_num[i],我们就需要借位,直接在该位加十,同时下一位减一。否则直接相减就可。

 while (a_num[alen] == 0 && alen > 1)
  alen--;
 for (; alen >= 1; alen--)
  cout << a_num[alen];
 return 0;

最后输出,但是相减可会导致高位为0,所以要去除所有的0,最后逆序输出即可。
完整代码:

#include<iostream>
#include<string>
using namespace std;
const int MAX = 100000;
int main()
{
	int a_num[MAX] = { 0 }, b_num[MAX] = { 0 };
	string a, b;
	cin >> a >> b;
	int alen = a.size();
	int blen = b.size();
	if (alen < blen || alen == blen && a < b) {
		swap(a, b);
		swap(alen, blen);
		cout << "-";
	}
	for (int i = 0; i < alen; i++) {
		a_num[alen - i] = a[i] - '0';
	}
	for (int i = 0; i < blen; i++) {
		b_num[blen - i] = b[i] - '0';
	}
	for (int i = 1; i <= alen; i++) {
		if (a_num[i] < b_num[i]) {
			a_num[i] += 10;
			a_num[i] -= b_num[i];
			a_num[i + 1] -= 1;
		}
		else
			a_num[i] -= b_num[i];
	}
	while (a_num[alen] == 0 && alen > 1)
		alen--;
	for (; alen >= 1; alen--)
		cout << a_num[alen];
	return 0;

}
发布了14 篇原创文章 · 获赞 3 · 访问量 154

猜你喜欢

转载自blog.csdn.net/IMDASHUAI/article/details/104558442