作者:无
时间:2019-3-7*
一.题目分析:求最大公约数并比较不同算法耗时情况
**1.**运行最大公约数的常用算法,并添加异常处理模块(如输入非法等)。在基础程序的基础上,可以考虑手动输入所有数字或者利用随机数产生数字,分别加入异常处理模块。
*注:随机数的产生方法
srand()的作用是提供一个种子。然后调用rand(),其格式为int rand(void)。它会根据提供给srand()的种子值返回一个随机数(在0到32767之间),我们可以根据自己的需要通过运算来改变范围。time()函数的作用则是产生一个正整数。此处要注意头文件的声明#include<time.h>
**2.**在此程序中,主要采取四种求最大公约数的算法:辗转相除法,穷举法,更相减损法,stein法.
**3.**最主要的是要考虑如何存储数据的问题,在这里,我采用了二维数组进行数据存储。
**4.**为了使程序优化,在程序中添加了在给定不同规模测试数据的情况下求平均运行时间的函数,这里就用到了时间函数。
*注 计算时间函数clock(): 捕捉从程序开始运行到clock()被调用时所耗费的时间。定义start,end来计算时间差。
clock_t start,end;
Start=clock( );
end=clock(); //结束计时
time1=(double)(end-start)/CLOCKS_PER_SEC;
printf(“耗时%fms\n”,time1);
二.算法构造(具体流程图在visio 文档中)
三.算法实现
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h> //求时间的头文件
#define max 1000 //定义最大组数
int hanshu(int a,int b) //辗转相除法(函数嵌套调用)
{ int temp; //定义整型变量,temp为中间交换数
if(a<b) //通过比较求出两个数中的最大值和最小值
{ temp=a;
a=b;
b=temp;
}
while(b!=0) //通过循环求两数的余数,直到余数为0
{
temp=a%b;
a=b; //变量数值交换
b=temp;
}
return (a); //返回最大公约数到调用函数处
}
int qiong(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 geng(int a,int b)
{
int i=0,temp,x;
while(a%2==0 && b%2==0) //判断a和b能被多少个2整除
{
a/=2;
b/=2;
i+=1;
}
if(a<b) //a保存大的值
{
temp=a;
a=b;
b=temp;
}
while(x)
{
x=a-b; // 以较大的数减较小的数
a=(b>x)?b:x; //所得的差与较小的数比较
b=(b<x)?b:x;
if(b==(a-b))
break;
}
if(i==0)
return b;
else
return (int )pow(2,i)*b;
}
int stein(int a,int b) //stein算法
{ if(a==0)
return b;
if(b==0)
return a;
if(~a&1)
{ if(b&1)
return stein(a>>1,b);
else
return stein(a>>1,b>>1)<<1;
}
if(~b&1)
return stein(a,b>>1);
if(a>b)
return stein((a-b)>>1,b);
return stein((b-a)>>1,a);
}
int main( )
{ int i;
int j,p; //i和j表示二维数组,p表示组数
int m; //通过m表示调用函数的返回值
int num;
int zu[max][2];
clock_t start,end;
double time1; //定义一个double型变量来输出时间
printf("请输入需要设定的组数:\n");
scanf("%d",&p);
if(p>1000)
{ printf("超出范围,请重新输入组数\n");
scanf("%d",&p);
}
srand(time(NULL)); //随机种子
for(i=0;i<p;i++)
{
for(j=0;j<2;j++)
{
zu[i][j]=rand( )%1000; //rand函数求随机数,1000表示求1000以内的随机数
}
}
printf("输出元素\n");
for(i=0;i<p;i++)
{ for(j=0;j<2;j++)
{printf("%d\t",zu[i][j]);
}
}printf("\n");
start=clock(); //开始计时
while(num) //选择方法
{
printf("\n");
printf("***请选择比较方法***:\n");
printf("***1.辗转相除法(函数嵌套调用)***\n");
printf("***2.穷举法***\n");
printf("***3.更相减损法***\n");
printf("***4.stein法***\n");
scanf("%d",&num);
printf("最大公约数为:\n");
for(int e=0;e<p;e++)
{
switch(num)
{case 1:
m=hanshu(zu[e][0],zu[e][1]); //调用相关函数
break;
case 2:
m=qiong(zu[e][0],zu[e][1]);
break;
case 3:
m=geng(zu[e][0],zu[e][1]);
break;
case 4:
m=stein(zu[e][0],zu[e][1]);
break;
}
printf("%d\t",m);
}
end=clock(); //结束计时
time1=(double)(end-start)/CLOCKS_PER_SEC;
printf("耗时%fms\n",time1);
}
return 0;
}
四.异常处理:
1.此处为手动输入的异常处理(由于此处算法都是针对正整数而言,因此当存在负数提示输入不合法)
2.此部分为随机产生数(此处处理主要针对数组的最大容量)
五.调试.测试及运行结果
1.调试:
2.测试:
(1)辗转相除法:
编写代码对函数一进行功能测试,由截图可知,辗转相除法求最大公约数功能可以实现
(2)穷举法:
编写穷举法的函数部分代码,求出最大公约数及消耗时间,结果表明,此功能正常。
(3)更相减损法:
(4)stein法:
以上四种测试结果表明,测试的四部分函数编写无误,并能正确得出相应时间,输出元素部分利用了随机函数,由运行结果可知,随机数的产生部分能够正常运行。二维数组中的数据也能正确的传入函数。
3.运行结果:
(1)测试组数定为五组:
对五组数据用不同的四种方法求最大公约数,并比较耗时。
(2)设定相应的比较组数为10组
以下截图为10组数求最大公约数的四种不同方法
(3)此处设定组数20组
(4)此处设定组数为30组
从不同组数的数据耗时可看出,随着数据的增多,求最大公约数最短耗时为辗转相除法
六.经验归纳
1.通过求最大公约数的程序编写,掌握了基本的四种算法思维,使程序更具优化性。在此处对四种算法选择方面采取了switch语句,方便清晰。
2.利用二维数组存储相应的数据,不会是数据错乱,方便输入数据,方便进行比较和运算。
3.在此次编写程序中我还出现了一个低级错误,就是在多个循环语句中重复使用同一变量,导致报错,因此,在写程序的过程中,要随相关变量进行正确的注释,避免重复。
4.头文件的声明也是最为重要的,也是最容易忽视的。其中需要我们再次掌握的还是随机函数rand()的应用以及计算耗时的函数。srand(time(NULL)); //随机种子