求最大公约数实验报告

求最大公约数实验报告

一. 题目要求
运行最大公约数的常用算法,明确算法的概念和特点,并进行程序的测试,通过对问题的分析,设计合理解决问题的方法。

二. 问题分析
2.1题目分析
计算最大公约数有不同的算法,不同的算法能解决相同的求最大公约数的问题,本程序
中计算最大公约数的算法有辗转相除法、穷举法、更相减损法和stein算法,这四种算法的解题思路不同,时间复杂度不同,其解题效率也不尽相同。

2.2算法思路
先分别用四种算法求出一组m和n的最大公约数,判断四个算法是否都是可行的,然后再添加能产生随机数组的函数,进行多个数组的测试,最后再调用时间函数,分别计算四种算法计算同样的数组所耗费的时间并输出,从而得到最优算法。并进行程序的多次测试,减小实验误差,避免偶然性,从而得到四种算法的平均时间。

三. 模块分析

3.1辗转相除法
⑴ 原理:
用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。设两数为a,b,设其中a做被除数,b做除数,temp为余数。
① 大数放a中,小数放b中;
② 求a÷b的余数temp;
③ 若temp=0,则b为最大公约数;
④ 如果temp!=0,则把b的值给a,temp的值给a;
⑤ 返回第二步

⑶时间复杂度分析:
辗转相除法在最坏情况下所需的模运算次数和输入的a和b的大小关系如下:
设a>b>=1(若a<b我们只需多做一次模运算, 若b=0或a=b模运算的次数分别为0和1), 构造数列{un}: u0=a, u1=b, uk=uk-2 mod uk-1(k>=2), 显然, 若算法需要n次模运算, 则有un=gcd(a, b), un+1=0. 我们比较数列{un}和菲波那契数列{Fn}, F0=1<=un, F1=1<=un-1, 又因为由uk mod uk+1=uk+2, 可得uk>=uk+1+uk+2, 由数学归纳法容易得到uk>=Fn-k, 于是得到a=u0>=Fn, b=u0>=Fn-1. 也就是说如果欧几里得算法需要做n次模运算, 则b必定不小于Fn-1. 换句话说, 若 b<Fn-1, 则算法所需模运算的次数必定小于n. 根据菲波那契数列的性质, 有Fn-1>(1.618)n/sqrt(5), 即b>(1.618)n/sqrt(5), 所以模运算的次数为O(lgb).故辗转相除法的时间复杂度为O(lgb)。

(4)代码
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);
}

3.2穷举法
(1)原理
穷举法的基本思想是根据题目的部分条件确定答案的大致范围,并在此范围内对所有可能的情况逐一验证,直到全部情况验证完毕。若某个情况验证符合题目的全部条件,则为本问题的一个解;若全部情况验证后都不符合题目的全部条件,则本题无解。穷举法也称为枚举法。对于两个正整数a,b,如果能在区间【a,0】或【b,0】内找到一个整数temp能同时被a,b所整除,则temp即为最大公约数。

(3)时间复杂度
穷举法的时间复杂度为O(n)
(4)代码
int divisor2(int a,int b)//穷举法
{
int temp;
temp=(a>b)?b:a;
while(temp>0)
{
if(a%temp0&&b%temp0)
break;
temp–;
}
return(temp);
}

3.3更相减损法
(1)原理:
如果需要对分数进行约分,可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。

(3)时间复杂度
在更相减损法在计算过程中,如果遇到一个数很大,另一个数比较小的情况,可能要进行很多次减法才能达到一次除法的效果,从而使得算法的时间复杂度退化为O(N),其中N是原先的两个数中较大的一个。

(4)代码
int gcd(int m,int n)//更相减损法
{
int temp,i=0,x;
while(m%20&&n%20)
{
m/=2;
n/=2;
i+=1;
}
if(m<n)
{
temp=m;
m=n;
n=temp;
}
while(x)
{
x=m-n;
m=(n>x)?n:x;
n=(n<x)?n:x;
if(nm-n)
break;
}
if(i
0)
return n;
else
return(int)2in;
}

3.4stein算法
(1)原理
Stein算法是一种计算两个数最大公约数的算法,是针对欧几里德算法在对大整数进行运算时,需要试商导致增加运算时间的缺陷而提出的改进算法。
1、如果An=Bn,那么An(或Bn)Cn是最大公约数,算法结束
2、如果An=0,Bn是最大公约数,算法结束
3、如果Bn=0,An是最大公约数,算法结束
4、设置A1=A、B1=B和C1=1
5、如果An和Bn都是偶数,则An+1=An/2,Bn+1=Bn/2,Cn+1=Cn
2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可)
6、如果An是偶数,Bn不是偶数,则An+1=An/2,Bn+1=Bn,Cn+1=Cn(很显然啦,2不是奇数的约数)
7、如果Bn是偶数,An不是偶数,则Bn+1=Bn/2,An+1=An,Cn+1=Cn(很显然啦,2不是奇数的约数)
8、如果An和Bn都不是偶数,则An+1=|An-Bn|/2,Bn+1=min(An,Bn),Cn+1=Cn
9、n加1,转1

(3)时间复杂度
欧几里德算法每次迭代中最恶劣的情况是,a=2b-1,这样,迭代后,r=b-1。如果a小于2^N,这样大约需要4N次迭代。而Stein算法,每次迭代后,显然AN+1BN+1≤ ANBN/2,最大迭代次数也不超过4N次。也就是说,迭代次数几乎是相等的。但是,需要注意的是,对于大素数,试商法将使每次迭代都更复杂,因此对于大素数,Stein算法将更有优势。

(4)代码
int Stein(unsigned int x,unsigned int y) //stein算法
{
int factor=0;
int temp;
if(x<y)
{
return 0;
}
while(x!=y)
{
if(x&0X1)
{
if(y&0x1)
{
y=(x-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);
}

四. 总结
开始在程序算法设计中也遇到了很多的问题,比如随机数组的使用问题,开始调试时
总是有问题,通过查阅资料,重新对for循环的使用,使随机函数的调用能产生自定义的随机数。其次,在四种算法的时间输出总是有问题,有时候时间输出总是很小甚至为0,通过对程序的反复检查,才发现是函数传参有问题,最后通过修改一一解决了问题。
通过对算法的比较,发现计算两个数的最大公约数,穷举法所花费时间最多,辗转相除法平均花费时间较少一些。在实验过程中,不同的算法解题思路不同,运行效率和时间复杂度也不尽相同,我们在以后的编程学习中,要通过对算法的比较分析,运用最优算法来解决问题,减少算法时间的过多浪费。
通过此次的上机实验题,让我对这四种求最大公约数的算法有了更加深入的理解,同时也增强了我的动手能力与实践能力,让我对编程也提高了一定的兴趣。我相信在今后的学习中,我将会收获更多。

猜你喜欢

转载自blog.csdn.net/qq_43815240/article/details/88622603