趣味算法- 最大公约数和最小公倍数

最大公约数:辗转相除法 和 Stein算法

1, 辗转相除法原理:两个整数的最大公约数等于其中较小的数和两数的差的最大公约数。

证明:

设两数为a、b(b<a),用gcd(a,b)表示a,b的最大公约数,r=a mod b 为a除以b以后的余数,辗转相除法即是要证明gcd(a,b)=gcd(b,r)。
  第一步:令c=gcd(a,b),则设a=mc,b=nc
  第二步:根据前提可知r =a-kb=mc-knc=(m-kn)c
  第三步:根据第二步结果可知c也是r的因数
  第四步:可以断定m-kn与n互素【否则,可设m-kn=xd,n=yd,(d>1),则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc,b=nc=ycd,故a与b最大公约数成为cd,而非c】
  从而可知gcd(b,r)=c,继而gcd(a,b)=gcd(b,r)。


2, Stein算法

  1) 如果A=0,B是最大公约数,算法结束 
  2) 如果B=0,A是最大公约数,算法结束 
  3) 设置A1 = A、B1=B和C1 = 1 
  4) 如果An和Bn都是偶数,则An+1 =An /2,Bn+1 =Bn /2,Cn+1 =Cn *2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可) 
  5) 如果An是偶数,Bn不是偶数,则An+1 =An /2,Bn+1 =Bn ,Cn+1 =Cn (很显然啦,2不是奇数的约数) 
  6) 如果Bn是偶数,An不是偶数,则Bn+1 =Bn /2,An+1 =An ,Cn+1 =Cn (很显然啦,2不是奇数的约数) 
  7) 如果An和Bn都不是偶数,则An+1 =|An -Bn|,Bn+1 =min(An,Bn),Cn+1 =Cn 
  8) n++,转4 


最小公倍数:两数乘积除以最大公约数


#include <stdio.h>

int gcd_ZhanZhuanXiangChu(int a, int b)
{
    int n, m, r;

    if (a > b)
    {
        m = a;
        n = b;
    }
    else
    {
        m = b;
        n = a;
    }

    r = m%n;
    while(r != 0)
    {
        m = n;
        n = r;
        r = m % n;
    }

    return n;
}

int gcd_Stein(int a, int b)
{
    int m  = 0, n = 0;
    if (a == 0)
    {
        return b;
    }
    if (b == 0)
    {
        return a;
    }

    if ((a%2 == 0) && (b%2 == 0))
    {
        return 2 * gcd_Stein(a/2, b/2);
    }

    if (a%2 == 0)
    {
        return gcd_Stein(a/2, b);
    }

    if (b%2 == 0)
    {
        return gcd_Stein(a, b/2);
    }

    if (a > b)
    {
        m = a;
        n = b;
    }
    else
    {
        m = b;
        n = a;
    }
    
    return gcd_Stein((m-n)/2, n);
}

int main()
{
    int a[]={120, 36, 56,17,90};
    int b[]={84 , 12, 36,66,100};
    int i = 0, c = 0;

    printf("Calc Greatest Common Divisor and Least Common Multiple\n");
    printf("Test Zhan Zhuan Xiang Chu ============== \n");
    for (i = 0; i < 5; i++)
    {
        c = gcd_ZhanZhuanXiangChu(a[i], b[i]);
        printf("a=%d and b=%d gcd=%d lcm=%d\n", 
               a[i], b[i], c, a[i]*b[i]/c);
    }

    printf("\nTest Stein ================= \n");
    for (i = 0; i < 5; i++)
    {
        c = gcd_Stein(a[i], b[i]);
        printf("a=%d and b=%d, gcd=%d lcm=%d\n",
               a[i], b[i], c, a[i]*b[i]/c);
    }
    scanf("%d", &i);
    return 0;
}

算法复杂度分析: a, b (a > b) O(a, b) = log(a)




你可能感兴趣的:(趣味算法- 最大公约数和最小公倍数)