辗转相除

      下面写说一个算法题:求两个正整数的最大公约数,一开始我是这么写的代码:

一:暴力枚举:暴力枚举就是把可能的答案一一列举出来,并加以判断。

 public static int GetGreatestCommonDivisor(int numA, int numB)
        { 
            int SmallNum=numA<numB?numA:numB;
            int BigNum=numA>=numB?numA:numB;
            if (BigNum % SmallNum == 0)
            {
                return SmallNum;
            }
            int greatestcommonDivisor=1; //初始最大公约数为1
            for(int i=2;i<=SmallNum/2;i++)
            {
                if(numA%i==0 && numB%i==0)
                {
                    greatestcommonDivisor=i; //每次只要都能被整除,就假设该数是最大的公约数
                }
            }
            return greatestcommonDivisor;
        }

        但想想,我这样利用暴力枚举的效率不高呀,如果我输入的这两个数是100000000和10000001,岂不是程序得循环100000000/2=50000000次,我如果输入更大的数那,接下来我就不刚想了。。。。。。。下面介绍一种算法——辗转相除


二:辗转相除:又名欧几里得算法,原理:两个正整数a和b(a>b),他们的最大公约数等于a除以的余数c和b之间的   最大公约数。例如10和25的最大公约数:25除以10的余数          为5,5和10的最大公约数为5,即10和25的最大公约数为5.

       根据这条原理,再利用递归的方法,即先计算出a除以b的余数c,b与c的最大公约数为e,e与c的最大公约数为f,......依次类推,直到两个数可以整除,即余数为0。代码思路如下:

        //方法接口,其实此方法就是先要判断输入的两个数的大小
         public static int getGreatestDivisor(int numA,int numB)
        {
            int divisor = 1;
             //判断这两个数的大小
            if (numA > numB)
            {
                divisor = GetDivisor(numA, numB);                 
            }
            else
            {
                divisor = GetDivisor(numB, numA);
            }
            return divisor;
        }

        //找最大公约数
        public static int GetDivisor(int a,int b)
        {
            //连个数是否可整除
            if (a % b == 0)
            {
                return b;
            }
            else
            {
                return GetDivisor(b, a % b);//调用自己的方法,利用递归找最大公约数
            }
        }   

注意:当整型数a,b较大时,a%b取模的性能会很低(所谓的性能,解释参考:

https://zhidao.baidu.com/question/15701184.html)。


三:更相减损术:原理:两个正整数a和b(a>b),它们的最大公约数为a-b与b的最大公约数.例如:10和25的最大公约数为(25-10)=15 与10的最大公约数.

       根据这条原理,再利用递归方法,即a减b的差为c,c与b的最大公约数e,b减e的差为f,e与f的最大公约数为g,.......依次类推,知道两个数相等,即差为0.代码思路如下:

        //递归求最大公约数
        public static int GetDivisor(int numA, int numB)
        {
            if (numA - numB == 0)//两个数相等的情况
            {
                return numA;
            }
            if (numA > numB)
            {
                return (GetDivisor(numB, numA - numB));//调用自己的方法,实现递归
            }
            else
            {
                return(GetDivisor(numA,numB-numA));//调用自己的方法,实现递归
            }
        }
注意:此方法运算的次数大于辗转相除法取模的方式,更相减损法不稳定,当a,b相差较大时,a=10000,b=1,就要递归9999次。


四:移位算法,该算法的性能比较快,利用更相减损术和移位结合,可避免取模运算,而且算法性能稳定

       1.a和b均为偶数,GetDivisor(a,b)=2*GetDivisor(a/2,b/2)=2*GetDivisor(a>>1,b>>1)

       2.a为偶数,b为奇数,GetDivisor(a,b)=GetDivisor(a/2,b)=GetDivisor(a>>1,b)

       3.a为奇数,b为偶数,GetDivisor(a,b)=GetDivisor(a,b/2)=GetDivisor(a,b>>1)

       4.a,b均为奇数时,则利用更相减损术运算一次,GetDivisor(a,b)=GetDivisor(b,a-b),此时a-b必然是偶数,又可以继续进行移位运算了。

        public static int GetDivisor(int numA, int numB)
        {
            if (numA == numB)
            {
                return numA;
            }

            if (numA < numB)//保证numA永远是较大者,较少代码量
            {
                return GetDivisor(numB, numA);
            }
            else
            {                
                if (numA % 2 ==0 && numB % 2==0) //偶偶
                {
                    return GetDivisor(numA >> 1, numB >> 1) << 1;
                }
                else if (numA % 2==0 && numB % 2!=0)//偶奇
                {
                    return GetDivisor(numA >> 1, numB);
                }
                else if (numA % 2!=0 && numB % 2==0)//奇偶
                {
                    return GetDivisor(numA, numB >> 1);
                }
                else //奇奇
                {
                    return GetDivisor(numB, numA - numB);
                }            
            }
        }

【总结】

以上方法的时间复杂度O各自有所不同,有关时间复杂度的知识还有待研究。




      







评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值