264 5。辗转相除法 java 实现 及其时间复杂度证明。" />

辗转相除法 java 实现 及其时间复杂度证明

代码

public static void main(String[] args) { Random r = new Random(); for (int ii = 0; ii < 10; ii++) { int num1 = r.nextInt(100); int num2 = r.nextInt(80); System.out.println(num1 + " " + num2 + " -> " + mod(num1, num2)); } } private static int mod(int a, int b) { if (a < b) return mod(b, a); while (a % b != 0) { int temp = b; b = a % b; a = temp; //这儿必须要有一个临时变量? } return b; }

【辗转相除法 java 实现 及其时间复杂度证明】输出
66 26 -> 2 64 50 -> 2 19 61 -> 1 79 43 -> 1 81 1 -> 1 17 76 -> 1 74 66 -> 2 48 9 -> 3 1 70 -> 1 59 5 -> 1

证明 这儿我们用的是非递归实现。
简单证明一下。 设最大公约数为 m。则数 a=n1*m,b=n2*m。a-b=(n1-n2)*m,gcd(a,b)=gcd(b, a mod b)。也就是说 a 、b 的公约数和b、a%b 的公约数是一样的。
时间复杂度证明 ## 时间复杂度 log(n),其中 n 为 a、b 间较大的数。
做一个实验:在10000以内两两辗转相除法,运算次数最多的是哪两个数呢?
6765和 4181
如果把上界再缩小或扩大,你会发现,出现的数都是斐波那契数列中的数,都是相邻的两项。
因为斐波那契数列相邻两项在做gcd的时候,每次mod只相当于做了一次a-b,退化成更相减损术了,而没有起到mod的加速效果。
而斐波那契数列有通项公式,Fn=(1.618)n/sqrt(5),第n项的值是与某两个无理数的n次相关的。所以,是logn了
还有一种解答,数学证明很麻烦
我们先不考虑模运算本身的时间复杂度(算术运算的时间复杂度在Knuth的TAOCP中有详细的讨论), 我们只考虑这样的问题: 欧几里得算法在最坏情况下所需的模运算次数和输入的a和b的大小有怎样的关系?
我们不妨设a>b>=1(若a < b我们只需多做一次模运算, 若b=0或a=b模运算的次数分别为0和1), 构造数列{un}: u0=a, u1=b, uk=uk-2 mod uk-1(k>=2), 显然, 若算法需要n次模运算, 则有un=gcd(a, b), un+1=0. 我们比较数列{un}和菲波那契数列{Fn}, F0=1<=un, F1=1<=un-1, 又因为由uk mod uk+1=uk+2, 可得uk>=uk+1+uk+2, 由数学归纳法容易得到uk>=Fn-k, 于是得到a=u0>=Fn, b=u0>=Fn-1. 也就是说如果欧几里得算法需要做n次模运算, 则b必定不小于Fn-1. 换句话说, 若 b < Fn-1, 则算法所需模运算的次数必定小于n. 根据菲波那契数列的性质, 有Fn-1>(1.618)n/sqrt(5), 即b>(1.618)n/sqrt(5), 所以模运算的次数为O(lgb).
参考文章 http://www.aliog.com/67694.html
http://blog.csdn.net/u014285517/article/details/45392407
https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97

    推荐阅读