acwing c++基础算法笔记(2)

高精度算法

1.高精度加法

// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t) C.push_back(t);
    return C;
}
  1. 参数调整:首先,函数通过比较AB的大小,如果A的位数少于B,则递归调用add函数并交换AB的顺序,这样可以确保在后续的计算中,始终以位数较多的数作为遍历的基准,简化了代码的逻辑

  2. 初始化结果容器和进位标志:定义一个空的vector<int>类型的变量C,用于存储相加的结果。同时,初始化一个整数变量t为 0,用于表示进位

  3. 遍历相加:使用for循环遍历A的每一位数字。在每次循环中,先将A当前位的数字加到进位t上,然后判断如果i小于B的大小,说明B在当前位还有数字,则将B当前位的数字也加到t上。接着,将t除以 10 的余数作为当前位的结果插入到结果容器C中,并更新进位t的值,即t除以 10 取整,为下一位的加法运算做准备

  4. 处理最后进位:循环结束后,如果进位t的值不为 0,说明最高位还有进位,则将进位t作为新的最高位插入到结果容器C

  5. 返回结果:最后,函数返回存储结果的vector<int>类型的变量C,即为两个大整数相加的最终结果

2.高精度减法

// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

定义结果向量 C 用于存储差值的每一位数字,同时初始化循环变量 i 和临时变量 tt 用于暂存减法过程中的借位信息及每一步的计算结果。

在循环中,先从 A 的当前位数字减去上一步的借位值 t,若 B 还有对应位数字(i < B.size()),则再减去 B 的当前位数字。将计算结果对 10 取模后存入 C,以得到当前位的差。若计算结果小于 0,说明需要借位,将 t 设为 1 表示借位;否则将 t 设为 0,表示无借位。

计算完成后,由于结果可能存在前导 0(例如 123 - 120 = 003),通过循环删除 C 末尾连续的 0,只保留有效数字部分,但至少保留一位数字,以处理如 10 - 5 = 5 的情况,防止误删。

假设 A = {1, 2, 3}B = {1, 2, 0},计算 A - B 过程如下:

第一轮循环:i = 0t = 0t = A[0] - t = 1 - 0 = 1B 在此位有数字,t -= B[0] = 1 - 1 = 0C.push_back((t + 10) % 10) = 0t = 0

第二轮循环:i = 1t = 0t = A[1] - t = 2 - 0 = 2t -= B[1] = 2 - 2 = 0C.push_back((t + 10) % 10) = 0t = 0

第三轮循环:i = 2t = 0t = A[2] - t = 3 - 0 = 3B 在此位无数字,C.push_back((t + 10) % 10) = 3t = 0。 最终 C = {0, 0, 3},去除前导 0 后为 {3},即 A - B = 3

3.高精度乘低精度

// C = A * b, A >= 0, b >= 0
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();

    return C;
}

这段代码定义了一个名为 mul 的函数,用于实现高精度整数乘法运算。函数接收一个表示高精度整数的 vector<int> 类型的参数 A(其中每个元素按低位到高位的顺序存储整数的每一位数字)以及一个普通的非负整数 b,计算 Ab 的乘积,并返回表示乘积结果的 vector<int>,同样按低位到高位存储每一位数字,同时对结果末尾可能存在的多余 0 进行了去除处理。

首先定义了一个名为 mul 的函数,它接受一个 vector<int> 类型的引用 A(使用引用可以避免在函数调用时进行整个 vector 的拷贝,提高效率,尤其是对于较大的 vector 时)和一个 int 类型的整数 b,函数的返回值类型为 vector<int>,即返回表示乘法运算结果的整数数组(按位存储)。

在函数内部,定义了一个新的 vector<int> 类型的变量 C,用于存储最终的乘法运算结果,初始为空。还定义了一个整型变量 t,用于暂存每一步运算产生的进位,初始化为 0

这里使用了一个 for 循环来模拟竖式乘法的过程,循环条件 i < A.size() || t 表示只要还没遍历完 A 向量中的所有元素或者还有进位(t 不为 0),就继续循环。

在循环体中,首先判断如果当前索引 i 小于 A 的大小,就将 A 中当前位数字与 b 相乘,并累加到 t 上(模拟乘法运算的每一位相乘以及进位累加过程)。

然后将 t 的个位数(即 t % 10)通过 push_back 函数添加到结果向量 C 中,这相当于获取当前位的结果数字并存储到结果中。

最后将 t 除以 10,去掉已经处理过的个位数,得到新的进位值,用于下一次循环的进位处理。

这是一个 while 循环,用于去除结果向量 C 末尾可能存在的多余的 0

条件 C.size() > 1 && C.back() == 0 表示当结果向量长度大于 1(避免把唯一的一位数字 0 也去掉了)并且最后一位数字是 0 时,就调用 pop_back 函数删除最后一位数字,直到不满足这个条件为止,也就是把末尾连续的 0 都去掉了。

最后函数返回处理好的结果向量 C,也就是 Ab 的高精度乘法运算的最终结果。

4.高精度除法

// A / b = C ... r, A >= 0, b > 0
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();
    return C;
}

该代码实现了高精度整数除法的功能。给定一个表示高精度整数的 vector<int> 类型的被除数 A(按低位到高位的顺序存储每一位数字)、一个正整数除数 b,通过函数运算得到商 C(同样以 vector<int> 按低位到高位存储每一位数字)以及余数 r,并且对商的结果做了去除末尾多余 0 的处理。

定义了名为 div 的函数,它接收三个参数:一个 vector<int> 类型的引用 A(引用传递可避免大对象拷贝,提高效率)作为被除数,一个 int 类型的正整数 b 作为除数,一个 int 类型的引用 r 用于存储余数。函数的返回值类型是 vector<int>,代表商。

在函数内部,首先创建了一个空的 vector<int> 变量 C,用于后续存储计算得到的商。然后将余数 r 初始化为 0,为后续的除法运算做准备

这里使用一个从高位到低位遍历被除数 Afor 循环来模拟手工进行除法运算的过程。

在每次循环中,先将当前余数 r 乘以 10(相当于将余数左移一位,为加上被除数的下一位数字做准备,模拟竖式除法中逐位除的操作),再加上被除数 A 当前位的数字,得到新的临时数值(也就是当前这一步除法运算的被除数部分)。

接着将这个新的临时数值除以除数 b,得到的商通过 push_back 函数添加到结果向量 C 中,这就完成了商的当前位数字的计算。

最后,通过 r %= b 计算得到这一步运算后的余数,用于下一次循环与被除数的下一位数字继续进行除法运算。

由于之前是从高位到低位依次计算并存储商的每一位数字到 C 中,所以需要调用 reverse 函数将 C 的元素顺序反转过来,使其符合正常的数字表示顺序(从低位到高位)。

然后使用 while 循环来去除商 C 末尾可能存在的多余的 0。条件 C.size() > 1 && C.back() == 0 表示当 C 的长度大于 1(避免把唯一的一位数字 0 也去掉了)且最后一位数字是 0 时,就调用 pop_back 函数删除最后一位数字,直到不满足该条件为止,以此保证商的结果在表示上更加简洁合理。

最后函数返回处理好的结果向量 C,也就是高精度整数除法运算得到的商。而余数则通过引用参数 r 传递回调用函数的地方,方便调用者获取余数信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值