[从零开始学算法]求最小公倍数与最大公约数

求两个数的最大公约数与最小公倍数

对于求两个数的最小公倍数与最大公约数,最大公约数等于两数相乘再除以最大公约数,所以问题的核心就是怎么求最大公约数。我所知道的有四种方法:穷举法(不推荐使用),辗转相除法(使用最多),更相减损术,Stein算法(密码领域用的多)

穷举法(暴力搜索)

穷举法就不多解释了直接给代码

int GCD1(int a,int b)//暴力搜索
{
    int gcd=(a>b?b:a);
    for(int i=gcd; i>0; i--)
    {
        if(a%i==0&&b%i==0)
        {
            gcd=i;
            break;
        }
    }
    return gcd;
}

辗转相除法(欧几里得算法)

辗转相除法分如下两部步:

  1. 较大数a对教小数b进行取余运算得到余数c;
  2. 若余数为零,则较小数为最大公约数;否则令a=b,b=c重新执行第一步

递归代码如下(要求a,b按大小输入):

int GCD2(int a,int b)//辗转相除
{
    return b==0?a:GCD2(b,a%b);
}

非递归代码如下:

int GCD2(int a,int b)//辗转相除
{
    int big,small;
    if(a>b)
    {
        big=a;
        small=b;
    }
    else
    {
        big=b;
        small=a;
    }
    for(int i=big%small; i>0; i=big%small)
    {
            big=small;
            small=i;
    }
    return small;
}

更相减损术

更相减损术用的是减法而不是除法,具体步骤如下:

  1. 两数若都为偶数则两数一直都除以2到不都为偶数,并记录除以了几个2;
  2. 较大数a减较小数b得到差值c;
  3. 若c与b相等,则c为最大公约数,否则令a=max(b,c),b=min(b,c)再执行第二步;

代码如下:

int GCD3(int a,int b)//更相减损术
{
    int mul=1;
    int big,small;
    if(a>b)
    {
        big=a;
        small=b;
    }
    else
    {
        big=b;
        small=a;
    }
    while(1)
    {
        if(big%2==0&&small%2==0)
        {
            mul*=2;
            big/=2;
            small/=2;
        }
        else break;
    }
    for(int i=big; i!=small; i=big-small)
    {
        if(i>small)
        {
            big=i;
        }
        else
        {
            big=small;
            small=i;
        }
    }
    return small*mul;
}

Stein算法

欧几里得算法与更相减损术的缺陷
       欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来。
       更相减损术在两数相差较大时,会进行多次无意义运算,两数相差越大,无意义运算越多,效率过低。
       一般实际应用中的整数很少会超过64位(当然已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。于是便有了Stein算法。
算法的思想
由J. Stein 1961年提出的Stein算法很好的解决了欧几里德算法中的这个缺陷,Stein算法只有整数的移位和加减法,为了说明Stein算法的正确性,首先必须注意到以下结论:

  1. gcd(a,a)=a,也就是一个数和其自身的公约数仍是其自身。
  2. gcd(ka,kb)=k gcd(a,b),也就是最大公约数运算和倍乘运算可以交换。特殊地,当k=2时,说明两个偶数的最大公约数必然能被2整除。
  3. 当k与b互为质数,gcd(ka,b)=gcd(a,b),也就是约掉两个数中只有其中一个含有的因子不影响最大公约数。特殊地,当k=2时,说明计算一个偶数和一个奇数的最大公约数时,可以先将偶数除以2。

算法的步骤

  1. 两数若都为偶数则两数一直都除以2到不都为偶数,并记录除以了几个2;
  2. 若两数中还有非偶数,将其除以2至奇数
  3. c=|数a-数b|,d=min(数a,数b),
  4. 若c为0则d为最大公约数,否则令a=c,b=d重复第二步

代码如下:

int GCD4(int a,int b)//Stein
{
    int mul=1;
    while(1)
    {
        if(a%2==0&&b%2==0)
        {
            a>>=1;
            b>>=1;
            mul<<=1;
        }
        else if(a%2==0)
        {
            a>>=1;
        }
        else if(b%2==0)
        {
            b>>=1;
        }
        else break;
    }
    while(a>0)
    {
        while(a%2==0)
        {
            a>>=1;
        }
        int abs=fabs(a-b);
        int small=a>b?b:a;
        a=abs;
        b=small;
    }
    return b*mul;
}

c++代码

具体实现代码及效果图:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int GCD1(int a,int b);//暴力搜索
int GCD2(int a,int b);//辗转相除
int GCD3(int a,int b);//更相减损术
int GCD4(int a,int b);//Stein算法
int main()
{
    int a=0,b=0;
    int gcd[4]= {1,1,1,1}; //最大公约数:greatest common divisor(gcd)
    int lcm[4]= {1,1,1,1}; //最小公倍数:least common multiple(lcm)
    while(cin>>a>>b)
    {
        gcd[0]=GCD1(a,b);
        gcd[1]=GCD2(a,b);
        gcd[2]=GCD3(a,b);
        gcd[3]=GCD4(a,b);
        for(int i=0; i<4; i++)
        {
            lcm[i]=a*(b/gcd[i]);//先算除法防止越界
            cout<<gcd[i]<<" "<<lcm[i]<<endl;
        }
    }
    return 0;
}

效果图
萌新一个,若代码有错误或算法思想有问题还望多多斧正;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值