求最大公约数及求多个数的最大公约数

求两个数的最大公约数的三种方法:

一、 穷举法:

分析:因为最大公约数必小于等于这两个数中的较小数,故先取两个数中较小的值 t 作为起始值开始判断,满足后直接输出并结束,不满足则继续判断 t- -,直至找到最大公约数为止!

void Greatest_common_divisor1(int a, int b)//穷举法
{
	if (a == 0 || b == 0)//0没有最大公约数
	{
		printf("\"0\"没有最大公约数!\n");
		//\"	\"是为了输出",不懂的童鞋可以查查转义字符。
		return;
	}
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	int t;
	t = a < b ? a : b;
	//最大公约数一定小于两个数中的较小数,故在此将较小值赋给t.
	//for (int i = t; i>0; i--)
	//{
	//	if ((a%i == 0) && (b%i == 0))//当i同时整除a,b时,此时i为最大公约数
	//	{
	//		printf("%d\n", i);
	//		break;
	//	}
	//}
	while ((a%t != 0) || (b%t != 0))
	{
		t--;
	}
	printf("%d\n", t);//与上述for循环功能一致,取一即可
}

二、【欧几里得算法】辗转相除法

分析:每个步骤都可以表示为m=n*C+r的形式,而经过每一个步骤,n 移到 m 的位置,r 移到 n 的位置。当m%n!=0时,执行上述步骤; 直至当r=m%n==0时,求得gcd=n;
目前,欧几里得开发的此算法是求最大公约数方法中被公认为效率最高的一种。

void Greatest_common_divisor2(int a, int b)//辗转相除法
{
	if (a == 0 || b == 0)//0没有最大公约数
	{
		printf("\"0\"没有最大公约数!\n");
		//\"	\"是为了输出",不懂的童鞋可以查查转义字符。
		return;
	}
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	if (a < b)
	{
		swap(&a, &b);
	}
	while (b>0)
	{
		int t = a%b;
		//不能直接把a%b赋给b(b=a%b),因为b的值在下一步要赋给a,如果现在就把a%b赋给b会将b的值覆盖掉导致下一步出错。引入t来解决这一问题
		a = b;
		b = t;
	}
	printf("%d\n", a);
} 

三、 辗转相减法

分析:判断两数的大小,取较大值和较小值的差并赋给较大值,直至两值相等,即相等的值即为最大公约数

void Greatest_common_divisor3(int a, int b)//辗转相减法
{
	if (a == 0 || b == 0)//0没有最大公约数
	{
		printf("\"0\"没有最大公约数!\n");
		//\"	\"是为了输出",不懂的童鞋可以查查转义字符。
		return;
	}
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	while (a != b)//当a和b相等时
	{
		if (a>b)
		{
			a = a - b;
		}
		else
		{
			b = b - a;
		}
	}
	printf("%d\n", b);
}

整体代码:

/*    求最大公约数的三种方法:
       运行环境:vs2013    */
#include
#include
#include
void swap(int *x, int*y);
void Greatest_common_divisor1();
void Greatest_common_divisor2();
void Greatest_common_divisor3();
int main()
{
	int a, b,s;
	while (1)
	{
		printf("请输入a,b的值:");
		scanf("%d%d", &a, &b);
		if (a == 0 || b == 0)//0没有最大公约数
		{
			printf("\"0\"没有最大公约数!\n");
			//	\"	\"是为了输出"0"的效果,不懂的童鞋可以查查转义字符。
			continue;
		}
		printf("1.使用穷举法求最大公约数;\n");
		printf("2.使用辗转相除法法求最大公约数;\n");
		printf("3.使用辗转相减法求最大公约数;\n");
		scanf("%d",&s);
		switch (s)
		{
		case 1:Greatest_common_divisor1(a, b);
			break;
		case 2:Greatest_common_divisor2(a, b);
			break;
		case 3:Greatest_common_divisor3(a, b);
			break;
		default:printf("输入有误!");
		}
		system("pause");
		system("cls");
	}
	return 0;
}
void Greatest_common_divisor1(int a, int b)//穷举法
{
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	int t;
	t = a < b ? a : b;//最大公约数一定小于两个数中的较小数,故在此将较小值赋给t.
	while ((a%t != 0) || (b%t != 0))
	{
		t--;
	}
	printf("%d\n", t);
}
void Greatest_common_divisor2(int a, int b)//辗转相除法
{
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	if (a < b)
	{
		swap(&a, &b);
	}
	int t=1;//随便给t一个大于0的值
	while (t>0)
	{
		t = a%b;
		//不能直接把a%b赋给b(b=a%b),因为b的值在下一步要赋给a,如果现在就把a%b赋给b会将b的值覆盖掉导致下一步出错。引入t来解决这一问题
		a = b;
		b = t;
	}
	printf("%d\n", a);
} 

