蓝桥杯C++:算法1:高精度

💡 高精度是通过字符串 + 数组逆序存储模拟竖式计算,解决 C++ 内置类型(int/long long)无法存储和运算超大整数的方法,核心包含加减乘除四大基础运算。


1 通用基础

💡 字符串存大数、数组逆序拆分、结果逆序输出

1.1 核心存储逻辑

  1. 超大数无法用 int/long long 存储,先存入string 字符串(x、y)
  2. 字符串不能直接运算,需逐字符转数字并逆序存入数组
    • 逆序原因:竖式计算从最低位开始,进位 / 借位时在数组尾部追加元素更方便,避免头部插入的复杂度
  3. 结果存储在数组 c 中,最终逆序输出(从高位到低位)

专业 📚

  1. C++ 内置整型范围:int(±2e9)、long long(±9e18),超过该范围的整数称为高精度数
  2. 逆序存储是高精度算法的行业标准方案,完美适配四则运算的进位 / 借位操作

拆分逆序核心代码 🧑💻

复制代码
// 计算字符串长度
la = x.size();
lb = y.size();
lc = max(la, lb); // 结果长度初始值(加减除专用),乘法为 la+lb

// 逐字符转数字 + 逆序存入数组(核心代码)
for(int i = 0; i < la; i++) a[la - 1 - i] = x[i] - '0';
for(int i = 0; i < lb; i++) b[lb - 1 - i] = y[i] - '0';

⚠️ 适用场景 & 核心注意

  • x[i] - '0' 是字符转数字的唯一标准方法(利用 ASCII 码差值)
  • 所有高精度运算必须先执行逆序拆分,无例外

1.2 必备头文件 & 全局变量

  1. 强制头文件:

    • <string>:存储高精度数
    • <algorithm>:调用 max 函数计算长度
    • <iostream>:标准输入输出
  2. 全局数组:必须开大空间(防止栈溢出),a/b 存运算数,c 存结果

    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;

    const int N = 1e6 + 10; // 开大数组,避免越界
    int a[N], b[N], c[N]; // a:第一个数 b:第二个数 c:运算结果
    int la, lb, lc; // 三个数组的有效长度
    string x, y; // 存储输入的超大数

1.3 通用输出逻辑

结果数组逆序存放,输出时从最后一位(最高位)向前遍历输出代码 🧑💻

复制代码
// 逆序输出最终结果
for(int i = lc - 1; i >= 0; i--) cout << c[i];

2 ➕

💡 模拟小学竖式加法,逐位相加 + 处理进位,结果长度为最大数长度或 + 1。

