标签:
---恢复内容开始---
最近在看一本算法的书。讲的都是一些基本的问题,并没有涉及很复杂的算法,或者说这本书更看重技巧。
其中开篇就讲了最大公约数的算法,觉得有可取之处,和大家分享一下。
提到最大公约数我们最先想到的一定是辗转相除法。
没错,永远不要蔑视我们的祖先,他们的智慧是无穷的。(扯远了,嘿嘿)
我们都在用辗转相除法来求最大公约数,却很少去想为什么辗转相除法就能求最大公约数呢?或者说怎么证明算法的正确性呢(至少我之前完全没有想过)。
这里我们感性的认识一下辗转相除法(不是很严格地证明一下)。
假设两个数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;
}
}
}
}
---恢复内容结束---
标签:
原文地址:http://www.cnblogs.com/qingergege/p/4992990.html