c++最大公约数和最小公倍数的深入剖析

目录

一、概念基础

二、常见算法及深度解析

1. 辗转相除法(欧几里得算法)

2. 更相减损术

3. 结合辗转相除法和更相减损术(优化算法)

三、应用场景全面举例

1. 化简分数

2. 判断互质关系

一、什么是最小公倍数

二、求最小公倍数的常见算法思路(基于 C++)

(一)暴力枚举法

(二)利用最大公约数(GCD)来求

三、多变量求最小公倍数

四、最小公倍数在实际编程中的应用场景

(一)任务调度问题

(二)分数运算中的通分

五、性能优化与注意事项

(一)溢出问题

(二)算法效率优化

一、利用最大公约数(GCD)求最小公倍数

二、质因数分解法

三、使用 C++ 标准库中的 lcm 函数(C++17 及以上版本支持)

利用最大公约数(GCD)求最小公倍数

1. 理论基础

2. 求最大公约数的欧几里得算法(辗转相除法)实现细节

3. 利用求出的最大公约数计算最小公倍数

质因数分解法

1. 原理深入剖析

2. C++ 代码详细实现与步骤解释

使用 C++ 标准库中的 lcm 函数(C++17 及以上版本支持)

1. 函数介绍与使用示例

2. 适用场景与优势



一、概念基础

最大公约数(Greatest Common Divisor,GCD)作为数论中的一个关键概念,在多个整数之间发挥着重要作用。从数学定义来讲,对于给定的两个或多个整数,其最大公约数就是能够同时整除这些整数的最大正整数。

例如,考虑整数 12 和 18:

  • 12 的所有约数(即能够整除 12 的正整数)包括 1、2、3、4、6、12。
  • 18 的所有约数有 1、2、3、6、9、18。
    通过对比它们的约数集合,可以清晰地发现共有的约数为 1、2、3、6,其中数值最大的 6 就是 12 和 18 的最大公约数。

在更广泛的数学和编程应用场景中,最大公约数有着诸多用途。比如在分数运算里化简分数时,必须依靠最大公约数将分子分母化为最简形式,以保证运算结果的准确性和规范性;在判断两个数是否互质(即它们的最大公约数为 1)方面也起着决定性作用,而互质这一特性在密码学、数论算法等诸多领域都有着关键应用,像一些加密算法在生成密钥等操作时会要求所选的数是互质的,这就需要通过计算最大公约数来进行验证。

二、常见算法及深度解析

1. 辗转相除法(欧几里得算法)

  • 算法原理
    辗转相除法基于一个重要的定理:两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数。具体操作过程是,用较大的整数除以较小的整数,得到一个商和余数,然后将除数作为新的被除数,余数作为新的除数,不断重复这个除法过程,直到余数为 0 时,此时的除数就是原来两个数的最大公约数。

以计算 252 和 105 的最大公约数为例来详细说明这个过程:

  • 首先,252 ÷ 105 = 2……42,这里 2 是商,42 是余数。

  • 接着,把 105 作为被除数,42 作为除数,即 105 ÷ 42 = 2……21。

  • 再把 42 作为被除数,21 作为除数,42 ÷ 21 = 2……0,此时余数为 0,所以 21 就是 252 和 105 的最大公约数。

  • 代码实现细节及分析
    以下是使用 C++ 实现辗转相除法求最大公约数的函数代码:

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    while (b!= 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

在这段代码中:

  • 函数gcd接受两个整数参数ab,代表要求最大公约数的两个数。

  • 通过while循环来不断执行辗转相除的操作,只要余数b不为 0,就持续更新ab的值。具体来说,先将当前的b值保存到临时变量temp中,然后让b等于a除以b的余数(b = a % b),再把temp(也就是原来的b)赋值给a,实现了被除数和除数的更新,这个过程模拟了辗转相除的数学步骤。

  • b最终变为 0 时,循环结束,此时的a就是最初输入的两个数的最大公约数,函数返回该值。

  • 算法复杂度分析
    辗转相除法在时间复杂度方面有着良好的性能表现。在最坏的情况下,例如求两个连续的斐波那契数(如F(n)F(n - 1)F(n)表示第n个斐波那契数)的最大公约数时,其时间复杂度接近O(log n),这里的n是指两个输入数中较大的那个数。在平均情况下,它的运算效率也比较高,这使得它在实际的编程应用中被广泛采用,尤其是处理较大规模整数求最大公约数的场景时,能够快速得出结果,减少计算时间和资源消耗。

2. 更相减损术

  • 算法原理
    更相减损术是我国古代数学中的杰出算法成果,其核心思想是:以较大的数减去较小的数,然后用所得的差与较小的数再次比较大小,并继续以大数减小数的操作,如此反复进行,直到所得的减数和差相等为止,这个相等的值就是原来两个数的最大公约数。

例如,计算 98 和 63 的最大公约数:

  • 首先,98 - 63 = 35。

  • 接着,63 - 35 = 28。

  • 然后,35 - 28 = 7。

  • 再接着,28 - 7 = 21。

  • 继续,21 - 7 = 14。

  • 最后,14 - 7 = 7,此时减数和差相等,所以 7 就是 98 和 63 的最大公约数。

  • 代码实现细节及分析
    以下是用 C++ 实现更相减损术求最大公约数的代码示例:

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    while (a!= b) {
        if (a > b) {
            a -= b;
        } else {
            b -= a;
        }
    }
    return a;
}

