求最大公约数之辗转相除法、更相减损术及两者结合算法

来源:互联网 发布:景泰蓝 珐琅 区别 知乎 编辑:程序博客网 时间:2024/06/05 00:23

下面代码受漫画算法:辗转相除法是什么鬼?启发,原文讲解十分精彩,强烈建议查看原文,但是原文代码有几个小错误,本文代码为修改后的版本。讲解均在代码注释。


/**< 测试几种求最大公约数的算法 */#include <stdio.h>#include <stdlib.h>int gcdOri(const int a, const int b);int gcdEA(const int a, const int b);int gcdMD(const int a, const int b);int gcdBEST(const int a, const int b);int main(){    int a, b;    scanf("%d %d", &a, &b);    printf("Common algorithm:          %d\n", gcdOri(a, b));    printf("Euclidean algorithm:       %d\n", gcdEA(a, b));    printf("More derogation algorithm: %d\n", gcdMD(a, b));    printf("Best algorithm:            %d\n", gcdBEST(a, b));    printf("Hello world!\n");    system("pause");}/** 最暴力的算法,从2遍历到a和b中较少的那个一半 *  效率最低,时间复杂度为O(n/2); */int gcdOri(const int a, const int b){    int smallnum = a<b?a:b;    int bignum = a>b?a:b;    int i, rlt;    if(bignum%smallnum == 0)        rlt = smallnum;    else    {        for(i=2; i<=smallnum/2; i++)        {            if((bignum%i==0) && (smallnum%i==0))            {                rlt = i;            }        }    }    return rlt;}/** 辗转相除法, 又名欧几里得算法(Euclidean algorithm) *  定理:两个正整数a和b(a>b),它们的最大公约数等于a除以b的余数c和b之间的最大公约数。 *  比如10和25,25除以10商2余5,那么10和25的最大公约数,等同于10和5的最大公约数。 *  但是当a、b较大是,a%b取模运算的性能比较低 */int gcdEA(const int a, const int b){    int rlt;    int smallnum = a<b?a:b;    int bignum = a>b?a:b;    if(bignum%smallnum == 0)        rlt = smallnum;    else    {        rlt = gcdEA(smallnum, bignum%smallnum);    }    return rlt;}/** 更相减损术, 出自于中国古代的《九章算术》 *  两个正整数a和b(a>b),它们的最大公约数等于a-b的差值c和较小数b的最大公约数。 *  比如10和25,25减去10的差是15,那么10和25的最大公约数,等同于10和15的最大公约数。 *  更相减算术依靠两数求差的方式来递归,运算的次数肯定远大于辗转相除法的取模方式 *  比如计算1000和1,就要递归999次 */int gcdMD(const int a, const int b){    int rlt;    int smallnum = a<b?a:b;    int bignum = a>b?a:b;    if(bignum%smallnum == 0)  /**< 应该和bignum==smallnum一样 */        rlt = smallnum;    else    {        rlt = gcdMD(smallnum, (bignum-smallnum));    }    return rlt;}/** 最优方法:把辗转相除法和更相减损法的优势结合起来,在更相减算术的基础上使用移位运算 *  对于给定的正整数a和b,不难得到如下的结论。其中gcb(a,b)的意思是a,b的最大公约数函数: *  当a和b均为偶数,gcb(a,b) = 2*gcb(a/2, b/2) = 2*gcb(a>>1, b>>1) *  当a为偶数,b为奇数,gcb(a,b) = gcb(a/2, b) = gcb(a>>1, b) *  当a为奇数,b为偶数,gcb(a,b) = gcb(a, b/2) = gcb(a, b>>1) *  当a和b均为奇数,利用更相减损术运算一次,gcb(a,b) = gcb(b, a-b), 此时a-b必然是偶数,又可以继续进行移位运算。 */int gcdBEST(const int a, const int b){    int rlt = 0;    int smallnum = a<b?a:b;    int bignum = a>b?a:b;    if(bignum%smallnum == 0)        rlt = smallnum;    else    {        if(!(bignum&1) && !(smallnum&1))  /**< '&1'与1运算,就是2进制下末尾和1做‘与’运行,结果同1异0,所以可用来判断奇偶,返回1为奇,0为偶 */        {            rlt = gcdBEST(bignum>>1, smallnum>>1) << 1;            /**< 右移运算 >>1 相当于偶数/2,相反地,左移运算,相当于*2 */        }        else if(!(bignum&1) && smallnum&1)        {            rlt = gcdBEST(bignum>>1, smallnum);        }        else if(bignum&1 && !(smallnum&1))        {            rlt = gcdBEST(bignum, smallnum>>1);        }        else if(bignum&1 && smallnum&1)        {            rlt = gcdBEST(smallnum, bignum-smallnum);        }    }    return rlt;}






阅读全文
0 0
原创粉丝点击