2.1 核心逻辑

  1. 遍历每一位,将 a[i]b[i] 相加存入 c[i]
  2. 处理进位:c[i]/10 加到下一位,c[i] 保留个位(%10
  3. 最后判断最高位是否进位,有则长度 + 1

专业 📚高精度加法时间复杂度为 O(n)(n 为数字位数),属于线性高效运算。

2.2 加法函数实现 🧑💻

复制代码
// 高精度加法函数
void add(int a[], int b[], int c[], int length) {
    for (int i = 0; i < length; i++) {
        c[i] += a[i] + b[i];       // 逐位相加
        c[i + 1] += c[i] / 10;     // 处理进位
        c[i] %= 10;                // 保留当前位的个位数字
    }
}

✨ 优化建议:原代码进位逻辑简化,直接用 c[i]/10 适配多进位场景,通用性更强


3 ➖

💡 模拟竖式减法,先判断大小保证被减数≥减数,逐位相减 + 处理借位,必须处理前导 0。

3.1 核心逻辑

  1. 大小判断:若减数 > 被减数,输出负号并交换两数,保证大数减小数
  2. 逐位相减,若结果 < 0,向前借 1(前一位 - 1,当前位 + 10)
  3. 处理前导 0 :避免输出 0001 这类错误格式,结果为 0 时保留 1 个 0

高精度减法是唯一需要提前比较数大小的运算;前导 0 处理是输出规范的必要步骤。

⚠️ 适用场景 & 核心注意

  • 适用场景:两个超大正整数相减
  • 避坑 1:交换数字后再计算长度,否则长度错误
  • 避坑 2:前导 0 循环条件用 lc>1,保留最后一个 0,避免无输出

3.2 减法函数实现 🧑💻

复制代码
// 高精度减法函数
void sub(int a[], int b[], int c[]) {
    for (int i = 0; i < lc; i++) {
        c[i] += a[i] - b[i];       // 逐位相减
        if (c[i] < 0) {            // 不够减,需要向前借位
            c[i + 1]--;
            c[i] += 10;
        }
    }
}

4 ✖️

💡 模拟竖式乘法,双层循环逐位相乘(结果存在第 i+j 位),统一处理进位,结果长度为两数长度之和。

4.1 核心逻辑

  1. 双层循环:a 的第 i 位 × b 的第 j 位,结果存入 c[i+j]
  2. ++所有位相乘完成后,统一处理进位(从低位到高位)++
  3. 处理前导 0,最后逆序输出

高精度乘法时间复杂度 O(n×m)(n/m 为两个数的位数);

4.2 乘法函数实现 🧑💻

复制代码
// 高精度乘法函数
void mul(int a[], int b[], int c[]) {
    // 双层循环:逐位相乘
    for (int i = 0; i < la; i++) {
        for (int j = 0; j < lb; j++) {
            c[i + j] += a[i] * b[j];
        }
    }
    // 统一处理所有位的进位
    for (int i = 0; i < lc; i++) {
        c[i + 1] += c[i] / 10;
        c[i] %= 10;
    }
    // 处理前导0
    while (lc > 1 && c[lc - 1] == 0) lc--;
}

5 ➗

💡 仅实现高精度 ÷ 低精度 ,模拟竖式除法从最高位开始计算(和其他三个不同),余数迭代参与运算,处理前导 0。

5.1 核心逻辑

  1. 仅被除数是高精度数(存 string),除数是低精度数(int)
  2. 计算顺序:从最高位到最低位(与加减乘完全相反)
  3. 核心公式:余数×10 + 当前位 = 新被除数
  4. 商 = 新被除数 ÷ 除数,余数 = 新的被除数 % 除数
  5. 处理前导 0,逆序输出

⚠️ 适用场景 & 核心注意

  • 高精度 ÷ 高精度实现极复杂,入门 / 竞赛优先掌握高精度 ÷ 低精度
  • 除法是高精度运算中唯一从高位计算的类型。

5.2 除法函数实现 🧑💻

复制代码
long long t = 0; // 余数(开大类型,防止溢出)
// 高精度 ÷ 低精度 函数
void div(int a[], int b, int c[]) {
    for (int i = la - 1; i >= 0; i--) {
        t = t * 10 + a[i];    // 迭代计算当前被除数
        c[i] = t / b;         // 计算当前位的商
        t %= b;               // 更新余数,用于下一位计算
    }
    // 处理前导0
    while (lc > 1 && c[lc - 1] == 0) lc--;
}

完整可运行代码合集

1. 高精度加法 完整代码

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
string x, y;
const int N = 510;
int a[N], b[N], c[N];

void add(int a[], int  b[], int  c[],int  length)
{
	for (int i = 0; i < length; i++)
	{
		c[i] += (a[i] + b[i]);
		if (c[i] >= 10)
		{
			c[i] %= 10;
			c[i + 1] = 1;
		}
	}
}

int main()
{
	cin >> x >> y;
	int length = max(x.size(), y.size());//真实的长度,最大下标+1

	for (int i = 0; i < x.size(); i++)
		a[x.size() - 1 - i] = x[i] - '0';

	for (int i = 0; i < y.size(); i++)
		b[y.size() - 1 - i] = y[i] - '0';


	 add(a, b, c,length);

	 if (c[length] )
		 length++;

	 for (int i = length - 1; i >= 0; i--)
	 {
		 cout << c[i];
	 }

	return 0;
}

2. 高精度减法 完整代码

cpp 复制代码
#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
string x, y, sw;
const int N = 1000010;
int a[N], b[N], c[N];
int la, lb, lc;
//
//
//void sub(int a[], int b[], int c[])
//{
//	for (int i = 0; i < lc; i++)
//	{
//		if (a[i] < b[i])
//		{
//			a[i] += 10;
//			a[i + 1]--;
//		}
//		c[i] = (a[i] - b[i]);
//	}
//}

void sub(int a[], int b[], int c[])
{
	for (int i = 0; i < lc; i++)
	{
		c[i] += (a[i] - b[i]);

		if (c[i] < 0)
		{
			c[i + 1]--;
			c[i] += 10;
		}
	}
}


int main()
{
	cin >> x >> y;

	if (x == y)
	{
		cout << 0 << endl;//都是0的情况
		return 0;
	}

	//la = x.size();
	//lb = y.size();
	//lc = max(la, lb);

	if (y.size() > x.size() || y > x)
	{
		cout << "-";

		sw = x;
		x = y;
		y = sw;
	}



	la = x.size();
	lb = y.size();
	lc = max(la, lb);


	for (int i = 0; i < la; i++)
		a[la - 1 - i] = x[i] - '0';
	for (int i = 0; i < lb; i++)
		b[lb - 1 - i] = y[i] - '0';

	sub(a, b, c);

	//if (c[lc - 1] == 0)
	//	lc--;


	//int flag = 0;//标记最后一个不是0的下标
	//for (int i = lc - 1; i >= 0; i++)
	//{
	//	if (c[i] != 0)
	//	{
	//		flag = i;
	//		break;
	//	}
	//}
	while (c[lc - 1]==0&&lc>=1)
		lc--;

	for (int i = lc - 1; i >= 0; i--)
	{
		cout << c[i];
	}


	return 0;
}

3. 高精度乘法 完整代码

cpp 复制代码
#include<iostream>
#include<string>

using namespace std;

const int N = 4000010;
int la, lb, lc, a[N], b[N], c[N];
string x,y;

void mul(int a[], int b[], int c[])
{
	for (int i = 0; i < la; i++)
	{
		for (int j = 0; j < lb; j++)
		{
			c[i + j] += a[i] * b[j];
		}
	}

	for (int i = 0; i < lc; i++)
	{
		c[i + 1] += c[i] / 10;
		c[i] %= 10;
	}

	while (lc >  1 && c[lc - 1] == 0)
		lc--;
}
int main()
{
	cin >> x >> y;
	for (int i = 0; i < x.size(); i++)
		a[i] = x[x.size() - 1 - i]  -'0';
	for (int i = 0; i < y.size(); i++)
		b[i] = y[y.size() - 1 - i] - '0';

	la = x.size();
	lb = y.size();
	lc = la + lb;

	mul(a, b, c);

	for (int i = lc-1; i  >=0;i--)
		cout << c[i];

	return 0;
}

4. 高精度除法 (高精度 ÷ 低精度) 完整代码

cpp 复制代码
#include<iostream>
#include<string>

using namespace std;
int a[100010], c[100010], b;
int la, lc;
string x ;
long long t = 0;
void div(int a[], int b, int c[])
{
	for (int i = la-1 ; i >=0 ; i--)//除法是从被除数最大为到最小位, 数组a 从后往前
	{
		t = t * 10 + a[i];//上一次的余数乘10再加上 a这一位上的数,就是这次的被除数
		c[i] = t / b;//得到这一位上的答案
		t %= b;//得到下一次的余数
	}

	while (lc> 1 && c[lc - 1] == 0)//
		lc--;

}
int main()
{
	cin >> x >> b;//将 被除数数放到string ,除数就是int

	la = x.size();
	lc = la;//先将结果的位数取最大的可能值

	for (int i = 0; i < la; i++)
		a[i] = x[la - i - 1] - '0';//存被除数的每一位


	div(a, b, c);


	for (int i = lc - 1; i >= 0; i--)
	{
		cout << c[i];
	}

	return 0;
}

总结

  1. 核心口诀:字符串存数 → 逆序转数组 → 模拟竖式计算 → 逆序输出
  2. 核心区别:加减乘从低位计算,除法从高位计算;减法需判大小,乘法长度为两数长度和
  3. 通用避坑:必须处理进位 / 借位、前导 0,数组开足够大
相关推荐
liulilittle2 小时前
SQLite3 C++ usage demo
数据库·c++·sqlite
酉鬼女又兒2 小时前
零基础快速入门前端DOM核心知识点详解与蓝桥杯Web赛道备考指南(可用于备赛蓝桥杯Web应用开发)
前端·职场和发展·蓝桥杯
leaves falling2 小时前
C++类和对象(3)(初始化列表,类型转换,static成员,友元)
java·开发语言·c++
宵时待雨2 小时前
C++笔记归纳15:封装map & set
开发语言·数据结构·c++·笔记·算法
啊哦呃咦唔鱼2 小时前
LeetCodehot100-21 合并两个有序链表
算法
935962 小时前
练习题31-45 翻译59
c语言·算法
眼眸流转2 小时前
LeetCode热题100(七)
算法·leetcode·c#
WWZZ20252 小时前
Sim2Sim理论与实践1:坐标系与位姿变换
人工智能·算法·机器人·大模型·具身智能·isaac sim
yong99902 小时前
动态四足机器人的自由模型预测控制(FMPC)MATLAB实现
算法·matlab·机器人