运行最大公约数的常用算法,并进行程序的调式与测试。 使用辗转相除法(嵌套,递归)、穷举法、更相损减法、Stein等算法并进行算法时间性能测试。

运行最大公约数的常用算法,并进行程序的调式与测试。
使用辗转相除法(嵌套,递归)、穷举法、更相损减法、Stein等算法并进行算法时间性能测试。
1、辗转相除法:
(1)嵌套:其算法过程为: 前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数
1、大数放a中、小数放b中;
2、求a/b的余数;
3、若temp=0则b为最大公约数;
4、如果temp!=0则把b的值给a、temp的值给b。

#include "pch.h"
#include <iostream>
using namespace std;

int zdgys(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;
}
int zxgbs(int a, int b) {
	int zdgbs(int a, int b);
	int temp;
	temp = zdgys(a, b);
	return (a*b / temp);
}
int main()
{
	int a, b;
	printf("请输入a的值\n");
	scanf_s("%d", &a);
	printf("请输入b的值\n");
	scanf_s("%d", &b);
	cout << "最大公约数为:" << zdgys(a, b) << endl;
	cout << "最小公倍数为:" << zxgbs(a, b) << endl;
}

(2)递归:
其算法步骤为:首先定义一个求余数函数digui(a,b),之后根据余数完成不同操作(若余数为0则返回b的值;若余数不为0则返回函数digui(b,a%b)进行函数重复调用),则最终返回值即为a,b两数最大公约数。

#include "pch.h"
#include <iostream>
using namespace std;
int digui(int a, int b) {
    a = (a > b) ? a : b;
	if (a % b == 0)
		return b;
	else return (b, a%b);
}
int main()
{
	int a, b;
	printf("请输入a值\n");
		scanf_s("%d", &a);
	printf("请输入b值\n");
		scanf_s("%d", &b);
	cout << "最大公约数为:" << digui(a, b) << endl;
	cout << "最小公倍数为:" << (a * b) / digui(a, b) << endl;
}

2、穷举法:
(1)穷举法1:
对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。

#include "pch.h"
#include <iostream>
using namespace std;
int zdgys(int a,int  b) {
	int temp;
	temp=a <b ? a : b;
	while (temp > 0) {
		if (a%temp == 0 && b%temp == 0)
			return temp;
		else temp--;
	}
}
int main()
{
	int a, b;
	printf("请输入a值:");
	scanf_s("%d", &a);
	printf("请输入b值:");
	scanf_s("%d", &b);
	cout << "最大公约数为:" << zdgys(a, b) << endl;
}

(2)穷举法2:
对两个正整数a,b,如果若干个a之和或b之和能被b所整除或能被a所整除,则该和数即为所求的最小公倍数。

#include "pch.h"
#include <iostream>
using namespace std;
int zxgbs(int a,int b) {
	int n,temp;
	temp = a > b ? a : b;
	while (1) {
		if ((temp)%b == 0)
			break;
		temp = temp + a;
	}
	return(temp);
}
int main()
{
	int a, b;
	printf("请输入a值:");
	scanf_s("%d", &a);
	printf("请输入b值:");
	scanf_s("%d", &b);
	cout << "最小公倍数为:" << zxgbs(a, b) << endl;
}

3、更相减损法:
更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。

#include "pch.h"
#include <iostream>
using namespace std;
int fhbs(int a, int b)     //定义返回a和b的除2次数
{
	int i = 0;
	while (a % 2 == 0 && b % 2 == 0) {
		a = a / 2;
		b = b / 2;
		i++;
	}
	if (i == 0)
		return(1);
	else
		return(i);
}
int fhds(int a, int b)     //定义返回等数函数
{
	int m, n, t;
	m = (a > b) ? a : b;
	n = (a < b) ? a : b;
	while (1)
	{
		t = m - n;
		if (t > n) {
			m = t;
			n = n;
		}
		else {
			m = n;
			n = t;
		}
		if (n == (m - n))
			break;
	}
	if (n == 0)
		return 1;
	else
		return n;
}
int main()
{
	int a, b;
	printf("请输入a值:");
	scanf_s("%d", &a);
	printf("请输入b值:");
	scanf_s("%d", &b);
	cout << "最大公约数为:" << fhbs(a,b) * fhds(a, b) << endl;
}

