GCD的两种简单写法

基本原理是辗转相除法,具体原理请点击链接:辗转相除法

第一种:

int gcd(int a, int b)
{
    return !b ? a : gcd(b, a%b);
}

 

如果b == 0,就直接输出a;如果b != 0,gcd(b, a%b),直至b == 0。

第二种:

int gcd(int a, int b)
{
    while(b^=a^=b^=a%=b);
    return a;
}

这里进行了三次异或运算交换了两数的数值。

我们把while语句展开:

while(b > 0)
{
    a = a%b;//求出余数赋值给a
    b = b^a;
    a = a^b;
    b = b^a;//三次异或交换数值
}

 

<think>我们正在讨论C++中实现GCD(最大公约数)函数的代码。根据引用内容,我们看到了几种不同的实现方式,包括使用C++内部函数__gcd()以及手动实现辗转相除法(欧几里得算法)。 首先,注意__gcd()函数是GNU扩展,并不是标准C++库的一部分,但它存在于一些编译器的<algorithm>头文件中。而手动实现辗转相除法是通用的方法。 下面我们将展示几种实现方式: 1. 使用__gcd()函数(需注意可移植性): 需要包含头文件<algorithm>,然后直接调用__gcd(x, y)。注意:该函数要求参数为整数类型(不能是浮点数)。 2. 手动实现辗转相除法(递归版本): 递归版本简洁,但递归深度可能较大,对于非常大的数可能不是最优。 3. 手动实现辗转相除法(非递归版本): 使用循环,避免递归带来的栈开销。 4. 使用C++17标准中的gcd函数(在<numeric>头文件中): 从C++17开始,标准库提供了std::gcd,但请注意编译器支持情况。 由于引用中主要提到了__gcd()和辗转相除法,而用户要求示例代码,我们将提供这些代码。 注意:用户没有明确要求使用C++17标准,所以我们主要展示前三种方法。 示例代码: 方法1:使用__gcd()函数 ```cpp #include <iostream> #include <algorithm> // 注意:__gcd()在<algorithm>中,但它是非标准的 int main() { int a, b; std::cout << "Enter two integers: "; std::cin >> a >> b; // 调用__gcd函数 int gcd_value = __gcd(a, b); // 注意:函数名前有两个下划线 std::cout << "GCD (using __gcd) is: " << gcd_value << std::endl; return 0; } ``` 方法2:递归版本的辗转相除法 ```cpp #include <iostream> // 递归函数计算GCD int gcd_recursive(int a, int b) { if (b == 0) return a; return gcd_recursive(b, a % b); } int main() { int a, b; std::cout << "Enter two integers: "; std::cin >> a >> b; // 处理负数:最大公约数通常定义为正数 a = abs(a); b = abs(b); int gcd_value = gcd_recursive(a, b); std::cout << "GCD (recursive) is: " << gcd_value << std::endl; return 0; } ``` 方法3:非递归版本的辗转相除法 ```cpp #include <iostream> #include <cstdlib> // 用于abs函数 // 非递归(迭代)版本 int gcd_iterative(int a, int b) { a = abs(a); b = abs(b); while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } int main() { int a, b; std::cout << "Enter two integers: "; std::cin >> a >> b; int gcd_value = gcd_iterative(a, b); std::cout << "GCD (iterative) is: " << gcd_value << std::endl; return 0; } ``` 注意: - 辗转相除法要求两个整数,我们使用绝对值确保非负(因为最大公约数是非负的)。 - 在递归版本中,递归深度可能较大,对于非常大的数(比如斐波那契数列相邻两项)可能会导致栈溢出。迭代版本则没有这个问题。 另外,引用[4]中提到了递归和非递归的写法,我们已包含。 如果用户使用的是支持C++17的编译器,可以使用标准库中的gcd函数: ```cpp #include <iostream> #include <numeric> // C++17标准,包含std::gcd int main() { int a, b; std::cout << "Enter two integers: "; std::cin >> a >> b; int gcd_value = std::gcd(a, b); // 注意:需要编译器支持C++17 std::cout << "GCD (using std::gcd) is: " << gcd_value << std::endl; return 0; } ``` 但请注意,使用std::gcd需要编译器开启C++17支持。 总结:推荐使用迭代版本的辗转相除法,因为它不依赖于特定的编译器扩展,也没有递归深度问题。如果确定环境支持__gcd()(如GCC),也可以使用它。 根据用户要求,我们生成了相关问题。 §§相关问题§§ 1. C++中除了__gcd()还有哪些数学函数可以方便地处理整数运算? 2. 辗转相除法的时间复杂度是多少?是否有更快的求最大公约数的方法? 3. 如何处理大整数的最大公约数计算(例如超过long long范围)? 4. 在C++中,如何求多个数的最大公约数?</think>以下是C++中实现最大公约数(GCD)函数的几种方法及示例代码: ### 1. 使用标准库函数 `__gcd()`(非标准但广泛支持) ```cpp #include <iostream> #include <algorithm> // 必需的头文件 int main() { int a, b; std::cin >> a >> b; int result = __gcd(a, b); // 直接调用内置函数 std::cout << "GCD: " << result << std::endl; return 0; } ``` - **特点**:语法简洁,但属于GCC扩展(非C++标准),适用于竞赛编程[^1][^4]。 - **限制**:仅支持整数类型,不支持浮点数。 --- ### 2. 手动实现辗转相除法(递归版) ```cpp int gcd_recursive(int a, int b) { return b == 0 ? a : gcd_recursive(b, a % b); } ``` - **原理**:基于定理 $\gcd(a, b) = \gcd(b, a \mod b)$[^3]。 - **时间复杂度**:$O(\log(\min(a,b)))$。 --- ### 3. 手动实现辗转相除法(迭代版) ```cpp int gcd_iterative(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } ``` - **优点**:避免递归栈溢出风险,适合大整数运算。 - **示例**: ```cpp Input: a=56, b=98 Steps: 56 % 98 = 56 → (98,56) 98 % 56 = 42 → (56,42) 56 % 42 = 14 → (42,14) 42 % 14 = 0 → GCD=14 ``` --- ### 4. C++17标准库 `std::gcd`(推荐) ```cpp #include <iostream> #include <numeric> // C++17标准头文件 int main() { int a, b; std::cin >> a >> b; std::cout << "GCD: " << std::gcd(a, b) << std::endl; return 0; } ``` - **要求**:编译器需支持C++17标准(编译选项:`-std=c++17`)。 --- ### 关键说明 1. **负数处理**:上述实现均返回非负结果(通过取绝对值隐式处理)。 2. **零值处理**:若输入为`(a,0)`,结果返回`|a|`。 3. **扩展应用**:计算最小公倍数(LCM)公式: $$ \text{LCM}(a,b) = \frac{|a \times b|}{\gcd(a,b)} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值