1. 程式人生 > >求最大公因子的簡單(時間複雜度小)演算法

求最大公因子的簡單(時間複雜度小)演算法

1.輾轉相除法
用(a,b)表示a和b的最大公約數
有定理: 已知a,b,c為正整數,若a除以b餘c,則(a,b)=(b,c)。 (證明過程請參考其它資料)
例如:求gcd(319,377):
∵ 377÷319=1(餘58)
∴gcd(377,319)=gcd(319,58);
∵ 319÷58=5(餘29),
∴ gcd(319,58)=gcd(58,29);
∵ 58÷29=2(餘0),
∴ gcd(58,29)= 29;
∴ gcd(319,377)=29.
演算法實現
#include <iostream>
#include <math.h>
using namespace std;

int gcd1(int a,int b)//遞迴版本
{
    if (a<b)  //確定被除數和除數
    {
        int temp=a;
        a=b;
        b=temp;
    }
    if (b==0)  //求出結果
    {
        return a;
    }
    else
    {
        <strong>return gcd1(b,a%b);   //遞迴呼叫</strong>
    }
}
int gcd2(int a,int b)//迴圈版本
{
    if (a<b)
    {
        int temp=a;
        a=b;
        b=temp;
    }
    while ( b!=0)
    {
        int c=a%b;
        a=b;
        b=c;
    }
    return a;
}
int main()
{
    int a,b;
    cout<<"請輸入兩個正數:"<<endl;
    cin>>a>>b;
    cout<<a<<"與"<<b<<"的最大公約數是:"<<gcd2(a,b)<<endl;//cout<<a<<"與"<<b<<"的最大公約數是:"<<gcd1(a,b)<<endl;

輾轉相除法的時間複雜度O(logN)

存在的問題,當兩個整形數較大時,做a%b的取模運算效能會比較低,所以,還有一個演算法叫更相減損演算法,更相減損術來自與《九章算術》 第一步:任意給定兩個正整數;判斷它們是否都是偶數。若是,則用2約簡;若不是則執行第二步。第二步:以較大的數減較小的數,接著把所得的差與較小的數比較,並以大數減小數。繼續這個操作,直到所得的減數和差相等為止。則第一步中約掉的若干個2與第二步中等數的乘積就是所求的最大公約數。其中所說的“等數”,就是最大公約數。求“等數”的辦法是“更相減損”法例1、用更相減損術求98與63的最大公約數。解:由於63不是偶數,把98和63以大數減小數,並
輾轉相減
:98-63=3563-35=2835-28=728-7=2121-7=1414-7=77-7=0所以,98和63的最大公約數等於7。例2、用更相減損術求260和104的最大公約數。解:由於260和104均為偶數,首先用2約簡得到130和52,再用2約簡得到65和26。此時65是奇數而26不是奇數,故把65和26輾轉相減:65-26=3939-26=1326-13=13所以,260與104的最大公約數等於13乘以第一步中約掉的兩個2,即13*2*2=52。時間複雜度分析:更相減損術和輾轉相除法的主要區別在於前者所使用的運算是“減”,後者是“除”。從演算法思想上看,兩者並沒有本質上的區別,但是在計算過程中,如果遇到一個數很大,另一個數比較小的情況,可能要進行很多次減法才能達到一次
除法的效果,從而使得演算法的時間複雜度退化為O(N),其中N是原先的兩個數中較大的一個。相比之下,輾轉相除法的時間複雜度穩定於O(logN)。 演算法實現:
int gcd(int a, int b)
{
   while(a != b)
   {
      if(a > b)
      a -= b;
      else
      b -= a;
   }
   return a;
}
所以說,採用什麼演算法求兩個數的最大公約數要看這兩個數的值