4、Stein算法:
Stein算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。来研究一下最大公约数的性质,发现有 gcd( kx,ky ) = kgcd( x,y ) 这么一个非常好的性质。试取 k=2,则有 gcd( 2x,2y ) = 2 * gcd( x,y )。很快联想到将两个偶数化小的方法。那么一奇一个偶以及两个奇数的情况如何化小呢?
先来看看一奇一偶的情况: 设有2x和y两个数,其中y为奇数。因为y的所有约数都是奇数,所以 a = gcd( 2x,y ) 是奇数。根据2x是个偶数不难联想到,a应该是x的约数。我们来证明一下:(2x)%a=0,设2x=n
a,因为a是奇数,2x是偶数,则必有n是偶数。又因为 x=(n/2)*a,所以 x%a=0,即a是x的约数。因为a也是y的约数,所以a是x和y的公约数,有 gcd( 2x,y ) <= gcd( x,y )。因为gcd( x,y )明显是2x和y的公约数,又有gcd( x,y ) <= gcd( 2x,y ),所以 gcd( 2x,y ) = gcd( x,y )。至此,我们得出了一奇一偶时化小的方法。
再来看看两个奇数的情况:设有两个奇数x和y,不妨设x>y,注意到x+y和x-y是两个偶数,则有 gcd( x+y,x-y ) = 2 * gcd( (x+y)/2,(x-y)/2 ),那么 gcd( x,y ) 与 gcd( x+y,x-y ) 以及 gcd( (x+y)/2,(x-y)/2 ) 之间是不是有某种联系呢?为了方便设 m=(x+y)/2 ,n=(x-y)/2 ,容易发现 m+n=x ,m-n=y 。设 a = gcd( m,n ),则 m%a=0,n%a=0 ,所以 (m+n)%a=0,(m-n)%a=0 ,即 x%a=0 ,y%a=0 ,所以a是x和y的公约数,有 gcd( m,n )<= gcd(x,y)。再设 b = gcd( x,y )肯定为奇数,则 x%b=0,y%b=0 ,所以 (x+y)%b=0 ,(x-y)%b=0 ,又因为x+y和x-y都是偶数,跟前面一奇一偶时证明a是x的约数的方法相同,有 ((x+y)/2)%b=0,((x-y)/2)%b=0 ,即 m%b=0 ,n%b=0 ,所以b是m和n的公约数,有 gcd( x,y ) <= gcd( m,n )。所以 gcd( x,y ) = gcd( m,n ) = gcd( (x+y)/2,(x-y)/2 )。
整理一下,对两个正整数 x>y :
1.均为偶数 gcd( x,y ) =2gcd( x/2,y/2 );
2.均为奇数 gcd( x,y ) = gcd( (x+y)/2,(x-y)/2 );
2.x奇y偶 gcd( x,y ) = gcd( x,y/2 );
3.x偶y奇 gcd( x,y ) = gcd( x/2,y ) 或 gcd( x,y )=gcd( y,x/2 );
现在已经有了递归式,还需要再找出一个退化情况。注意到 gcd( x,x ) = x ,就用这个。

#include "pch.h"
#include <iostream>
using namespace std;
int Stein(int x, int y)
{
	int ans = 0;
	if (x < y) {
		swap(x, y);
	}
	if (y == 0) return x;     //0能被任何非0数整除
	while (x != y)
	{
		if (x & 1) {      //x&0x1(0x表示16#)
			if (y & 1) {    //x,y同为奇数时
				y = (x - y) >> 1;
				x -= y;
			}
			else {      //x为奇数,y为偶数时
				y >>= 1;
			}
		}
		else {
			if (y & 1) {//x为偶数,y为奇数
				x >>= 1;
				if (x < y) swap(x, y);
			}
			else {//x,y都为偶数
				x >>= 1;
				y >>= 1;
				ans++;
			}
		}
	}
	return x << ans;
}
int main()
{
	int a, b;
	printf("请输入a的值\n");
	scanf_s("%d", &a);
	printf("请输入b的值\n");
	scanf_s("%d", &b);
	cout << "最大公约数为:" <<Stein(a,b) << endl;
	cout << "最小公倍数为:" <<(a*b)/ Stein(a, b) << endl;
}

