C语言复习---获取最大公约数(辗转相除法和更相减损法)

时间:2020-12-04 00:30:09

源自:百度百科 

辗转相除法

辗转相除法:辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法

例如,求(319377):
∵ 319÷377=0(余319)
∴(319377)=(377319);
∵ 377÷319=1(余58)
∴(377319)=(31958);
∵ 319÷58=5(余29)
∴ (31958)=(5829);
∵ 58÷29=2(余0)
∴ (5829)= 29;
∴ (319377)=29

用辗转相除法求几个数的最大公约数,可以先求出其中任意两个数的最大公约数,再求这个最大公约数与第三个数的最大公约数,依次求下去,直到最后一个数为止。最后所得的那个最大公约数,就是所有这些数的最大公约数。

更相减损法

第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用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。
这个过程可以简单的写为:
(9863)=(3563)=(3528)=(728)=(721)=(714)=(77)=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)(/2/2) =>(65,26)=(39,26)=(13,26)=(13,13)=13. (*2*2) => 52 [1]

比较:

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

代码实现

一:最简单方法

#include <stdio.h>
#include <stdlib.h>


int main()
{
    int m, n,temp,i;
    scanf("%d", &m);
    scanf("%d", &n);
    
    if (m>n)
    {
        temp = m;
        m = n;
        n = temp;
    }

    for (i = m; i >= 1;i--)
        if (m%i==0 && n%i==0)
            break;

    printf("%d\n", i);

    system("pause");
    return 0;
}

二:辗转相除法(递归)

#include <stdio.h>
#include <stdlib.h>

int gcd(int a, int b) { int mod; if ((mod = a % b) == 0) return b; return gcd(b, mod); } int main()
{
    int m, n,ret;
    scanf("%d", &m);
    scanf("%d", &n);

    ret = gcd(m, n);
    printf("%d", ret);
    
    system("pause");
    return 0;
}

三:辗转相除法(非递归)

int gcd(int a, int b)
{
    int mod=a % b;
    while (mod!=0)
    {
        a = b;
        b = mod;
        mod = a % b;
    }
    return b;
}

四:更相减损法(非递归)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int gcd(int a, int b)
{
    int val= a - b;
    while (val != b)
    {
        if (b>val)
        {
            a = b;
            b = val;
        }
        else
        {
            a = val;
        }
        val = a - b;
    }
    return val;
}

int main()
{
    int m, n,ret,temp,count=0;
    scanf("%d", &m);
    scanf("%d", &n);

    if (m == n)
    {
        printf("%d", m);
        return 0;
    }

    if (m < n)
    {
        temp = m;
        m = n;
        n = temp;
    }

    while (m%2 == 0 && n%2 == 0)
    {
        count++;
        m /= 2;
        n /= 2;
    }
    
    ret = gcd(m, n);
    printf("%d", ret*((int)pow(2,count)));  //使用pow需要进行(int)转换,不然会报错
    
    system("pause");
    return 0;
}