一、问题描述:
运行最大公约数的常用算法

二、问题分析与设计:
1.辗转相除法(又名欧几里德法)

①函数嵌套调用

其算法过程为: 前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数
1、大数放a中、小数放b中;
2、求a/b的余数;
3、若temp=0则b为最大公约数;
4、如果temp!=0则把b的值给a、temp的值给a;
5、返回第二步;

代码:

#include<iostream>
using namespace std;
int divisor(int a,int b)           //自定义函数求最大公约数
{int temp;                   //整形零时变量if(a<b)                     //a<b 则交换 {temp=a;a=b;b=temp;}while(b!=0){temp=a%b;              //a中大数除以b中小数循环取余,直到b及余数为0a=b;b=temp;}return a;                  //返回最大公约数到调用函数处
}
int multipile(int a,int b)         //自定义函数求最小公倍数
{int divisor(int a,int b);       //自定义函数返回值类型int temp;temp=divisor(a,b);          //再次调用自定义函数,求出最大公约数return(a*b/temp);           //返回最小公倍数到主调函数处进行输出
}
int main()
{int m,n,t1,t2;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0){    printf("请重新输入正确整数:");cin.clear();                //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=divisor(m,n);t2=multipile(m,n);printf("最大公因数为:%d\n",t1);printf("最小公倍数为:%d\n",t2);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int divisor(int a,int b)
{int temp;if(a<b){temp=a;a=b;b=temp;}while(b!=0){temp=a%b;a=b;b=temp;}return a;
}
void main()
{int m[5000],n[5000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<5000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<5000;i++){t1=divisor(m[i],n[i]);printf("%d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/5000;       //平均运行时间printf("%f milliseconds\n",duration);}

②函数递归调用

#include<iostream>
#include<time.h>
using namespace std;
int gcd(int a,int b)                 //自定义函数求最大公约数
{if(a%b==0)                    //终止条件return b;                   //b及为最大公约数elsereturn gcd(b,a%b);
}
int main()
{int m,n,t1;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0)  //判断输入两数字是否小于零或为小数{   printf("请重新输入正确整数:");cin.clear();            //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=gcd(m,n);printf("最大公因数为:%d\n",t1);printf("最小公倍数为:%d\n",m*n/t1);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int gcd(int a,int b)
{if(a%b==0)return b;elsereturn gcd(b,a%b);
}
void main()
{int m[2000],n[2000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<2000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<2000;i++){t1=gcd(m[2000],n[2000]);printf("%d  %d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/2000;       //平均运行时间printf("%f seconds\n",duration);}

流程图

2.穷举法(也称枚举法)利用数学定义

穷举法求两个正整数的最大公约数的解题步骤:从两个数中较小数开始由大到小列举,直到找到公约数立即中断列举,得到的公约数便是最大公约数。

定义1:对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。
定义2:对两个正整数a,b,如果若干个a之和或b之和能被b所整除或能被a所整除,则该和数即为所求的最小公倍数。
代码:

#include<iostream>
using namespace std;
int divisor(int a,int b)         //自定义函数求两数的最大公约数
{int temp;temp=(a>b)?b:a;         //采用条件运算表达式求出两个数中的最小值while(temp>0){if(a%temp==0&&b%temp==0)     //只要找到一个数能同时被a,b所整除,则中止循环break;temp--;                        //如不满足if条件则变量自减,直到能被a,b所整除}return(temp);                      //返回满足条件的数到主调函数处
}
int multiple(int a,int b)
{int p,q,temp;p=(a>b)?a:b;                     //求两个数中的最大值q=(a>b)?b:a;                     //求两个数中的最小值temp=p;                        //最大值赋给p为变量自增作准备while(1)                        //利用循环语句来求满足条件的数值{if(p%q==0)break;                  //只要找到变量的和数能被a或b所整除,则中止循环p+=temp;                   //如果条件不满足则变量自身相加}return(p);
}
int main()
{int m,n,t1,t2;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0){    printf("请重新输入正确整数:");cin.clear();                 //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=divisor(m,n);t2=multiple(m,n);printf("最大公因数为:%d\n",t1);printf("最小公倍数为:%d\n",t2);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int divisor(int a,int b)
{int temp;temp=(a>b)?b:a;while(temp>0){if(a%temp==0&&b%temp==0)break;temp--;}return(temp);
}
void main()
{int m[5000],n[5000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<5000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<5000;i++){t1=divisor(m[i],n[i]);printf("%d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/5000;       //平均运行时间printf("%f seconds\n",duration);
}

流程图

3. 更相减损法

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

代码:

#include<iostream>
#include<math.h>
using namespace std;
int gcd(int m,int n)                //求最大公约数
{int i=0,temp,x;while(m%2==0 && n%2==0)     //判断m和n能被多少个2整除(i个){m/=2;n/=2;i+=1;}if(m<n)                       //m保存大的值{temp=m;m=n;n=temp;}while(x){x=m-n;                     //{ 以较大的数减较小的数,m=(n>x)?n:x;             n=(n<x)?n:x;                //接着把所得的差与较小的数比较,if(n==(m-n))                //并以大数减小数。}break;}if(i==0)return n;else return (int )pow(2,i)*n;
}
int main()
{int m,n,t1;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0)  //判断输入两数字是否小于零或为小数{   printf("请重新输入正确整数:");cin.clear();                        //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=gcd(m,n);printf("最大公因数为:%d\n",t1);printf("最小公倍数为:%d\n",m*n/t1);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
int gcd(int m,int n)         //求最大公约数
{int i=0,temp,x;while(m%2==0 && n%2==0)  //判断m和n能被多少个2整除(i个){m/=2;n/=2;i+=1;}if(m<n)     //m保存大的值{temp=m;m=n;n=temp;}while(x){x=m-n;                     //{以较大的数减较小的数,m=(n>x)?n:x;               n=(n<x)?n:x;               //接着把所得的差与较小的数比较,if(n==(m-n))               //并以大数减小数。}break;}if(i==0)return n;else return (int )pow(2,i)*n;
}
void main()
{int m[2000],n[2000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<2000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<2000;i++){t1=gcd(m[i],n[i]);printf("%d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/2000;       //平均运行时间printf("%f seconds\n",duration);
}

流程图:

4.Stein算法

Stein算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。来研究一下最大公约数的性质,发现有 gcd( kx,ky ) = kgcd( x,y ) 这么一个非常好的性质。
试取 k=2,则有 gcd( 2x,2y ) = 2 * gcd( x,y )。很快联想到将两个偶数化小的方法。
那么一奇一个偶以及两个奇数的情况如何化小呢?
先来看看一奇一偶的情况: 设有2x和y两个数,其中y为奇数。因为y的所有约数都是奇数,所以 a = gcd( 2x,y ) 是奇数。
根据2x是个偶数不难联想到,a应该是x的约数。
我们来证明一下:
(2x)%a=0,设2x=n
a,因为a是奇数,2x是偶数,则必有n是偶数。
又因为 x=(n/2)*a,所以 x%a=0,即a是x的约数。
因为a也是y的约数,所以a是x和y的公约数,有 gcd( 2x,y ) <= gcd( x,y )。
因为gcd( x,y )明显是2x和y的公约数,又有gcd( x,y ) <= gcd( 2x,y ),
所以 gcd( 2x,y ) = gcd( x,y )。
至此,我们得出了一奇一偶时化小的方法。

再来看看两个奇数的情况:
设有两个奇数x和y,不妨设x>y,注意到x+y和x-y是两个偶数,
则有gcd( x+y,x-y ) = 2 * gcd( (x+y)/2,(x-y)/2 ),
那么 gcd( x,y ) 与 gcd( x+y,x-y ) 以及 gcd( (x+y)/2,(x-y)/2 ) 之间是不是有某种联系呢?
为了方便设 m=(x+y)/2 ,n=(x-y)/2 ,容易发现 m+n=x ,m-n=y 。
设 a = gcd( m,n ),则 m%a=0,n%a=0 ,
所以 (m+n)%a=0,(m-n)%a=0 ,即 x%a=0 ,y%a=0 ,
所以a是x和y的公约数,有 gcd( m,n )<= gcd(x,y)。
再设 b = gcd( x,y )肯定为奇数,则 x%b=0,y%b=0 ,
所以 (x+y)%b=0 ,(x-y)%b=0 ,
又因为x+y和x-y都是偶数,跟前面一奇一偶时证明a是x的约数的方法相同,
有 ((x+y)/2)%b=0,((x-y)/2)%b=0 ,即 m%b=0 ,n%b=0 ,
所以b是m和n的公约数,有 gcd( x,y ) <= gcd( m,n )。
所以 gcd( x,y ) = gcd( m,n ) = gcd( (x+y)/2,(x-y)/2 )。

*整理一下,对两个正整数 x>y :
1.均为偶数 gcd( x,y ) =2gcd( x/2,y/2 );
2.均为奇数 gcd( x,y ) = gcd( (x+y)/2,(x-y)/2 );
2.x奇y偶 gcd( x,y ) = gcd( x,y/2 );
3.x偶y奇 gcd( x,y ) = gcd( x/2,y ) 或 gcd( x,y )=gcd( y,x/2 );
现在已经有了递归式,还需要再找出一个退化情况。注意到 gcd( x,x ) = x ,就用这个。

①函数非递归调用
#include<iostream>
using namespace std;
int Stein( unsigned int x, unsigned int y )         //函数非递归调用
{     int factor = 0;                           //返回最大公约数x和y int temp;if ( x < y ){ temp = x;x = y;y = temp;}if ( 0 == y ){return 0;}while ( x != y ){                                      //当x时偶数时 if ( x & 0x1 ){if ( y & 0x1 ){                               //当x和y都是偶数时     y = ( x - y ) >> 1;x -= y;}else{                                //当x是偶数,y是奇数     y >>= 1;}}else{                                    //当x是奇数 if ( y & 0x1 ){x >>= 1;if ( x < y ){temp = x;x = y;y = temp;}}else{                                //当x和y都是奇数 x >>= 1;y >>= 1;++factor;}}}return ( x << factor );
}
int main()
{int m,n,t1;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0)        //判断输入两数字是否小于零或为小数{ printf("请重新输入正确整数:");cin.clear();                            //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=Stein(m,n);printf("最大公因数为:%d\n",t1);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int Stein( unsigned int x, unsigned int y )/* return the greatest common divisor of x and y */
{int factor = 0;int temp;if ( x < y ){temp = x;x = y;y = temp;}if ( 0 == y ){return 0;}while ( x != y ){if ( x & 0x1 ){/* when x is odd */if ( y & 0x1 ){/* when x and y are both odd */y = ( x - y ) >> 1;x -= y;}else{/* when x is odd and y is even */y >>= 1;}}else{/* when x is even */if ( y & 0x1 ){/* when x is even and y is odd */x >>= 1;if ( x < y ){temp = x;x = y;y = temp;}}else{/* when x and y are both even */x >>= 1;y >>= 1;++factor;}}}return ( x << factor );
}
void main()
{int m[2000],n[2000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<2000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<2000;i++){t1=Stein(m[2000],n[2000]);printf("%d  %d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/20000;       //平均运行时间printf("%f seconds\n",duration);}

②函数递归调用

#include<iostream>
using namespace std;
int gcd(int u,int v)
{if (u == 0) return v;if (v == 0) return u;// 寻找两个数的最大公约数if (~u & 1)                        // u是偶数{if (v & 1)                     // v是奇数return gcd(u >> 1, v);else                            // u和v都是偶数return gcd(u >> 1, v >> 1) << 1;}if (~v & 1)                         // u是奇数, v是偶数return gcd(u, v >> 1);// 减少较大的变量if (u > v)return gcd((u - v) >> 1, v);return gcd((v - u) >> 1, u);
}
int main()
{int m,n,t1;printf("请输入两个整形数字:");scanf("%d%d",&m,&n);if(m<0||n<0||(m-(int)m)>0||(n-(int)n)>0)     //判断输入两数字是否小于零或为小数{    printf("请重新输入正确整数:");cin.clear();                              //清除错误标记,重新打开输入流cin.sync ();scanf("%d%d",&m,&n);}t1=gcd(m,n);printf("最大公因数为:%d\n",t1);return 0;
}

测试及测试代码与平均运行时间:
测试代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int gcd(int u,int v)
{if (u == 0) return v;if (v == 0) return u;if (~u & 1) {if (v & 1) return gcd(u >> 1, v);else return gcd(u >> 1, v >> 1) << 1;}if (~v & 1) return gcd(u, v >> 1);if (u > v)return gcd((u - v) >> 1, v);return gcd((v - u) >> 1, u);
}
void main()
{int m[5000],n[5000],t1,i;clock_t start,finish;double duration;time_t t=time(NULL);srand(t);for(i=0;i<5000;i++){m[i]=rand()%100;n[i]=rand()%100;}start=clock();for(i=0;i<5000;i++){t1=gcd(m[i],n[i]);printf("%d  %d  %d\n",m[i],n[i],t1);}finish=clock();duration=(double)(finish-start)/5000;       //平均运行时间printf("%f seconds\n",duration);
}

流程图:

求最大公约数的4种常用算法相关推荐

  1. 最大公约数简便算法_求最大公约数的4种算法

    for(z=0; z<10000000; z++) 循环只是为了增加程序的运行时间, 让我们体会算法的时间复杂度. 算法一:短除法 想法,采用短除法找出2个数的所有公约数,将这些公因子相乘,结果 ...

  2. 用java语言求前50个素数_Java求质数的几种常用算法总结

    Java求质数的几种常用算法分析 本文实例讲述了Java求质数的几种常用算法.分享给大家供大家参考,具体如下: 1.根据质数的定义求 质数定义:只能被1或者自身整除的自然数(不包括1),称为质数. 利 ...

  3. 求最大公约数的4种算法(C++)

    求最大公约数的4种算法(C++) 一.实验目的 1.计算两个正整数的最大公约数和最小公倍数,并进行程序的调式与测试. 2.理解四种不同的求最大公约数的方法,学习其思维模式. 3.了解算法的概念.对问题 ...

  4. c语言实现求最大公约数的三种方法

    一.最大公约数 最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也 ...

  5. 求最大公约数的4种方法

    一.最大公约数与最小公倍数 最大公约数,属于数论所探究的内容. 最大公约数可以通过下面的三种方法求出来. 最小公倍数呢,它与最大公约数的乘机为所求数之积. 比如求 x,y的最大公约数和最小公倍数 记住 ...

  6. JavaScript实现求最大公约数 (GCD)的算法(附完整源码)

    JavaScript实现求最大公约数 (GCD)的算法(附完整源码) euclideanAlgorithm.js完整源代码 euclideanAlgorithm.js完整源代码 export defa ...

  7. 用C语言求最大公约数的4种方法

    C语言求最大公约数的四种方法如下: 辗转相除法:通过不断地交换两个数,使较大的数除以较小的数,最后得到的余数即为最大公约数. 更相减损术:通过不断地让两个数减去较小的数,最后得到的结果即为最大公约数. ...

  8. 最大公约数简便算法_求最大公约数的几种算法

    给定两个整数,求出这两个整数的最大公约数是我们从小就接触过的问题,但是我们如何用更简洁的算法来计算呢? 本文中,假定这两个整数是m和n且m>=n>=0.让我们从最简单的算法说起! 一.Co ...

  9. 求最大公约数的四种算法

    一. 题目分析 如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数.几个自然数公有的约数,叫做这几个自然数的公约数.公约数中最大的一个公约数,称为这几个自然数的最大公约数. 根据约数的 ...

  10. JAVA工程师常用算法_算法工程师必须要知道的8种常用算法思想

    算法思想有很多,业界公认的常用算法思想有8种,分别是枚举.递推.递归.分治.贪心.试探法.动态迭代和模拟.当然8种只是一个大概的划分,是一个"仁者见仁.智者见智"的问题. 1.1 ...

最新文章

  1. 浏览器的加载与页面性能优化
  2. VC++的应用程序框架中各类之间的访问方法
  3. eclipse java jdk_设置Eclipse和Java JDK
  4. 【推荐系统】深入理解推荐系统:无需人工特征工程的xDeepFM
  5. 对于一个采用字符数组存放的字符串str,设计一个递归算法StrLength(char *str)求其字符个数(长度)。递归求字符串长度
  6. Ubuntu下安装配置VIM/GVIM(GUI-Vim)
  7. 某易游戏经典吃豆豆动画404页面源码
  8. php伪静态函数,PHP写的U()函数,结合伪静态做seo优化
  9. 永大电梯小键盘服务器显示黑色条杠,永大电梯小键盘操作手顺
  10. C语言,realloc
  11. Java反射原理与Class类(详解)
  12. excel函数提取计算机登录名,excel常用函数怎么提取姓氏?excel常用函数提取姓氏的方法...
  13. opencv raw转rgb_使用OpenCV实现RGB、HSI、CMYK颜色空间的转换
  14. SQL Server Case表达式
  15. day01 pathon基础
  16. wifi模块服务器项目心得,一次关于WiFi 驱动移植的总结复盘
  17. 从github上下载文件,文件夹,整个项目
  18. 内存类型:UDIMM、RDIMM、LRDIMM
  19. AB-PLC之间通讯
  20. 【AUTOSAR】:功能安全(HSM与HOST的配置)

热门文章

  1. WebGIS 瓦片地图引擎实现之——地图瓦片计算
  2. 图片文字怎么合并转发_怎么把图片和文字组合发微信
  3. 让Android 设备通过USB 转RJ45有线网卡上网
  4. (5)树莓派+1个USB有线网卡+1个USB无线网卡做路由器
  5. 固定资产管理软件分析
  6. 使用element插件点击跳转时报错form-item.vue:315 Uncaught (in promise) TypeErelForm.removeField is not a function
  7. Origin科研绘图实战
  8. accept搭配用法_accept的固定搭配及用法
  9. 对数的matlab代码,Matlab的对数
  10. uniapp发行为小程序分享转发功能