5、时间性能比较:

#include"pch.h"
#include <stdio.h>
#include<iostream>
#include <time.h>
using namespace std;
const  float CLOCKS_PER_SECOND = 1000000;
int Stein(int a, int b)         //stein算法
{
	int ans = 0;
	if (a < b) {
		swap(a, b);
	}
	if (b == 0) return a;     //0能被任何非0数整除
	while (a != b)
	{
		if (a & 1) {      //x&0x1(0x表示16#)
			if (b & 1) {    //x,y同为奇数时
				b = (a - b) >> 1;
				a -= b;
			}
			else {      //x为奇数,y为偶数时
				b >>= 1;
			}
		}
		else {
			if (b & 1) {//x为偶数,y为奇数
				a >>= 1;
				if (a < b) swap(a, b);
			}
			else {//a,b都为偶数
				a >>= 1;
				b >>= 1;
				ans++;
			}
		}
	}
	return a << ans;
}
int digui(int a, int b) {        //递归算法
	a = (a > b) ? a : b;
	if (a % b == 0)
		return b;
	else return (b, a%b);
}
int fhbs(int a, int b)     //更相替减法
{
	int i = 0;
	while (a % 2 == 0 && b % 2 == 0) {
		a = a / 2;
		b = b / 2;
		i++;
	}
	if (i == 0)
		return(1);
	else
		return(i);
}
int fhds(int a, int b)
{
	int m, n, t;
	m = (a > b) ? a : b;
	n = (a < b) ? a : b;
	while (1)
	{
		t = m - n;
		if (t > n) {
			m = t;
			n = n;
		}
		else {
			m = n;
			n = t;
		}
		if (n == (m - n))
			break;
	}
	if (n == 0)
		return 1;
	else
		return n;
}
int zdgys(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;
}
int zxgbs(int a, int b) {
	int zdgbs(int a, int b);
	int temp;
	temp = zdgys(a, b);
	return (a*b / temp);
}
int Zdgys(int a, int  b) {     //穷举法1
	int temp;
	temp = a < b ? a : b;
	while (temp > 0) {
		if (a%temp == 0 && b%temp == 0)
			return temp;
		else temp--;
	}
}
int Zxgbs(int a, int b) {       //穷举法2
	int  temp;
	temp = a > b ? a : b;
	while (1) {
		if ((temp) % b == 0)
			break;
		temp = temp + a;
	}
	return(temp);
}

int main()
{
	int i, a,b;
		printf("请输入数据a:");
		scanf_s("%d", &a);
		printf("请输入数据b:");
		scanf_s("%d", &b);
		for (i = 1; i < 5; i++) {
			switch (i) {
			case 1: {cout << "stein算法最大公约数:" << Stein(a, b)<<"最小公倍数;"<<(a*b)/Stein(a,b) << endl; break; }
			case 2: {cout <<"递归算法最大公约数:"<<digui(a,b)<< "最小公倍数:" <<(a*b)/ digui(a, b) << endl; break; }
			case 3: {cout << "嵌套算法最大公约数 "<<(a*b)/zxgbs(a,b)<< "嵌套算法最小公倍数:" << zxgbs( a, b) << endl; break; }
			case 4: {cout << "穷举算法最大公约数:" << Zdgys( a, b) << "穷举算法最小公倍数:" << Zxgbs(a, b) << endl; break; }
			}
			cout << "运行时间为:" << clock()/(CLOCKS_PER_SECOND) << endl;
		}	
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值