第二次程序作业

一.题目分析
题目要求:求出任意俩个数的最大公约数和最小公倍数
题目分析:
(1).辗转相除法:
1.将大数给a,小数给b;
2.求a%b的余数;
3.若余数的值为0,则b就是最大公约数;
4.如果余数的值不为0,把b的值给a,余数的值给b;
5.返回第二步;
6.用最开始a与b的乘积除以最大公约数的值就是最小公倍 数了。
(2).穷举法:
1.将大数给a,小数给b;
2.利用循环,从b开始递减,同时能被a,b整除的数就是最 大公约数。
3.利用循环,从a开始递增,能同时整除a,b的数就是最大公倍数
(3)更相减损法:
1.给变量i初始化为1。
2.如果a,b都是偶数的话,a,b同时除以2,i++
3如果a,b都是偶数的话,重复第二步
4.将a与b做差,将b与差中较大的给a,小的给b;
5如果b与a-b的值不相等,重复第四步
5.将2的i次方乘以b的值就是最大公约数
6. 用最开始a与b的乘积除以最大公约数的值就是最小公倍 数了。
(4)Stein算法
1.将a,b中较大的数给a,小的给b
2.如果a,b都是偶数,a,b都除以2
3.如果a.b中一个是偶数,一个是奇数。偶数除以2,奇数不 变
4.如果a、b都是奇数,a=(a+b)/2,b=(a-b)/2
5.在执行完2、3、4的每一步完,如果a=b,就直接结束,重复执行第2、3、4步.

二.算法构造
1.辗转相除法的流程图
在这里插入图片描述
2.穷举法的流程图
在这里插入图片描述
3.更相相减术流程图
在这里插入图片描述
4.Stein算法流程图
在这里插入图片描述

三.算法实现
程序源代码:
package count;
import java.util.Scanner;//导包
public class GCD //创建一个求最大公约数和最小公倍数的类
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);//创建键盘输入对象
int[] data=new int[20];//定义俩组长度为20的数组用来存放输入的20组数据
int[] data1=new int[20];
int i=0;
System.out.println(“请依次输入20组数据”);
for(i=0;i<20;i++)
{
System.out.println(“第”+(i+1)+“组数据”);
System.out.print(“请输入第一个数据:”);//获取数据
data[i]=sc.nextInt();
System.out.print(“请输入第二个数据:”);//获取数据
data1[i]=sc.nextInt();
}
for(i=0;i<20;i++)//先将每一组数据中较大的放进data[i]中,较小的放进data1[i]中
if(data[i]<data1[i])
{
int temp=data[i];
data[i]=data1[i];
data1[i]=temp;
}
long start1=System.nanoTime(); //获取开始时间
for(i=0;i<20;i++)
firstWay(data[i],data1[i]); //测试的代码段
long end1=System.nanoTime(); //获取结束时间
System.out.println("第一种方法运行时间: "+(end1-start1)+“ns”);
long start2=System.nanoTime(); //获取开始时间
for(i=0;i<20;i++)
secondWay(data[i],data1[i]); //测试的代码段
long end2=System.nanoTime(); //获取结束时间
System.out.println("第二种方法运行时间: "+(end2-start2)+“ns”);
long start3=System.nanoTime(); //获取开始时间
for(i=0;i<20;i++)
thirdWay(data[i],data1[i]); //测试的代码段
long end3=System.nanoTime(); //获取结束时间
System.out.println("第三种方法运行时间: "+(end3-start3)+“ns”);
long start4=System.nanoTime(); //获取开始时间
for(i=0;i<20;i++)
fourthWay(data[i],data1[i]); //测试的代码段
long end4=System.nanoTime(); //获取结束时间
System.out.println("第四种方法运行时间: "+(end4-start4)+“ns”);
}
public static void firstWay(int x,int y)//利用嵌套的方法求出最大公约数和最小公倍数

	{
			
		int max=gCD(x,y);//调用gCD方法求最大公约数
		System.out.println("1最大公约数为:"+max);
		int min=lCM(x,y,max);//调用LCM方法求最大公倍数
		System.out.println("1最小公倍数为:"+min);
	}
		public static int gCD(int a,int b)
		{
			int c=0;
			if(a%b==0)//证明b本身就是a的一个公约数,所以也是俩个的最大公约数
				return b;
			else
			{
				c=a%b;
				a=b;//将b的值给a,余数的值给b
				b=c;
				return gCD(a,b);//使用递归
			}
		}
		public static int lCM(int a,int b,int c)
		{
			return(a*b)/c;//将a*b的值除以c就是最小公倍数
		}
		public static void secondWay(int a,int b)//.采用穷举法求出最大公约数和最小公倍数
		{
			int i=0;
			int max=0,min=0;
			for(i=b;i>0;i--)//从俩个数中最小的数开始最递减循环
			{
				if((a%i==0)&&(b%i==0))//如果在小于最小数的范围之内找到一个可以同时被这俩个数整除的值将是最大公约数
					{
					max=i;break;//将最大公约数的值记下,结束循环
					}
			}
			for(i=a;i<10000000;i++)//从俩个数中较大的数开始最递增循环
			{
				if((i%a==0)&&(i%b==0))//如果在大于最大数的范围之内找到一个可以同时整除这俩个数的值将是最大公约数
				{
					min=i;break;//记下最大公约数,结束循环
				}
			}
			System.out.println("2最大公约数为:"+max);
			System.out.println("2最小公倍数为:"+min);
		
		}
		public static void thirdWay(int a,int b)//利用更相减损法求出最大公约数和最小公倍数
		{
			int i=0,temp=0,x=1;
			int sum=1;
			int min=a*b;
			while((a%2==0)&&(b%2==0))
			{
				a/=2;//如果这俩个数都是偶数的话,同时除以2,然后i++
				b/=2;
				i++;
			}
			while(x==1)//然后进入一个while循环
			{
				temp=a-b;//将a与b做差
				if(temp>b)//如果差的值大于b,将俩个的值互换
				{
					int leap=0;
					leap=temp;
					temp=b;
					b=leap;
				}
				a=b;//然后将b的值给a,差的值给b
				b=temp;
				if(b==(a-b))//直到差等于被减数,结束循环
					break;
			}
			int j=0;
			for(j=0;j<i;j++)//此时最大公约数就是2的i次方的值乘以b
				sum*=2;
			int max=sum*b;
			System.out.println("3最大公约数为:"+max);
			min=min/max;
			System.out.println("3最大公倍数为:"+min);
		}
		public static void fourthWay(int a,int b)//利用Stein 算法求出最大公约数和最小公倍数
		{
			int max;
			int min=a*b;
			max=Stein(a,b);//调用Stein的方法求出最小公约数
			System.out.println("4最大公约数为:"+max);
			min=min/max;
			System.out.println("4最小公倍数为:"+min);		
		}
		public static int Stein(int a, int b)	//stein算法--递归实现
		{
			if (a < b)//将a,b中将的数大的给a,小的给b
			{
				int temp=0;
				temp=a;
				a=b;
				b=temp;
			}
			if (b == 0)
				return a;
			if ((a & 1) == 0 && (b & 1) == 0)	//a,b同时为偶数
				return Stein(a >> 1, b >> 1) << 1;	
			else if ((a & 1) == 0 && (b & 1) != 0)	//a为偶数,b为奇数
				return Stein(a >> 1, b);	
			else if ((a & 1) != 0 && (b & 1) == 0)	//a为奇数,b为偶数
				return Stein(a, b >> 1);	
			else
				return Stein(a - b, b);
		}

		}

