论题一: 给出两个非负整数u和v,求出它们的最大公因子. 用gcd(u,v)表示.
算法一:现代欧几里德算法
A1:如果v=0,则u就是最大公因子,否则继续;
A2:置r=u mod v,u=v,v=r,跳转到A1;
上面的描述可以用递归来实现,C#代码如下:
- public int gcd(int u,int v)
- {
- if(0==v)
- {
- return u;
- }
- else
- return gcd(v,u%v);
- }
欧几里德算法无疑是一个经典然而它并不是解决这个问题的最好方法。下面描述一个主要适用于二进制的gcd算法.
二进制的gcd算法基于正整数的四项基本事实:
1)如果u和v都是偶数,则gcd(u,v)=2gcd(u/2,v/2);
2)如果u是偶数而v是奇数,则gcd(u,v)=gcd(u/2,v);
3)如果u和v都是奇数,则|u-v|是偶数,且|u-v|<max(u,v);
4)gcd(u,v)=gcd(u-v,v);
上面的描述用C#代码实现如下:
- public int binaryGcd(int u, int v)
- {
- int fac = 0;
- if (0 == u)
- {
- return v;
- }
- if (0 == v)
- {
- return u;
- }
- fac+= (u&1)==0? 0:1;
- fac+= (v&1)==0? 0:2;
- switch (fac)
- {
- case 0:
- return binaryGcd(u >> 1, v >> 1) << 1;
- break;
- case 1:
- return binaryGcd(u, v >> 1);
- break;
- case 2:
- return binaryGcd(u >> 1, v);
- break;
- default:
- return binaryGcd(Math.Abs(u - v) >> 1, u > v ? v :u);
- }
- }
求最大公因子的问题解决了,那么求最小公倍数的问题就很简单了,因为u和v的乘积除以gcd(u,v)的结果就是它们的最小公倍数。
C#代码如下:
- public uint scp(uint u,uint v)
- {
- return u*v/gcd(u,v);
- }
今天就写到这里了,水平有限,欢迎大家提出意见和建议;
参考:<<计算机程序设计艺术>>,英文名<<The Art of Computer Programming>>;
和一些在网上搜集的资料。