求最大公约数的两种算法

转自:http://blog.csdn.net/a253664942/article/details/51051268

  • 1.辗转相除法

  辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法。
例如,求gcd(319,377):

377÷319=1(余58)
∴gcd377319)=gcd31958);
∵ 319÷58=5(余29),
∴ gcd31958)=gcd5829);
∵ 58÷29=2(余0),
∴ gcd5829)= 29;
∴ gcd319377)=29
  • 算法实现
//辗转相除法,此处默认m>n
int gcd(int m , int n){
    int r = 0 ;
    while(n){
        r = m%n;
        m = n;
        n = r;
    }
    return m;
}
  • 更相减损法:

  更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。
  《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
  第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
  第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
  则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
  其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。
  例1、用更相减损术求98与63的最大公约数。
  解:由于63不是偶数,把98和63以大数减小数,并辗转相减:

98-63=35
63-35=28
35-28=7
28-7=21
21-7=14
14-7=7

  所以,98和63的最大公约数等于7。
这个过程可以简单的写为:
(98,63)=(35,63)=(35,28)=(7,28)=(7,21)=(7,14)=(7,7)=7.
例2、用更相减损术求260和104的最大公约数。
  解:由于260和104均为偶数,首先用2约简得到130和52,再用2约简得到65和26。
此时65是奇数而26不是奇数,故把65和26辗转相减:

65-26=39
39-26=13
26-13=13

所以,260与104的最大公约数等于13乘以第一步中约掉的两个2,即13*2*2=52。
这个过程可以简单地写为:
(260,104)=(65,26)=(39,26)=(13,26)=(13,13)=13

  • 算法实现
//更相减损术
int gcd(int m , int n){
    int mul=1;
    while(!(m&0x1) && !(n&0x1) ){
        m>>=1;
        n>>=1;
        mul<<=1;
    }
    int res=1;
    while((res =m-n)!=n){
        m = n>=res?n:res;
        n = n<=res?n:res;
    }
    return n*mul;
}
  • 辗转相除法与更相减损术的区别

  (1)都是求最大公因数的方法,计算上辗转相除法以除法为主,更相减损术以减法为主,计算次数上辗转相除法计算次数相对较少,特别当两个数字大小区别较大时计算次数的区别较明显。
  (2)从结果体现形式来看,辗转相除法体现结果是以相除余数为0则得到,而更相减损术则以减数与差相等而得到。

  • 4.常用结论

在解有关最大公约数、最小公倍数的问题时,常用到以下结论:
  (1)如果两个数是互质数,那么它们的最大公约数是1,最小公倍数是这两个数的乘积。
  例如8和9,它们是互质数,所以(8,9)=1,[8,9]=72。
  (2)如果两个数中,较大数是较小数的倍数,那么较小数就是这两个数的最大公约数,较大数就是这两个数的最小公倍数。
  例如18与3,18÷3=6,所以(18,3)=3,[18,3]=18。
  (3)两个数分别除以它们的最大公约数,所得的商是互质数。
  例如8和14分别除以它们的最大公约数2,所得的商分别为4和7,那么4和7是互质数。
  (4)两个数的最大公约数与它们的最小公倍数的乘积等于这两个数的乘积。  
  PS:由上述第一条结论可知:两个数的最小公倍数求法: m*n/gcd(gcd为最大公约数)

转自:

http://blog.csdn.net/sunmenggmail/article/details/8197167

求两个或N个数的最大公约数(gcd)和最小公倍数(lcm)的较优算法

 #include <iostream>  
 #include <cmath>  
 using namespace std;     
 int gcd(int a, int b);  
 int ngcd(int *a, int n);  
 int lcm(int a, int b);  
 int nlcm(int *a, int n);     
 int main()  
 {  
     //int a,b;  
     //cin >> a >> b;  
     //cout << lcm(a, b) << endl;  
     int *a = new int[3];  
     a[0] = 3;  
     a[1] = 4;  
     a[2] = 5;  
     cout << nlcm(a, 3) << endl;  
    return 0;  
 }   
 //两个数的最大公约数--欧几里得算法  
 int gcd(int a, int b)  
 {  
     if (a < b)  
         swap(a, b);  
     if (b == 0)  
         return a;  
     else  
         return gcd(b, a%b);  
}   
//n个数的最大公约数算法  
//说明:   
//把n个数保存为一个数组  
//参数为数组的指针和数组的大小(需要计算的数的个数)  
//然后先求出gcd(a[0],a[1]), 然后将所求的gcd与数组的下一个元素作为gcd的参数继续求gcd  
//这样就产生一个递归的求ngcd的算法  
int ngcd(int *a, int n)  
{  
     if (n == 1)  
     return *a;  
     return gcd(a[n-1], ngcd(a, n-1));  
 }    
 //两个数的最小公倍数(lcm)算法  
 //lcm(a, b) = a*b/gcd(a, b)  
 int lcm(int a, int b)  
 {  
     return a*b/gcd(a, b);  
 }    
 //n个数的最小公倍数算法  
 //算法过程和n个数的最大公约数求法类似  
 //求出头两个的最小公倍数,再将欺和大三个数求最小公倍数直到数组末尾  
 //这样产生一个递归的求nlcm的算法  
 int nlcm(int *a, int n)  
 {  
     if (n == 1)  
         return *a;  
     else  
         return lcm(a[n-1], nlcm(a, n-1));  
 }  
  • 附录:联动优势笔试题:

