C语言复习---获取最大公约数(辗转相除法和更相减损法)
源自:百度百科
辗转相除法
辗转相除法:辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法。
例如,求(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。
用辗转相除法求几个数的最大公约数,可以先求出其中任意两个数的最大公约数,再求这个最大公约数与第三个数的最大公约数,依次求下去,直到最后一个数为止。最后所得的那个最大公约数,就是所有这些数的最大公约数。
更相减损法
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用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 [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; }