在这段代码里:

  • 函数gcd同样接收两个整数ab作为输入参数。

  • 通过while循环来持续执行相减操作,只要ab不相等,就判断它们的大小关系。如果a大于b,就用a减去b,更新a的值;反之,如果b大于a,就用b减去a,更新b的值。这样不断循环,直到ab相等,此时的a(也就是相等后的这个值)就是最大公约数,最后函数返回该值。

  • 算法复杂度分析
    更相减损术的时间复杂度在最坏情况下相对较高,可能达到O(max(a, b)),这里ab是输入的两个数。也就是说,在某些极端情况下,比如两个数相差非常大且需要多次相减操作时,计算次数会随着输入数的大小而增加较多。不过,在一些数据分布相对均匀的实际场景中,其实际运算次数可能并不会特别多,但总体来讲,相较于辗转相除法,在多数常规应用场景下,它的效率会稍低一些,不过由于其蕴含的独特数学思想以及在一些特定领域的应用价值,依然值得深入了解。

3. 结合辗转相除法和更相减损术(优化算法)

  • 算法原理
    这种优化算法巧妙地结合了前两者的优势。首先,利用更相减损术对于偶数的处理优势,当两个数ab均为偶数时,先将它们都除以 2,同时记录下除掉的 2 的个数(可以通过一个变量,每次除以 2 时就让其自乘 2 来实现对 2 的幂次方的记录),然后对得到的新的ab(此时至少有一个是奇数)使用辗转相除法来求最大公约数,最后将通过辗转相除法得到的最大公约数乘上之前除掉的 2 的个数对应的 2 的幂次方,这样得到的结果就是原来ab的最大公约数。

例如,对于 48 和 36 这两个数:

  • 第一步,发现它们都是偶数,48÷2 = 24,36÷2 = 18,同时记录因子 2(假设用变量factor表示,初始值为 1,此时factor = 2)。

  • 接着,24 和 18 还是偶数,继续操作,24÷2 = 12,18÷2 = 9,factor更新为factor *= 2,即factor = 4

  • 此时,12 和 9 中只有 12 是偶数,不符合均为偶数的条件了,对 12 和 9 使用辗转相除法:12÷9 = 1……3,9÷3 = 3……0,得到最大公约数为 3。

  • 最后,将这个 3 乘以之前记录的factor(值为 4),得到 12,这就是 48 和 36 的最大公约数。

  • 代码实现细节及分析
    以下是结合辗转相除法和更相减损术求最大公约数的 C++ 代码示例:

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    int factor = 1;
    while (a % 2 == 0 && b % 2 == 0) {
        a /= 2;
        b /= 2;
        factor *= 2;
    }
    while (b!= 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a * factor;
}

在代码中:

  • 首先定义了变量factor并初始化为 1,用于记录除掉的 2 的幂次方。

  • 通过第一个while循环来处理ab均为偶数的情况,只要ab都能被 2 整除,就分别除以 2,并让factor乘以 2 来更新其值,这样不断提取公因子 2,直到ab至少有一个不再是偶数。

  • 接着,使用第二个while循环执行辗转相除法,其原理和前面单独介绍辗转相除法时的代码逻辑一致,通过不断更新ab的值,直到b为 0,此时得到的a是经过前面处理后的ab的最大公约数。

  • 最后,将这个通过辗转相除法得到的最大公约数a乘以factor,得到的就是最初输入的ab的最大公约数,函数返回该最终结果。

  • 算法复杂度分析
    这种优化算法由于先通过快速处理偶数情况,有效地减少了后续辗转相除法的运算规模,整体的时间复杂度依然接近O(log n),这里的n同样是指输入的两个数中较大的那个数。不过在处理一些较大且含有较多 2 因子的数时,相比单纯的辗转相除法,它能够通过提前去除大量的 2 因子,从而减少辗转相除的迭代次数,运算速度会更快一些,在对效率要求较高的一些大规模数据处理或者数论相关复杂应用场景中,有着较好的优势。

三、应用场景全面举例

1. 化简分数

在数学的分数运算中,化简分数是一个常见操作。例如,对于分数12/18,要将其化为最简分数形式,就需要求出分子 12 和分母 18 的最大公约数。通过前面介绍的求最大公约数的算法(比如使用辗转相除法,求得 12 和 18 的最大公约数为 6),然后将分子分母同时除以这个最大公约数,即12÷6 = 218÷6 = 3,得到最简分数2/3

在 C++ 编程中,如果要实现一个分数类,在类的构造函数或者专门的化简方法中,就可以调用求最大公约数的函数来完成分数的化简操作。以下是一个简单的分数类示例代码,其中包含了利用最大公约数化简分数的功能:

#include <iostream>
using namespace std;

class Fraction {
private:
    int numerator;  // 分子
    int denominator;  // 分母
public:
    Fraction(int num, int den) : numerator(num), denominator(den) {
        simplify();
    }
    void simplify() {
        int gcd_value = gcd(numerator, denominator);
        numerator /= gcd_value;
        denominator /= gcd_value;
    }
    void display() {
        cout << numerator << "/" << denominator << endl;
    }
    int gcd(int a, int b) {
        while (b!= 0) {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
};

int main() {
    Fraction fraction(12, 18);
    fraction.display();
    return 0;
}

在这个代码中:

  • Fraction类表示分数,有numerator(分子)和denominator(分母)两个私有成员变量。
  • 构造函数接受分子和分母作为参数,并在初始化对象时调用simplify方法来化简分数。
  • simplify方法通过调用类内部定义的gcd函数(实现了辗转相除法求最大公约数)求出分子分母的最大公约数,然后将分子分母分别除以这个最大公约数来完成化简。
  • display方法用于输出化简后的分数形式。

2. 判断互质关系

判断两个数是否互质在很多领域都有着重要应用,

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值