(1)求数组最大公约数
(2)求数组前k个数升序,后面降序排列

/*
联动优势
20161025日做的,感觉C语言部分就有点难度,还是英文的;
java部分更不用说了
至于大编程题,呵呵了,记录切出次数,直接被pass了
把编程题记录如下:
1.有一个数组,求前k个数升序排列,后面的数降序排列
大概的接口: int* sortArrayAsDes(int* arr,int length,int k)
我遇到的问题:在线编译器GCC说找不到sort?????
2.求一个数组中最大公约数
int CalcuArrGCD(int* arr,int length)
*/

//排序数组
#include<algorithm>
#include<functional> //greater在这个库里面!!!
#include<iostream>
#include<exception>
using namespace std;
int *sortArrayAsDes(int* arry, int length, int k)
{
    sort(arry, arry + k - 1, less<int>());
    sort(arry + k, arry + length , greater<int>());
    return arry;
}
/*
//数组排序问题测试例程
int main(void)
{
    try
    {
        int testArr[10] = {4,2,1,5,7,8,2,3,9,7};
        int* resultArr;
        resultArr = sortArrayAsDes(testArr, 10, 5);
        cout << "原始数组为:" << endl;
        for (int i = 0; i < 10; i++)
        {
            cout << testArr[i] << " ";
        }
        cout << endl;
        cout << "排序后数组为:" << endl;
        for (int i = 0; i < 10; i++)
        {
            cout << *(resultArr+i) << " ";
        }
        cout << endl;
    }
    catch (exception ex)
    {
        cout << ex.what() << endl;
    }
}
*/

#include<iostream>
#include<algorithm>
using namespace std;
/*
  欧几里得算法求两数最大公约数
*/
int gcd_O(int a, int b)
{
    //首先对两数进行排序
    if (a > b)
        swap(a, b);
    //对特殊情况处理
    if (a == 0)
        return b;
    return gcd_O(a,b%a);
}

/*
更相减损术求解两数最大公约数
*/
int gcd_G(int a, int b)
{
    //首先判断两数是否为偶数
    int mul = 1;
    while ((a % 2 == 0) && (b % 2) == 0)
    {
        a =a/2;
        b =b/2;
        mul =mul*2;
    }
    //更相减损法
    if (a < b)
        swap(a, b);
    int res;
    while (( res = (a - b)) != b)
    {
        a = res>=b ? res : b;
        b = res>=b ? b : res;
    }
    //输出记得乘以2的约数
    return mul*b;
}

/*
  定义求解数组最大公约数子函数
  函数输入:int*a:输入待计算最大公约数数组指针
            int length:数组长度
*/
int ngcd(int* a, int length)
{
    //首先递归调用要定义截止条件
    if (length == 1)
        return *a;
    return gcd_O(ngcd(a, length - 1), *(a + length - 1));
}

/*
    定义求解最小公倍数子函数
    根据公式 lcm = a*b/gcd(a,b);
*/
int lcm(int a, int b)
{
    return(a*b / gcd_O(a, b));
}

/*
    定义求解一维数组最小公倍数子函数
*/
int nlcm(int* a, int length)
{
    if (length == 1)
        return *a;
    return lcm(nlcm(a, length - 1), *(a + length - 1));
}
//最大公约数两种求法测试程序
int main(void)
{
    int a, b;
    a = 14, b = 21;
    //http://www.ab126.com/shuxue/2797.html 在线计算器可算出数组最小公倍数为420,与测试一致。
    int array[5] = { 7, 14, 21, 28, 35 };
    int result;
    cout << "欧几里得算法求解最大公约数" << endl;
    result = gcd_O(a, b);
    cout << result << endl;
    cout << "更相减损术求解最大公约数" << endl;
    result = gcd_G(a, b);
    cout << result << endl;
    cout << "最小公倍数为" << endl;
    result = lcm(a, b);
    cout << result<<endl;
    cout << "求解数组最大公约数" << endl;
    result = ngcd(array, 5);
    cout << result << endl;
    cout << "求解数组最小公倍数" << endl;
    result = nlcm(array, 5);
    cout << result << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qiye005/article/details/52943184