算法 | 求最大公约数的几种方法

目录

  • 前言
  • 穷举法
  • 辗转相除法
  • 更向减损法
  • Stein算法
  • 结语

前言

相信小伙伴们都求过两个数的最大公倍数吧?

今天就让我们一起来学习几种求最大公倍数的不同方法吧!

我们可以从中提升自己的思维还有代码能力哦!

温馨提示:今天的算法都是有C语言实现的哦!

穷举法

穷举法又可以称为:直接法、定义法。

其思路如下:

定义一个变量来存放两个数中较小的一个,然后通过循环来尝试这一个变量中的数字是否能够被这两个数字同时整除,如果不行就减少1,再尝试。

实现的代码如下:

#include

int main()
{
     
	int a = 0;
	int b = 0;
	int c = 0;
	scanf("%d %d", &a, &b);
	
	//c用于存放a和b中较小的那一个
	c = a < b ? a : b;

	//如果a和b这两个数字的最大公倍数为1,那么while中最后到1再c--后也会退出循环
	while (c > 0)
	{
     
		if (a % c == 0 && b % c == 0)
		{
     
			printf("最大公约数为:%d", c);
			break;
		}
		c--;

	}
	
	return 0;
}

辗转相除法

辗转相除法又称欧几里得算法。

它们的最大公约数等于a除以b 的余数c和b之间的最大公约数。

即第一次相除的除数作为第二次的被除数,两个数相除后所得的余数做为第二次相除的除数直到余数为0,此时除数就为最大的公约数。

这个方法可以有两种方式来实现:一种是直接法,另一种是函数递归的方法。

具体的代码实现如下:

#include

int func1(int a, int b)
{
     
	int c = 0;
	while (c = a % b)
	{
     
		a = b;
		b = c;

	}
	return b;
}

int func2(int a, int b)
{
     
	if (!(a % b))
		return b;
	else
		return func2(b, a % b);

}

int main()
{
     
	int a = 0;
	int b = 0;
	int c = 0;
	scanf("%d %d", &a, &b);

	//直观实现
	int ret1 = func1(a, b);
	printf("最大公约数为:%d\n", ret1);

	//递归实现
	int ret2 = func2(a, b);
	printf("最大公约数为:%d\n", ret2);


	return 0;
}

更向减损法

该方法出自我国古代的《九章算术》,体现出我国古代人们的智慧!

思路如下:
给定两个正整数,这两个数的最大公约数为两个数的差(非负)与较小的那个数字的最大公约数。

该方法适合于用递归的方法来解决。

具体的代码如下:

#include

int func1(int a, int b)
{
     
	if (a == b)
		return a;
	else if (a > b)
		return func1(a - b, b);
	else
		return func1(b - a, a);

}

int main()
{
     
	int a = 0;
	int b = 0;
	int c = 0;
	scanf("%d %d", &a, &b);


	//递归实现
	int ret1 = func1(a, b);
	printf("最大公约数为:%d\n", ret1);


	return 0;
}

Stein算法

这个算法也被称为二进制算法,该算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。

算法 | 求最大公约数的几种方法_第1张图片

(温馨提示:上述两幅图片来源于网络)

代码如下:

//Stein算法

#include

//更向减损法
int func1(int a, int b)
{
     
	if (a == b)
		return a;
	else if (a > b)
		return func1(a - b, b);
	else
		return func1(b - a, a);
}

//Stein
int func2(int a, int b)
{
     
	//如果这两个数字相等,那么最大公约数就为本身
	if (a == b)
		return a;
	if (0 == a)
		return b;
	if (0 == b)
		return a;
	if (a % 2 == 1)
	{
     
		if (b % 2 == 1)
		{
     
			//保证等一下相减的时候能够得到正数
			int tmp1 = a > b ? a : b;
			int tmp2 = a < b ? a : b;
			return func1((tmp1 - tmp2), tmp2);

		}
		else
		{
     
			return func2(a, b / 2);
		}
	}
	else
	{
     
		if (b % 2 == 1)
		{
     
			return func2(a / 2, b);
		}
		else
		{
     
			return func2(a / 2, b / 2) * 2;
		}
	}

}


int main()
{
     
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);

	int ret = func2(a, b);

	printf("%d\n", ret);

	return 0;
}

以上就是该算法的基本实现了,但是,再实际的开发中,所输入的数字可能会很大,那么取模和除法运算就会比较浪费时间了,我们注意到,这上述代码中,除法运算都是以除以2为主,判断奇偶的时候也是以取模运算为主。

那么我们可以对上述代码进行优化。

判断奇数还是偶数:一个数按位与1,结果为1则说明这个数字是奇数,结果为0则说明这个数为偶数。

乘以二:一个数左移1位

除以二:一个数右移1位

那么现在我们就可以对上述代码进行改造啦

//Stein算法

#include

//更向减损法
int func1(int a, int b)
{
     
	if (a == b)
		return a;
	else if (a > b)
		return func1(a - b, b);
	else
		return func1(b - a, a);
}

//Stein
int func2(int a, int b)
{
     
	//如果这两个数字相等,那么最大公约数就为本身
	if (a == b)
		return a;
	if (0 == a)
		return b;
	if (0 == b)
		return a;
	if (a&1)
	{
     
		if (b&1)
		{
     
			//保证等一下相减的时候能够得到正数
			int tmp1 = a > b ? a : b;
			int tmp2 = a < b ? a : b;
			return func1((tmp1 - tmp2), tmp2);

		}
		else
		{
     
			return func2(a, b>>1);
		}
	}
	else
	{
     
		if (b&1)
		{
     
			return func2(a>>1, b);
		}
		else
		{
     
			return func2(a>>1, b>>1)<<1;
		}
	}

}


int main()
{
     
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);

	int ret = func2(a, b);

	printf("%d\n", ret);

	return 0;
}

位运算是再内存中直接对数据进行运算的,这样的话,效率会比除法运算和取模运算提高很多哦~

结语

算法的学习不在于代码的多少与否,关键还得看自己是否学习到其中的思想,小伙伴们一定不能仅限于看懂代码哦,一定要多上手写一写代码才行哦。

最后啊,创作不易呀,希望小伙伴们可以动动小手,给我一个关注、一个赞还有评论哦~

由于本人能力有限,如果有错误的地方,希望大佬们可以指出!
算法 | 求最大公约数的几种方法_第2张图片

你可能感兴趣的