一、题目分析:
我们有很多计算两个正整数的最大公约数的算法,比如辗转相除法,穷举法,更相减损法,Stein算法等,而我们就是要寻找一个解决问题的最佳方法,所以,我们今天用以上四种方法同时求不同规模测试数据的情况下的平均运行时间,从而比较四种算法的时间优越性。
二、算法构造(用流程图表示)
1、辗转相除法:
2、穷举法(用数学定义):
3、更相减损法:
4、Stein算法
二、算法实现
/*计算四种不同求最大公约数的算法平均运行时间*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
//辗转相除法
int divisor1 (int a,int b) /*自定义函数求两数的最大公约数*/
{
int temp;
if(a<b) /*通过比较求出两个数中的最大值和最小值*/
{ temp=a;a=b;b=temp;} /*设置中间变量进行两数交换*/
while(b!=0) /*通过循环求两数的余数,直到余数为0*/
{
temp=a%b;
a=b; /*变量数值交换*/
b=temp;
}
return (a); /*返回最大公约数到调用函数处*/
}
//穷举法
int divisor2 (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 gcd(int m,int n)
{
int i=0,temp,x;
if(m==n)
return m;
while(m%2==0 && n%2==0) //判断m和n能被多少个2整除
{
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;
}
//Stein算法
int Stein( unsigned int x,unsigned int 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)
{
if(y&0x1)
{
y=(x-y)>>1;//y的值右移1
x-=y;
}
else
{
y>>=1;
}
}
else
{
if(y&0x1)
{
x>>=1;
if(x<y)
{
temp=x;
x=y;
y=temp;
}
}
else
{
x>>=1;
y>>=1;
++factor;
}
}
}
return(x<<factor);
}
int main()
{
int b=1,t;
int i,j;
int a[20]; //生成随机数,并把随机数放入一维数组里面,并打印出来,以便对照
for(i=0;i<20;i++)
{
a[i]=rand()%50 + 1; //随机数的范围是1到51
printf("%d ",a[i]); //打印出来数组
}
printf("\n");
int c[20];
for(i=0;i<20;i++)
{
c[i]=rand()%50 + 1;
printf("%d ",c[i]);
}
printf("\n");
for(b=1;b<=4;b++) //便于一次运行就可以把所有方法都用上
{
printf("输入你想选择的方法(辗转相减法为1,穷举法为2,更相减损法为3,Stein为4):");
scanf("%d",&t) ;
clock_t start,finish;
double duration; //用于测量一个时间的持续时间
start= clock(); //开启计时器
for(i=0;i<20;i++) //每组数据开始遍历
{
switch(t) //选择结构
{
case 1:printf("辗转相减法所得最大公约数为:%d\n",divisor1(a[i],c[i]));break;
case 2:printf("穷举法所得最大公约数为:%d\n",divisor2(a[i],c[i]));break;
case 3:printf("更相减损法所得最大公约数为:%d\n",gcd(a[i],c[i]));break;
case 4:printf("Stein算法所得最大公约数为:%d\n",Stein(a[i],c[i]));break;
}
}
finish=clock(); //关闭计时器
duration=(double)(finish-start)/CLOCKS_PER_SEC;
printf("time=%lf seconds\n",duration);
}
system("pause");
return 0;
}
四、调试、测试及运行结果
1、调试:
这次运行结果出现了一些问题,就是只出现运行时间,没有参加最大公约数的运算,最后发现原来是循环初始条件的问题,初始条件应该为i=0。
2、测试
3、运行结果:
3-1(5组数据):
3-1-1:数据截图:
3-1-2:最大公约数还有运行时间截图
比较:辗转相除法=穷举法>更相减损法>Stein算法
3-2 (10组数据)
3-2-1 数据截图
3-2-2 辗转相除法运行结果:
3-2-3穷举法运行结果:
3-2-4 更相减损法运行结果:
3-2-5 Stein算法运行结果
比较:辗转相除法<穷举法<更相减损法<Stein算法
3-3 (20组数据)
3-3-1数据截图
3-3-2 辗转相除法的运行结果
3-3-3穷举法的运行结果
3-3-4 更相减损法的运行结果
3-3-5 Stein算法的运行结果
比较:Stein<辗转相除法< 穷举法 <更相减损法
3-4.测试100组数据时:Stein算法0.117s<更相减损法0.312s<辗转相除法0.356s<穷举法0.637s
3-5.测试1000组数据时:Stein算法0.691s<更相减损法1.322s<穷举法1.656s<辗转相除法2.015s
(大规模数据不太好截图,所以在此略去)
总结:以上可知,大规模数据时用Stein算法和更相减损法可以更快捷,小规模数据时可用辗转相除法和穷举法。
五、经验归纳
这次的上机实验,让我复习了辗转相除法,穷举法求最大公约数的算法实现,也让我学习到了更相减损法和Stein算法求最大公约数的方法,不得不说,Stein算法真的是这四种算法中最难的,是真的难理解。。。在这次实验中,我把四种算法组合到了一个源代码中,也设置了clock函数再加上switch选择语句去求各个算法的总运行时间,因为要比较不同规模测试数据下四种算法运行时间,我觉得一组组地输入数字很麻烦,并且如果要输入很多组数据的话也难以实现,所以就想到了用随机数构造数组来实现不同规模下的算法运行时间。首先说时间部分,我之前是把时间clock加在各个算法的函数体里,妄想每算一次输出一次时间,但是这每计算一次打印一次时间运行起来看着也头疼,而且每个函数都有返回值,在我的多次试验中发现这想法根本行不通,就去和同学们讨论,发现switch的选择语句是个好东西,所以时间问题就解决啦。第二是数组,本来是想随机数构造二维数组的,但是因为能力问题,指针、分配空间的部分没有掌握好,所以折腾了很久也没能实现,最后灵光一现,使用了两个一维数组。虽然生成的是伪随机数,但是看了一个算法的运行时间后在重新运行也麻烦,所以我又添加了一个for循环,让我们可以运行一次程序就把四个算法的运行时间全看到,而数据规模改变时就修改程序里的数组a[]b[]中括号里值就好。
这次实验还不错,虽然过程很曲折,但是运行成功的时候真的很开心,所以我一定会继续努力哒!