编程之美___最大公约数问题

—————————————————————————————————————————————————————————————————————————————

看《编程之美》这本书,写的很不错,可是只看不把代码敲一下,总觉得不是真正的吸收了,而在敲代码的过程中说不定也会有更深层次的了解,所以就把其中的思路写下来同时也方便以后查阅。

PS:这篇博文是自己码的,里面的思想几乎全部都是摘抄自《编程之美》这本书,喜欢这本书,请买原书。

—————————————————————————————————————————————————————————————————————————————–

写一个程序,求两个非负整数的最大公约数(greatest common divisor),如果两个正整数都很大呢,如果两个数差别比较大呢

首先求最大公约数一般是使用辗转相除法,代码如下:

int gcd1(int a, int b)
{
	if (b == 0)
	{
		return a;
	}
	return gcd1(b, a%b);
}

上述代码是根据辗转相除的定义来的,里面有%操作,对于大数来说,这是很费时的操作,有没有不用%的思路呢?

其实,(x, y) 和 (x-y, y)是相等的()表示求两个数的最大公约数,当然这里需要x > y,当x < y 时候,可以实用 y-x 来保证满足题意。

代码如下:

int gcd2(int a, int b)
{
	if (0 == b)
	{
		return a;
	}
	if (a < b)
	{
		return gcd2(b, a);
	}
	return gcd2(a-b, b);
}

把%运算换成了-运算,本质上其实没有多大变化,gcd2也有问题,如当a 和 b相差比较大的时候(如222222 和 1)求公约数的过程中将递归很深而使得程序崩溃

有没有可能结合gcd1 和 gcd2的思路呢?分析如下:

我们知道,如果x = k *a, y = k*b 那么(x,  y)= k * (a,  b)并且若 x = p*x1,p为素数且y%p != 0的话(x, y)  = (x1, y)。那么使用最小的素数2便可以有下分析

  1. x, y 均为偶数 则 (x, y) = 2 * (x  >> 1,  y  >> 1) 
  2. x为偶数,y为奇数 则 (x, y) =  (x  >> 1,  y ) 
  3. x为奇数,y为偶数 则 (x, y) =  (x ,  y  >> 1)
  4. x为奇数,y为奇数 则 (x, y) =  (x  – y,  y )

代码如下:

int gcd3(int a, int b)
{
	if (0 == b)
	{
		return a;
	}
	if (a < b)
	{
		return gcd3(b, a);
	}
	if (a&1)
	{
		if (b&1)
		{
			return gcd3(a-b, b);
		}
		else
		{
			return gcd3(a, b >> 1);
		}
	}
	else
	{
		if (b&1)
		{
			return gcd3(a >> 1, b);
		}
		else
		{
			return 2 * gcd3(a >> 1, b >> 1);
		}
	}
}

通过移位和减法来避免取模运算,提高了算法的效率。

PS: 这里的示例代码都是用int来说明问题,可以轻易地推广到大数问题,只有重载相应的运算。

    原文作者:sharp_king
    原文地址: https://blog.csdn.net/u011272079/article/details/23752651
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