void swap(int *x, int*y)
//通过指针改变原地址内存储的值,当该函数结束.栈帧释放时实现该函数的改值操作仍有效。
{
	int t = *x;
	*x = *y;
	*y = t;
} 
void Greatest_common_divisor3(int a, int b)//辗转相减法
{
	a = abs(a);//取绝对值,防止a或b为负对结果造成错误影响
	b = abs(b);
	while (a != b)//当a和b相等时
	{
		if (a>b)
		{
			a = a - b;
		}
		else
		{
			b = b - a;
		}
	}
	printf("%d\n", b);
}

说完三种方法,再思考一下当求多个数的最大公约数时,该如何处理:

递归法:

分析思路:该gcd应该先求前两个数的gcd,然后再将gcd和下一个数求gcd和这个数的gcd,听起来有点绕口,简言之就是不断用gcd和后面的数进行求公约数运算,直至进行到最后一个数得到的gcd便是这组数的gcd;(作者简称最大公约数:gcd)
注:求两个数的最大公约数以上介绍了三种方法,此处选择最靠谱的辗转相除法。
代码实现如下:

//求最大公约数进阶:求多个数的最大公约数。
#include
#define max 4//一共求max个数的最大公约数
void set_array();
void print_array();
void swap(int *x, int *y);
int Greatest_common_divisor(int a, int b);
int main()
{
	int a[max] = { 0 };
	set_array(a);
	print_array(a);
	int gcd=Greatest_common_divisor(a[0],a[1]);
	for (int i =2; i < max; i++)
	{
		gcd = Greatest_common_divisor(gcd, a[i]);
		//每次使gcd和后面的数求最大公约数
	}
	printf("该%d个数的共同最大公约数为:%d\n", max, gcd);
	return 0;
}
int Greatest_common_divisor(int a, int b)
{
	if (a < b)
	{
		swap(&a, &b);
	}
	a = abs(a);
	b = abs(b);
	while (b)
	{
		int t = a%b;
		a = b;
		b = t;
	}
	return a;
}
void swap(int *x, int *y)
{
	int t = *x;
	*x = *y;
	*y = t;
}
void set_array(int p[])
{
	for (int i = 0; i < max; i++)
	{
		scanf("%d", &p[i]);
	}
}
void print_array(int *p)
{
	for (int i = 0; i < max; i++)
	{
		printf("%d\t", p[i]);
	}
}

穷举法:

分析:一组数的最大公倍数肯定小于这组数的最小数,然后从这个最小数开始穷举,每次判断这组数是否可以全部整除这个数,若可以,则该数为这组数的最大公约数;否则,继续穷举;知道找到为止。
代码实现:

#include
#include
#include
#define max 4
void set_array();//初始化数组
void print_array();//输出数组
int Min_Num(int *p);//返回数组中的最小数
bool Determine_divisible(int *p, int n);//判断n是否可以整除*p中所有数
int main()
{
	int a[max] = { 0 };
	set_array(a);
	print_array(a);
	int min = Min_Num(a);
	for (int i = min; i > 0; i--)
	{
		if (Determine_divisible(a, i))
		{
			printf("\n这几个数的最小公约数:%d\n", i);
			break;
		}
	}
	for (int i = a[0]; i > 0; i--)
	//此处i的初始值不同,相比与上一个循环可以不用Min_Num()函数的辅助,省去求最小值的时间。
	/*给i赋这组数中任意值,若改值可以被其他数整除,故该数为最大公倍数(这种情况只存在于所给数恰好为最小数,且该数可以整除其余数)
	否则递减,直到满足所有数都可被i整除	*/
	{
		if (Determine_divisible(a, i))
		{
			printf("这几个数的最小公约数:%d\n", i);
			break;
		}
	}
	return 0;
}
void set_array(int p[])
{
	for (int i = 0; i < max; i++)
	{
		scanf("%d", &p[i]);
	}
}
void print_array(int *p)
{
	for (int i = 0; i < max; i++)
	{
		printf("%d\t", p[i]);
	}
}
int Min_Num(int *p)
{
	int t = p[0];
	for (int i = 1; i < max; i++)
	{
		t = p[i]>t ? t : p[i];
	}
	return t;
}
bool Determine_divisible(int *p, int n)
{
	for (int i = 0; i < max; i++)
	{
		if (p[i] % n != 0)
		{
			return false;
		}
	}
	return true;
}

你可能感兴趣的:(c语言---基础,每日一题)