您的位置:首页 > 编程语言 > C语言/C++

求两个整数的最小公倍数和最大公约数的算法及其C++实现

2016-11-04 22:23 609 查看
今天碰到一道C++练习题“求两个整数的最小公倍数和最大公约数的算法及其C++实现”,感觉可以做个整理笔记。

最大公约数

最大公约数(英语:Greatest Common Divisor,简写为G.C.D.;或Highest Common Factor,简写为H.C.F.),指某几个整数共有约数中最大的一个。

求两个整数最大公约数主要的方法:

列举法:各自列出约数,再找出最大的公约数

素因数分解法:两数各作素因数分解,然后取出共有的项相乘,所得的积就是这几个数的最大公约数。

短除法:短除法求最大公约数,先用这几个数的公约数连续去除,一直除到所有的商互质为止,然后把所有的除数连乘起来,所得的积就是这几个数的最大公约数。

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

例如,求(319,377):

∵ 319÷377=0(余319)

∴(319,377)=(377,319);

∵ 377÷319=1(余58)

∴(377,319)=(319,58);

∵ 319÷58=5(余29),

∴ (319,58)=(58,29);

∵ 58÷29=2(余0),

∴ (58,29)= 29;

∴ (319,377)=29.

扩展欧几里德算法:扩展欧几里得算法(又称扩充欧几里得算法)是用来解某一类特定的不定方程的一种方法,常用用来求解模线性方程及方程组。扩展的欧几里得算法可以用来计算模逆元,而模逆元在公钥密码学中占有举足轻重的地位。

基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。

证明:设 a>b。

1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;

2,ab≠0 时

设 ax1+by1=gcd(a,b);

bx2+(a mod b)y2=gcd(b,a mod b);

根据朴素的欧几里德原理有 gcd(a,b)=gcd(b,a mod b);

则:ax1+by1=bx2+(a mod b)y2;

即:ax1+by1=bx2+(a-(a/b)*b)y2=ay2+bx2-(a/b)*by2;

根据恒等定理得:x1=y2; y1=x2-(a/b)*y2;

这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.

上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。

更相减损法:也叫更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。

第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用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)(/2/2) =>(65,26)=(39,26)=(13,26)=(13,13)=13. (*2*2) => 52

Stein算法:Stein算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。和欧几里德算法算法不同的是,Stein算法只有整数的移位和加减法,这对于程序设计者是一个福音。

设置A1=A、B1=B和C1=1

1、如果An=0,Bn*Cn是最大公约数,算法结束

2、如果Bn=0,An*Cn是最大公约数,算法结束

3、如果An和Bn都是偶数,则An+1=An/2,Bn+1=Bn/2,Cn+1=Cn*2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可)

4、如果An是偶数,Bn不是偶数,则An+1=An/2,Bn+1=Bn,Cn+1=Cn (很显然啦,2不是奇数的约数)

5、如果Bn是偶数,An不是偶数,则Bn+1=Bn/2,An+1=An,Cn+1=Cn (很显然啦,2不是奇数的约数)

6、如果An和Bn都不是偶数,则An+1=|An-Bn|,Bn+1=min(An,Bn),Cn+1=Cn

7、n加1,转步骤1

考虑欧几里德算法,最恶劣的情况是,每次迭代a=2b-1,这样,迭代后,r=b-1。如果a小于2N,这样大约需要4N次迭代。而考虑Stein算法,每次迭代后,显然A(n+1)B(n+1)≤AnBn/2,最大迭代次数也不超过4N次。也就是说,迭代次数几乎是相等的。但是,需要注意的是,对于大素数,试商法将使每次迭代都更复杂,因此对于大素数Stein将更有优势。

以上内容整理自维基百科,百度百科

C++实现

辗转相除法:

#include<iostream>
int main()
{
int a,b,c;
scanf("%d %d",&a,&b);
if(a!=0&&b!=0)   //先判断输入整数中有无零值,有零值的话无法求公约数返回error;
{
do{
c=a%b;
a=b;
b=c;
}while(c);
}
else
printf("error\n");
printf("%d\n",a);
return 0;
}


更相减损法:

#include<iostream>
#include<cmath>
int main()
{
int a,b,n=0;
scanf("%d %d",&a,&b);
if(a!=0&&b!=0)   //先判断输入整数中有无零值,有零值的话无法求公约数返回error;
{
while(a%2==0&&b%2==0)
{
a/=2;
b/=2;
n++;
}
while(a!=b)
{
(a>b)?a-=b:b-=a;
}
a=a*pow(2,n);
printf("%d\n",a);
}
else
printf("error\n");
return 0;
}


Stein算法:

#include<iostream>
int gcd(int n,int m)      //适用于计算很大的数的最大公约数;
{
if(n==m)
return n;
else if(n==0)      //不明白这个算法为什么有零值还能求公约数,后头再查查
return m;
else if(m==0)
return n;
else if(m>n)
return gcd(m,n);
if(n%2==0)
{
if(m%2==0)
return gcd(n>>1,m>>1)<<1;
else
return gcd(n>>1,m);
}
else
{
if(m%2==0)
return gcd(n,m>>1);
else
return gcd((n-m)>>1,m);
}
}
int main()
{
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}


最小公倍数

最小公倍数是数论中的一个概念。若有一个数X,可以被另外两个数A、B整除,且X大于(或等于)A和B,则X为A和B的公倍数。A和B的公倍数有无限个,而所有的公倍数中,最小的公倍数就叫做最小公倍数。两个整数公有的倍数称为它们的公倍数,其中最小的一个正整数称为它们两个的最小公倍数。同样地,若干个整数公有的倍数中最小的正整数称为它们的最小公倍数。n整数 a1,a2,…,an的最小公倍数一般记作: [a1,a2,…,an],或者参照英文记法记作 lcm(a1,a2,…,an),其中lcm是英语中“最小公倍数”一词(lowest common multiple)的首字母缩写。

例如,十天干和十二地支的混合称为一个阴历年,干支循环回归同一名称的所需时间,就是12和10的最小公倍数,即是60──一个“甲子”。

(摘自维基百科)

C++算法实现

根据最大公约数来求最小公倍数,以辗转相除法为例:

#include<iostream>
int main()
{
int a,b,c,n,m;
scanf("%d %d",&n,&m);
if(n!=0&&m!=0)   //先判断输入整数中有无零值,有零值的话无法求公约数返回error;
{
a=n;
b=m;
do{
c=a%b;
a=b;
b=c;
}while(c);
}
else
printf("error\n");
printf("%d\n",n*m/a);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 C++
相关文章推荐