1. 程式人生 > >求兩個數的最大公約數,輾轉相除法與更相減損法(遞歸叠代)

求兩個數的最大公約數,輾轉相除法與更相減損法(遞歸叠代)

叠代 div 余數 公約數 穩定 log test 算法 復雜度

問題:給出兩個數a和b,求出他們的最大公約數(greatest common divisor)。

解法一:輾轉相除法,又叫歐幾裏得算法。兩個正整數a和b(a>b),他們的最大公約數等於a除以b的余數和b之間的最大公約數。

比如10和25,25除以10余5,那麽10和25的最大公約數等同於5和10之間的最大公約數。

//輾轉相除法    遞歸解法
int gcd(int a,int b){
    if(a%b==0)
        return b;
    return (b,a%b);
}

//輾轉相除法   叠代解法
int
gcd2(int a,int b){ int t;
while(b!=0){ t=b; b=a%b; a=t; } return a; }

解法二:更相減損術,出自中國古代的《九章算術》。兩個正整數a和b(a>b),他們的最大公約數等於a-b的差值c和較小數b的最大公約數。

比如10和25,25-10=15,那麽10和25的最大公約數等於10和15的最大公約數。

//更相減損術  遞歸 
int gcd3(int a,int b){
    if(a==b)
        return a;
    if(a>b)
        return gcd(a-b,b);
    
else return gcd(b-a,a); }

//更相減損術  叠代
int gcd4(int a,int b){
    while(a*b!=0){
        if(a>b)
            a=a-b;
        else
            b=b-a;    
    }
    return a?a:b;
}

改進:更相減損術是不穩定的算法,當兩個數相差懸殊時,如10000和1的最大公約數,要遞歸9999次。

做法;

當a和b都是偶數時,gcd(a,b)=2*gcd(a/2,b/2)=2*gcd(a>>1,b>>1)。

當a是奇數,b是偶數時,gcd(a,b)=gcd(a,b/2)=gcd(a,b>>1)。

當a是偶數,b是奇數時,gcd(a,b)=gcd(a/2,b)=gcd(a>>1,b)。

當a和b都是奇數數時,gcd(a,b)=gcd(a-b,b)。

//改進版:
int gcd5(int a,int b){
    if(a==b)
        return a;
    else if(a<b)
        return gcd5(b,a);    //始終讓 a>b
    else{
        if(!(a&1)&&!(b&1)){    //兩數都為偶數 
            return gcd5(a>>1,b>>1)<<1;
        }else if((a&1)&&!(b&1)){    //a奇數 b偶數 
            return gcd5(a,b>>1);
        }else if(!(a&1)&&(b&1)){    //a偶數 b奇數 
            return gcd5(a>>1,b);
        }else
            return gcd(a,a-b);        //都是奇數 相減 
        
    } 
}

算法復雜度:

輾轉相除法:O(log(max(a,b)))

更相減損法:O(max(a,b))

改進更相減損法:O(log(max(a,b)))

求兩個數的最大公約數,輾轉相除法與更相減損法(遞歸叠代)