求两个数的最大公约数3种算法

方法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的最大公约数的函数

  1. 当a和b均为偶数,gcb(a,b) = 2gcb(a/2, b/2) = 2gcb(a>>1, b>>1)
  2. 当a为偶数,b为奇数,gcb(a,b) = gcb(a/2, b) = gcb(a>>1, b)
  3. 当a为奇数,b为偶数,gcb(a,b) = gcb(a, b/2) = gcb(a, b>>1)
  4. 当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;
}

你可能感兴趣的:(算法)