数据结构与算法入门指南
我们都知道int可以表示-2147483648 到2147483647,long long可以表示-9223372036854775808到9223372036854775807,但要是想表达更大的数字怎么办呢?例如这个数字有一百位、一千位甚至一万位。
这个时候就需要用到高精度算法了,其实本质上是用数组将每一位都储存起来,进行加减运算的时候手动模拟运算的过程,最终得到结果。
需要注意的是:存储的时候为了方便运算一般会倒着存,例如:12345会存成{5, 4, 3, 2, 1}。
加法模板
回想一下我们平时计算加法的步骤,是不是跟下面一样呢?
写加法高精度算法的时候就是模拟上一过程,只不过由于我们存储的方式是倒着存的,所以不需要从右往左开始加,顺次加即可,记录每一次的进位情况,最后计算出结果。
P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
using namespace std;
vector<int> add(vector<int> A, vector<int> B)
{
int t = 0; vector<int> C;
for (int i = 0; i < A.size() || i < B.size(); i++)
{
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10); t /= 10; //进位
}
if (t) C.push_back(1); //如果最后还能进位,就进位
return C;
}
int main()
{
string a, b; cin >> a >> b;
vector<int> A, B, C;
for (int i = a.length() - 1; i >= 0; i--) //倒着存
A.push_back(a[i] - '0'); //字符转数字类型,减去'0'即可。
for (int i = b.length() - 1; i >= 0; i--)
B.push_back(b[i] - '0');
C = add(A, B);
for (int i = C.size() - 1; i >= 0; i--) //倒着输出
cout << C[i];
return 0;
}
减法模板
减法需要注意的是,如果是小数a减大数b,那么会得到负数,我们会先用大数b减去小数a,再补上负号即可。
P2142 高精度减法 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<int> &A, vector<int> &B) //用来判断A与B谁大
{
if (A.size() != B.size()) return A.size() > B.size();
for (int i = A.size(); i >= 0; i--)
if (A[i] != B[i])
return A[i] > B[i];
return true;
}
vector<int> sub(vector<int> &A, vector<int> &B)
{
if (!cmp(A, B)) return sub(B, A); //如果是小数减大数就返回大数减小数的结果
int t = 0; vector<int> C;
for (int i = 0; i < A.size() || i < B.size(); i++)
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
t = (t < 0 ? 1 : 0);
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
string a, b; cin >> a >> b;
vector<int> A, B, C;
for (int i = a.length() - 1; i >= 0; i--)
A.push_back(a[i] - '0');
for (int i = b.length() - 1; i >= 0; i--)
B.push_back(b[i] - '0');
C = sub(A, B);
if (!cmp(A, B)) cout << '-'; //如果是小数减大数,应该补上负号。
for (int i = C.size() - 1; i >= 0; i--)
cout << C[i];
return 0;
}
乘法模板
高精度乘int
与上述加法模板差不多。
vector<int> mul(vector<int> &A, int b)
{
vector<int> C; int t = 0;
for (int i = 0; i < A.size() || t; i++)
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10); t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去除前置0
return C;
}
高精度乘高精度
再开一个C数组存下最终处理出来的结果,把中间的每次乘法算出来的结果直接加到最终结果上,再对最终结果进行进位处理。
P1303 A*B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
vector<int> mul(vector<int> &A, vector<int> &B)
{
int len = A.size() + B.size(); vector<int> C(len);
for (int i = 0; i < A.size(); i++)
for (int j = 0; j < B.size(); j++)
C[i + j] += A[i] * B[j]; //把每次乘的结果直接累加到最终结果上
for (int i = 0; i < len; i++)
if (C[i] > 9) //能进位就进位
{
C[i + 1] += C[i] / 10;
C[i] %= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去除前置0
return C;
}
这两个模板的用法具体要看题目的要求选用。
除法模板
除法不同的是,不是无限的去计算后续位数,而是返回商和余数。
高精度除int,函数返回值为商,r为传出的余数。
vector<int> div(vector<int> &A, int b, int &r)
{
vector<int> C; r = 0;
//回想一下除法,我们运算的时候是顺次的,由于这里是倒着存,所以也要倒着遍历。
for (int i = A.size() - 1; i >= 0; i--)
{
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end()); //翻转数组
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去前置0
return C;
}
题目
待增加