作者:A.y.
日期:2019.3.7
运行环境:Visual C++ 6.0
问题描述:运行最大公约数的常用算法(辗转相除法、穷举法、更相减损法、Stein算法),并进行程序的调式与测试。
算法设计思路:
1.辗转相除法:
①函数嵌套调用:
display1()函数(求最大公约数):
令进行运算的两个数的大的数为a,小的数为
b,让a对b进行求余数temp;
若temp=0,则最大公约数为b,返回b的值,否则将b赋值给a,将temp赋值给b,再重复上述操作直到temp=0。
display2()函数(求最小公倍数):
先调用display1()函数求最大公约数,再利用两数相乘除以最大公约数即可得到最小公倍数。
②函数的递归调用:
dispaly()函数(求最大公约数):
令进行运算的两个数的大的数为a,小的数为
b,让a对b进行求余数temp;
若temp=0,返回最大公约数b,否则继续调用display()函数进行求余判断,直至temp为0。
2.穷举法:
display1()函数(求最大公约数):
令进行运算的两数中的小的数为b,大的数为a,令变量temp=b,若a%temp== 0且b%temp== 0,返回最大公约数temp,否则temp自减,再进行上述判断。
display2()函数(求最小公倍数):
令进行运算的两数中的小的数为b,大的数为a,令变量temp=a,若temp%b== 0且temp%a== 0,返回最小公倍数temp,否则temp=temp+a,再进行上述判断。
3.更相减损法:
display()函数(求最大公倍数):
令进行运算的两数中的小的数为b,大的数为a,若两数都是偶数,则两数同时除以2,同时i++(i用来记录该步骤执行次数,初始值为0),再进行偶数判断,否则进行判断b= =a-b,若成立则返回最大公约数b,否则将max(b,a-b)赋值给a,将min(b,b-b)赋值给b再进行上述判断。
4.Stein算法
display()函数(求最大公约数):
先将进行运算的两数a,b进行判断,若a== b,则返回最大公约数为a,否则进行奇偶性判断,若a,b都为偶数,则a,b同时除以2再进行a== b判断;若a为偶数,b为奇数,则a除以2再进行a== b判断;若a为奇数,b为偶数,则b除以2再进行a==b判断;若a,b都为奇数,则a=(a+b)/2,b=fabs(a-b)/2;进行上述操作直至a=b。
算法设计流程图:
1.辗转相除法:
2.穷举法:
3.更相减损法:
4.Stein算法:
代码实现:
1.辗转相除法(非递归)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int display1(int a,int b) /*计算最大公约数*/
{
int temp;
if(a<b)
{
temp=a;
a=b;
b=temp;
}
while(a%b!=0) /*利用循环直至余数为0,此时b为最大公约数*/
{
temp=a%b;
a=b;
b=temp;
}
return b;
}
int display2(int a,int b) /*计算最小公倍数*/
{
return(a*b/display1(a,b)); /*嵌套调用函数display1()*/
}
int main()
{
clock_t begin,end; /*变量begin和end表示开始时间和终止时间*/
double time; /*time变量表示程序运行时间(秒制)*/
int m,n;
int temp1,temp2;
int a[2][5000];
for(n=0;n<2;n++)
for(m=0;m<5000;m++)
a[n][m]=rand();
begin=clock(); /*获得程序开始时间*/
for(m=0;m<5000;m++)
{
temp1=display1(a[0][m],a[1][m]);
temp2=display2(a[0][m],a[1][m]);
printf("\t最大公约数为:%d\t",temp1);
printf("最小公倍数为:%d\n",temp2);
}
end=clock(); /*获得程序结束时间*/
time=(double)(end-begin)/1000;
printf("\n\t算法运行时间:%0.3lf秒\n",time);
return 0;
}
2.辗转相除法(递归)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int display(int a,int b) /*display()函数用来求最大公约数*/
{
int temp;
if(a<b)
{
temp=a;
a=b;
b=temp;
}
if(a%b==0) /*求余判断,若余数为0,则最大公约数为b,否则调用自身函数继续进行求余判断*/
return b;
else
return display(b,a%b);
}
int main()
{
clock_t begin,end; /*变量begin和end表示开始时间和终止时间*/
double time; /*time变量表示程序运行时间(秒制)*/
int m,n;
int temp;
int a[2][5000];
for(n=0;n<2;n++)
for(m=0;m<5000;m++)
a[n][m]=rand();
begin=clock(); /*获得程序开始时间*/
for(m=0;m<5000;m++)
{
temp=display(a[0][m],a[1][m]);
printf("\t最大公约数为:%d\t",temp);
printf("最小公倍数为:%d\n",a[0][m]*a[1][m]/temp);
}
end=clock(); /*获得程序结束时间*/
time=(double)(end-begin)/1000;
printf("\n\t算法运行时间:%0.3lf秒\n",time);
return 0;
}
3.穷举法
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int display1(int a,int b) /*计算最大公约数*/
{
int temp;
if(a<b)
{
temp=a;
a=b;
b=temp;
}
for(temp=b;temp>0;temp--) /*利用穷举法计算最大公约数*/
{
if(a%temp==0&&b%temp==0)
return temp;
}
return (1);
}
int display2(int a,int b) /*计算最小公倍数*/
{
int i=1;
if(a>b) /*利用穷举法计算最小公倍数*/
{
while(i*a%b!=0)
i++;
return a*i;
}
else
{
while(i*b%a!=0)
i++;
return b*i;
}
}
int main()
{
clock_t begin,end; /*变量begin和end表示开始时间和终止时间*/
double time; /*time变量表示程序运行时间(秒制)*/
int m,n;
int temp1,temp2;
int a[2][5000];
for(n=0;n<2;n++)
for(m=0;m<5000;m++)
a[n][m]=rand();
begin=clock(); /*获得程序开始时间*/
for(m=0;m<5000;m++)
{
temp1=display1(a[0][m],a[1][m]);
temp2=display2(a[0][m],a[1][m]);
printf("\t最大公约数为:%d\t",temp1);
printf("最小公倍数为:%d\n",temp2);
}
end=clock(); /*获得程序结束时间*/
time=(double)(end-begin)/1000;
printf("\n\t算法运行时间:%0.3lf秒\n",time);
return 0;
}
4.更相减损法
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
int display(int a,int b) /*计算最大公倍数*/
{
int temp,i=0;
while(a%2==0&&b%2==0) /*若两个数都为偶数则同时除以2,同时记录该操作次数*/
{
a=a/2;
b=b/2;
i++;
}
if(a<b)
{
temp=a;
a=b;
b=temp;
}
while(a!=2*b) /*如果a==a-b,则跳出循环记录a的值,否则a=b,b=a-b再进行判断*/
{
if(b>(a-b))
{
temp=a-b;
a=b;
b=temp;
}
else
a=a-b;
}
while(i--)
b=b*2;
return b; /*返回最大公约数b*/
}
int main()
{
clock_t begin,end; /*变量begin和end表示开始时间和终止时间*/
double time; /*time变量表示程序运行时间(秒制)*/
int m,n;
int temp;
int a[2][5000];
for(n=0;n<2;n++)
for(m=0;m<5000;m++)
a[n][m]=rand();
begin=clock(); /*获得程序开始时间*/
for(m=0;m<5000;m++)
{
temp=display(a[0][m],a[1][m]);
printf("\t最大公约数为:%d\t",temp);
printf("最小公倍数为:%d\n",a[0][m]*a[1][m]/temp);
}
end=clock(); /*获得程序结束时间*/
time=(double)(end-begin)/1000;
printf("\n\t算法运行时间:%0.3lf秒\n",time);
return 0;
}
5.Stein算法
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
int display(int a,int b)
{
int temp,i=0;
while(a!=b)
{
if(a%2==0)
{
a>>=1;
if(b%2==0)
{
b>>=1;
i++;
}
}
else
{
if(b%2==0)
b>>=1;
else
{
temp=a;
a=(a+b)/2;
b=(int)(fabs(a-b));
}
}
}
return (int)(a*pow(2,i));
}
int main()
{
clock_t begin,end; /*变量begin和end表示开始时间和终止时间*/
double time; /*time变量表示程序运行时间(秒制)*/
int m,n;
int temp;
int a[2][5000];
for(n=0;n<2;n++)
for(m=0;m<5000;m++)
a[n][m]=rand();
begin=clock(); /*获得程序开始时间*/
for(m=0;m<5000;m++)
{
temp=display(a[0][m],a[1][m]);
printf("\t最大公约数为:%d\t",temp);
printf("最小公倍数为:%d\n",a[0][m]*a[1][m]/temp);
}
end=clock(); /*获得程序结束时间*/
time=(double)(end-begin)/1000;
printf("\n\t算法运行时间:%0.3lf秒\n",time);
return 0;
}
调试截图:
若两数均为奇数下一次操作a应为两数相加除以2,b为两数相减除以2,但该处出现了问题,原因是当执行a=(a+b)/2后再执行b=fabs(a-b)/2时,a的值已经发生了改变,所以产生了错误。
错误代码:
temp=a;
a=(a+b)/2;
b=(int)(fabs(a-b)/2);
修改后:
temp=a;
a=(a+b)/2;
b=(int)(fabs(a-b));
其余算法测试均无错误。
四、测试截图:
1.辗转相除法(非递归):
dispaly1()函数测试:
测试代码:
测试截图:
辗转相除法(递归):
display()函数测试:
测试代码:
测试截图:
2.穷举法:
display1()函数测试:
测试代码:
测试截图:
display2()函数测试:
测试代码:
测试截图:
3.更相减损法:
display()函数测试:
测试代码:
测试截图:
4.Stein算法:
display()函数测试:
测试代码:
测试截图:
四种算法比较:
5000组数据各个算法平均运行时间分析(测试五次取平均值):
①.辗转相除法(非递归和递归):2.3052s 、2.3642s
②.穷举法:2.5926s
③.更相减损法:2.4756s
④.Stein算法:2.434s
上机心得:
对c语言求最大公约数和最小公倍数的四个基本算法原理有了更深入的了解,同时掌握了time.h头文件中基本的时间函数。在本次实验中,还对数组的随机数赋值函数rand()有了了解。