调试:
一开始计算程序运行的方法是System.currentTimeMillis(),但是由于这种方法计算出来的时间单位都是ms,所以每一种程序运行的时间都很短,甚至有些时间是0 ,为了更精确的计算出程序运行的时间,采用System.nanoTime();方法求出程序运行的时间

运行及结果:
需要自己手动输入20组数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第一种方法运行的时间为1224204ns
由于数据较多,不展示第二、三、四种方法的运行结果,只展示运算时间,便于比较四种方法的时间复杂度
在这里插入图片描述

第二种方法运行的时间为7085533ns
在这里插入图片描述

第三种方法运行的结果为3324305ns
在这里插入图片描述

第四种方法运行的结果为3323305ns
单从第一次的结果来看:更相减损法和Stein算法所用的时间远远短于辗转相除法和穷举法的时间。
为了更准确的比较这四种算法运行时间的快慢,再取4次20组不同的数据进行计算,将每一种方法所得的时间求平均值,结果如下:
方法 辗转相除法 穷举法 更相减损法 Stein法
平均时间/10(6)ns 13.2 8.1 3.8 3.8

由表可知,第一种方法的时间是第三种和第四种方法的时间的4倍,第二种方法的时间是第三种和第四种方法的时间的2倍。推荐使用更相减损法和Stein算法。
五。经验归纳
1.在看到题目以后,不要忙的就取写程序,应该先好好的思考一下算法的各个步骤,然后再随便拿一些数据在纸上进行验算,判断自己的思路是否正确。最后在开始写程序。这样不但会节省时间,而且会减少程序的一些错误。
2.在调用时间函数的时候,先应该大体估算程序要运行的时间,然后调用合适的函数,避免出现太大或者太小的情况
3.写程序的过程中应该及时的加一些注释,不然过一会很可能出现忘记程序是如何运行的了。

猜你喜欢

转载自blog.csdn.net/weixin_44382383/article/details/88359187
今日推荐