大数加法
食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目只有题目分析,代码实现,代码误区
题目描述:
-
给定两个正整数(不含前导 0),计算它们的和。
输入格式
共两行,每行包含一个整数。输出格式
共一行,包含所求的和。数据范围
1≤整数长度≤100000
输入样例:
12
23
输出样例:
35
题目分析:
- 长度为十万的整数是什么概念:
十亿的数字长度:1,000,000,000 十位
int表示的最大数字:2,147,483,647 也是十位
long long表示的最大数字:9,223,372,036,854,775,807 19位
本题数据已经超出了内置整型范围 - 针对数据规模远远超出内置数据类型的数据运算,我们把这类问题称为高精度问题
- 高精度问题需要我们自己手动以字符串表示数据来实现加减乘除函数
算法原理:
大数:
- 高精度问题只针对整型,不产生小数
- 所有含有负数的运算都可以改为绝对值运算,结果加正负号,所以手动实现的高精度运算不考虑负数
- 大数:数字的位数超过百万的数
(PS:百万本身就7位数) - 高精度问题其实是两个问题:
- 大数的输入输出存储形式
- 大数四则运算函数
大数的存储:
- 以int数组存储大数:
- 以string存储大数:
- 以vector<int>存储大数
- 字节序:
arr[0]存储个位上数值,arr[n]存储权值为10^n的数值
优点:arr[n++]即可表示进位,同理vec.push_back()则vec.size()增加1,表示进位 - 输入大数:
先以string接收到字符串,再-'0’后写入int数组中
string的str[0]是高位,转化int时arr[0]是个位,所以从arr[str.size()-1]读取到arr[0] - 输出大数:
由于输出要求高位在前,而存储高位在后
若为数组则从arr[n-1]输出到arr[0]
若为vector则从vector.size()-1输出到0 - 只需要记住:大数的输入经过一次逆转,输出又经过一次逆转
大数加法:
- x位上的结果数由三部分构成:C[x] = (arr[x]+brr[x]+t) % 10;
- 加数数组的arr[x]
- 被加数数组的brr[x]
- x-1位的进位t
- x位上的输出由两部分构成:
- 当前位的数值C[x]
- 当前位给x+1位上的进位t
- 进位t是可以循环使用的:
- 上一位的进位t直接加入C[x]
- 这一位的进位t = arr[x]+brr[x]+t / 10;
- 上一位的进位t在计算这一位的进位时被重置,没有不良影响
写作步骤:
两大步骤:
大数输入输出:
- 输入:
大数被cin>>string
sting到vector<int>发生一次逆置存储,将个位放在vector<int>[0] - 输出:
逆置输出,vector<int>从vector<int>.size()-1开始输出,直到0,最后输出个位
大数加法:
- 位对位相加:两个加数vector<int>数组位对位相加,加上进位输入到结果数组vector<int> C中
- 进位记录:利用一个变量t即可完成上一位的进位添加入当前位的数据,以及这一位的进位记录
核心算法:
- 加法
- 输入输出控制
代码注意:
- string存储的是char,vector存储的是int,需要 -‘0’ 或 -48
-'0’是最容易遗忘和出错的,当结果非常奇怪的时候,百分之90是因为加的ASCII码 - 输出就不必逆置存储了,倒序输出即可
- 加法进位其实最大也就是进1
99 + 99 = 198
代码模板:
#include <iostream>
#include <algorithm>
using namespace std;
vector<int> add(vector<int> &A, vector<int> &B){
vector<int> C;
//注意点2:初始进位为0
int t = 0;
for(int i=0; i<A.size() || i<B.size()){
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
//注意点3:检查最高位是否需要进位
if (t) C.push_back(1);
}
int main(){
string a, b;
cin >> a >> b;
vector<int> A, B;
for(int i=a.size()-1; i>=0; i--){
A.push_back(a[i] - '0');
}
for(int i=b.size()-1; i>=0; i--){
B.push_back(b[i] - '0');
}
vector<int> C = add(A,B);
for(int i=C.size()-1; i>=0; i--){
cout << C[i];
}
return 0;
}
代码误区:
1. 为什么要给输入的大数-‘0’?
- sting虽然是stl,但是内部还是以char存储的
- 我们运算的是int
- 字符0在ASCII中编码为48,字符串结尾的/0在ASCII编码才是0
2. 为什么两个被加数加完后最多进位1:
- arr[i] 最大 9, brr[i]最大 9,和最大18
- 上一位进位最大1,18+1 == 19
- 19 / 10 == 1,大数加法最大进1
3. 最容易忘记的两点:
- 输入string到vector需要-‘0’
- 全部位数相加完成后,判断最高位是否需要进位
本篇感想:
- 高精度加法很简单吧,重点其实是学输入输出,以及不要忘记两个易漏点
- 看完本篇博客,恭喜已登《练气境-初期》
距离登仙境不远了,加油