方法1:辗转相除法(欧几里得算法)
欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:
定理:gcd(a,b) = gcd(b,a mod b)
证明:a可以表示成a = kb + r,则r = a mod b
假设d是a,b的一个公约数,则有
d|a, d|b,而r = a - kb,因此d|r
因此d是(b,a mod b)的公约数
假设d 是(b,a mod b)的公约数,则
d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证
代码如下:
int gcd(int a,int b){
if(b == 0)
return a;
return gcd(b,a%b);
}
int main()
{
int a = 12,b = 18;
int res = gcd(a,b);
cout << a << "和"<< b << "的最大公约数是" << res<<endl;
return 0;
}
方法2:更相减损术
更相减损法:更相减损术, 出自于中国古代的《九章算术》,也是一种求最大公约数的算法。
①先判断两个数的大小,如果两数相等,则这个数本身就 是就是它的最大公约数。
②如果不相等,则用大数减去小数,然后用这个较小数与它们相减的结果相比较,如果相等,则这个差就是它们的最大公约数,而如果不相等,则继续执行②操作。
代码如下:
int gcd(int a,int b){
while (true)//用大数减去小数并将结果保存起来
{
if (a > b)
{
a -= b;
}
else if(a < b)
{
b -= a;
}
else//如果两个数相等时,则这个数就是最大公约数
{
return a;
}
}
}
int main()
{
int a = 12,b = 18;
int res = gcd(a,b);
cout << a << "和"<< b << "的最大公约数是" << res<<endl;
return 0;
}
方法3:Stein算法(结合辗转相除法和更相减损法的优势以及移位运算)
众所周知,移位运算的性能非常快。对于给定的正整数a和b,不难得到如下的结论。其中gcb(a,b)的意思是求a,b的最大公约数的函数
- 当a和b均为偶数,gcb(a,b) = 2gcb(a/2, b/2) = 2gcb(a>>1, b>>1)
- 当a为偶数,b为奇数,gcb(a,b) = gcb(a/2, b) = gcb(a>>1, b)
- 当a为奇数,b为偶数,gcb(a,b) = gcb(a, b/2) = gcb(a, b>>1)
- 当a和b均为奇数,利用更相减损术运算一次,gcb(a,b) = gcb(b, a-b), 此时a-b的结果必然是偶数,又可以继续进行移位运算。
代码如下:
int gcd(int a,int b){
if(a == 0) return b;
if(b == 0) return a;
if(a % 2 == 0 && b % 2 == 0) return 2 * gcd(a >> 1, b >> 1);
else if(a % 2 == 0) return gcd(a >> 1, b);
else if(b % 2 == 0) return gcd(a, b >> 1);
else return gcd(abs(a - b), min(a, b));
}
int main()
{
int a = 12,b = 18;
int res = gcd(a,b);
cout << a << "和"<< b << "的最大公约数是" << res<<endl;
return 0;
}