• 多个数的最大公约数


    ---恢复内容开始---

    最近在看一本算法的书。讲的都是一些基本的问题,并没有涉及很复杂的算法,或者说这本书更看重技巧。

    其中开篇就讲了最大公约数的算法,觉得有可取之处,和大家分享一下。

    提到最大公约数我们最先想到的一定是辗转相除法。

    没错,永远不要蔑视我们的祖先,他们的智慧是无穷的。(扯远了,嘿嘿)

    我们都在用辗转相除法来求最大公约数,却很少去想为什么辗转相除法就能求最大公约数呢?或者说怎么证明算法的正确性呢(至少我之前完全没有想过)。

    这里我们感性的认识一下辗转相除法(不是很严格地证明一下)。

    假设两个数a,b且a>b。 设a除以b商k,余数为r,那么会有a=k*b+r,那么b和r的最大公约数,就是a和b的最大公约数。所以问题就转换求成除数和余数的最大公约数,依次递归,递归的出口就是一个已知的条件:如果a能够被b整除,那么b就是a和b的最大公约数,所以辗转相除法递归代码如下:

    int GCD1(int num1,int num2)
    {
       if(num1%num2==0)
       {
        return num2;
       }
       else
       {
        int next1=num2;
        int next2=num1%num2;
        return GCD1(next1,next2);
        }
    }

    还有一种我们耳熟能详的求最大公约数的算法就是更相减损术,他的基本思想就是:两个数a,b且a>b,那么令c=a-b,然后把 b和c看成新的a和b,递归下去,递归出口就是一个已知的条件:如果a=b,那么a和b的最大公约数就是a或b。其实更相减损术和辗转相除法是一个东东,更相减损术就是让辗转相除法中的商(k)恒为1,所以大多数情况下,辗转相除法的效率要比更相减损术的效率高。给出更相减损术的代码:

    int GCD2(int num1,int num2)
    {
       if(num1==num2)
       {
          return num2;
       }
       else
      {
          int next1=  (num1>num2)? (num1-num2):(num2-num1);
          int next2= (num1>num2)?num2:num1;
          if(next1>next2)
          {
           return GCD2(next1,next2);
          }
          else
          {
             return GCD2(next2,next1);
          }
        }
    }

    好了,步入这次的正题:多个数求最大公约数(实际上就是辗转相除法的扩展)给出算法:

    设一组数a1,a2,a3,a4,a5..

    (1)对这一组数进行排序(从大到小)

    (2)对每两个相邻的两个数进行如下操作:

        设相邻的两个数为A和B(A在前,因为已经排序,所以A>B),如果A=n*B(n为整数),也就是A能够被B整除,那么就令A=B;如果A不能被B整除则令A=A%B。

    (3)重复(1)、(2)知道数组中每个数都相等,则最大公约数就为这个数。

     

    给出完整程序:

    #include<iostream>
    using namespace std;
    void Sort(int* num,int n);
    int GCD3(const int* num,int n);
    int main()
    {

       int num[4]={756,504,630,2226};
       int result=GCD3(num,4);
       cout<<"数组:";
       for(int i=0;i<4;i++)
       {
          cout<<num[i]<<"  ";
       }
       cout<<"的最大公约数为:"<<result<<endl;
       return 0;
    }

    int GCD3(const int* num,int n)
    {
       int *temp=new int[n];
       for(int i=0;i<n;i++)
       {
          temp[i]=num[i];
       }
       do
       { 
          if(temp[0]==temp[n-1])
          {
             break;
          }
          else
          {
             Sort(temp,n);//排序
             for(int i=0;i<n-1;i++)
             {
                if(temp[i]%temp[i+1]==0)
                {
                   temp[i]=temp[i+1];
                }
                else
                {
                   temp[i]=temp[i]%temp[i+1];
                }
             }
          }
       }while(temp[0]!=temp[n-1]);
       return temp[0];
    }

    //排序
    void Sort(int* num,int n)
    {

      //冒泡排序法
       for(int i=0;i<n-1;i++)
       {
          for(int j=i;j<n-1;j++)
          {
             if(num[i]<num[j+1])
             {
                int temp=num[i];
                num[i]=num[j+1];
                num[j+1]=temp;
             }
          }
        }
    }

    ---恢复内容结束---

  • 相关阅读:
    java volatile关键字解惑
    Java 反射
    拷贝源实体类到目标实体类中
    Bean和Map之间的转换
    DateUtils时间的封装
    HttpClient的代码封装,便于直接调用
    HttpClient语法
    LinkedHashMap+ConcurrentHashMap+hashMap的区别
    1006 Tick and Tick
    Event Flow
  • 原文地址:https://www.cnblogs.com/qingergege/p/4992990.html
Copyright © 2020-2023  润新知