一.题目名称:用不同的算法求最大公约数。
二.题目背景:通过使用“辗转相除法”“穷举法”“更相减损法”“Stein算法”来计算最大公因数,并且比较四种方法各自使用的时间。
三.题目分析:不同的方法有不同的解题步骤与思路,此题要求用四种不同的算法来计算最大公因数并且进行时间比较,我的想法是利用一个主函数分别调用四个函数算法,定义一个时间函数来计算时间,初始化一个随机数序列方便测试,因为四种算法是用两个整型数进行比较,而若要进行时间比较,一组数据是远远不够的,所以我的想法是,定义一个函数,将产生的随机数保存在一个数组内存在函数中,再逐个的进行运用与调用来完成时间比较。
四.所用方法
1.辗转相除法
算法过程:1.设两数为a,b设其中a做被除数,b做除数,t为余数
2.较大值存于a,较小值存于b
3.求a%b的余数赋值于t;
4.若t=0则b为最大公约数;
5.如果t!=0,则将b的值赋给a、b的值赋给t,返回第二步后再次进行计算。
算法代码:
void divisor1(int a,int b)
{
int t; //定义一个整型变量
if(a<b) //判断输入a,b的大小
{
t=a;a=b;b=t; //交换大小
}
while(b!=0)
{
t=a%b; //求余
a=b; //互换
b=t;
}
cout<<"the highest common divisor is "<<a<<endl;
}
算法流程图:
2.穷举法
算法过程:1.设两数为a,b,并且定义一个t;
2.比较a,b大小,将较小值赋给t;
3.若t大于0,则进行判断,截止条件为当a,b同时将t整除时,t为最大公因数;
4.若不符合截止条件,则t进行递减继续进行第三步。
算法代码:
void divisor2(int a,int b)
{
int t;
t=(a>b)?b:a; //将较小值赋给t
while(t>0)
{
if(a%t==0 && b%t==0) //截止条件为a,b同时可以将t整除
{
break;
}
t--; //t递减直到可以整除为止
}
cout<<"the highest common divisor is "<<t<<endl;
}
算法流程图:
3.更相减损法
算法过程:1.设两数为a,b,并且定义i为0,t,x;
2.给定两个整数,判断他们是否都是整数,若为整数,则用2约简,并且记录约简次数i内,若不是则继续进行;
3.判断a,b的大小,较大值赋给a,较小值赋给b;
4.设x为较大值减去较小值之差,若x大于0,利用b与x比较大小,较大值赋给a,较小值赋给b,若b与x相等则输出判断,若i为0,则b为最大公因数,若i不为0,则最大公因数为(2^i)*b;
5,若b与x不相等,则继续进行第四步,直到输出。
算法代码:
void gcd(int a,int b)
{
int i=0,t,x;
while(a%2==0 && b%2==0) // 判断a,b能被多少个2整除
{
a/=2;
b/=2;
i+=1;
}
if(a<b) //判定a,b的大小,较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
while(x)
{
x=a-b;
a=(b>x)?b:x; //将较大值赋给a
b=(b<x)?b:x; //将较小值赋给b
if(b==(a-b))
break;
}
if(i==0)
cout<<"the highest common divisor is "<<b<<endl;
else
cout<<"the highest common divisor is "<<(int)pow(2,i)*b<<endl; //pow(2,i)函数意义为2^i
}
算法流程图:
4.Stein算法
算法过程:1.定义两个整型无符号数a,b,并且定义factor为0,t;
2.判断a,b的大小,较大值赋给a,较小值赋给b;
3.判断b是否为0,若为0则最大公因数为0,若b不是0,则继续进行;
4.若a不等于b,则进行判断,分别判断a偶b偶,a偶b奇,a奇b偶,a奇b奇四种形式,(当a,b都为偶时,factor进行递增),直到a等于b是,最大公因数为a向左移动factor个距离。
算法代码:
void Stein(unsigned int a,unsigned int b)
{
int factor=0;
int t;
if(a<b) //判断a,b的大小,将较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
if(b==0)
{
cout<<0<<endl; //如果b为0,则输出
}
while (a!=b)
{
if(a & 0x1) //判断a是否为奇数,相当于取a的二进制中最右边的数字
{
if(b & 0x1) //判断b是否为奇数,相当于取b的二进制中最右边的数字
{
b=(a-b)>>1; // >>是右移运算符
a-=b;
}
else
{
b>>=1; // ">>="为右移后赋值运算符 相当于 b=b>>1
}
}
else
{
if(b & 0x1)
{
a>>=1;
if(a<b) //进行判断,将较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
}
else
{
a>>=1;
b>>=1;
++factor;
}
}
}
cout<<"the highest common divisor is "<<(a<<factor)<<endl;
}
算法流程图:
五.程序源代码
#include <iostream.h>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <stdlib.h>
#define N 5
int divisor1(int m,int n);
int divisor2(int m,int n);
int gcd(int m,int n);
int Stein(unsigned int m,unsigned int n);
void array1(int a[],int b[]);
void main()
{
int i,j;
int arr[N],brr[N],arr_s[N],brr_s[N]; //前两个用于计算,后两个用于备份
srand(time(0)); //初始化一个随机数序列,为了随机,一般用time(0)
for (i = 0; i<N; i++)
arr_s[i] = rand()%1000; //从随机数序列中依次抓取一个正整数 0到1000区间内
for (j = 0; j<N; j++)
brr_s[j] = rand()%1000;
clock_t start,finish; //定义时间函数
int Time[4];
int input; //输入数据
do
{
cout<<"********************************"<<endl;
cout<<"1--辗转相除法 2--穷举法"<<endl;
cout<<"3--更相减损法 4--Stein算法"<<endl;
cout<<"0--退出 "<<endl;
cout<<"********************************"<<endl;
cout<<"please input a number:"<<endl;
cin>>input;
for (i = 0; i<N; i++)
arr[i] = arr_s[i]; //复制一份数组用于计算
for (j = 0; j<N; j++)
brr[j] = brr_s[j];
switch(input) //选择所要查看的方法
{
case 1:
cout<<"辗转相除法"<<endl;
start=clock();
array1(arr,brr);
finish=clock();
Time[input]=finish-start;
cout<<"The 辗转反侧法 run time of the computer is "<<Time[input]<<"ms"<<endl;
break;
case 2:
cout<<"穷举法"<<endl;
start=clock();
array1(arr,brr);
finish=clock();
Time[input]=finish-start;
cout<<"The 穷举法 run time of the computer is "<<Time[input]<<"ms"<<endl;
break;
case 3:
cout<<"更相减损法"<<endl;
start=clock();
array1(arr,brr);
finish=clock();
Time[input]=finish-start;
cout<<"The 更相减损法 run time of the computer is "<<Time[input]<<"ms"<<endl;
break;
case 4:
cout<<"Stein算法"<<endl;
start=clock();
array1(arr,brr);
finish=clock();
Time[input]=finish-start;
cout<<"The Stein算法 run time of the computer is "<<Time[input]<<"ms"<<endl;
break;
case 0:
break;
default:
break;
}
if(input!=0 && input!=1 && input!=2 && input!=3 && input!=4)
{
cout<<"wrong input"<<endl;
}
}while(input);
}
void array1(int a[],int b[]) //重新定义一个函数,将数组保存在内
{
int m,n,i,j,x,t;
cout<<"please input a number"<<endl;
cin>>x;
if(i<N && j<N)
{
for(i=0;i<N;i++)
{
m=a[i]; //将a[i]的数值保存在m中
cout<<"m["<<i<<"]="<<m<<endl;
for(j=0;j<N;j++)
{
n=b[j]; //将b[j]的数值保存在n中
cout<<"n["<<j<<"]="<<n<<endl;
if(x==1)
{
divisor1(m,n);
}
else if(x==2)
{
divisor2(m,n);
}
else if(x==3)
{
gcd(m,n);
}
else if(x==4)
{
Stein(m,n);
}
}
}
}
}
//辗转相除法
int divisor1(int a,int b)
{
int t; //定义一个整型变量
if(a<b) //判断输入a,b的大小
{
t=a;a=b;b=t; //交换大小
}
while(b!=0)
{
t=a%b; //求余
a=b; //互换
b=t;
}
cout<<"the highest common divisor is "<<a<<endl;
return(0);
}
//穷举法
int divisor2(int a,int b)
{
int t;
t=(a>b)?b:a; //将较小值赋给t
while(t>0)
{
if(a%t==0 && b%t==0) //截止条件为a,b同时可以将t整除
{
break;
}
t--; //t递减直到可以整除为止
}
cout<<"the highest common divisor is "<<t<<endl;
return(0);
}
//更相减损法
int gcd(int a,int b)
{
int i=0,t,x;
while(a%2==0 && b%2==0) // 判断a,b能被多少个2整除
{
a/=2;
b/=2;
i+=1;
}
if(a<b) //判定a,b的大小,较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
while(x)
{
x=a-b;
a=(b>x)?b:x; //将较大值赋给a
b=(b<x)?b:x; //将较小值赋给b
if(b==(a-b))
break;
}
if(i==0)
cout<<"the highest common divisor is "<<b<<endl;
else
cout<<"the highest common divisor is "<<(int)pow(2,i)*b<<endl; //pow(2,i)函数意义为2^i
return 0;
}
//Stein算法
int Stein(unsigned int a,unsigned int b)
{
int factor=0;
int t;
if(a<b) //判断a,b的大小,将较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
if(b==0)
{
cout<<0<<endl; //如果b为0,则输出
}
while (a!=b)
{
if(a & 0x1) //判断a是否为奇数,相当于取a的二进制中最右边的数字
{
if(b & 0x1) //判断b是否为奇数,相当于取b的二进制中最右边的数字
{
b=(a-b)>>1; // >>是右移运算符
a-=b;
}
else
{
b>>=1; // ">>="为右移后赋值运算符 相当于 b=b>>1
}
}
else
{
if(b & 0x1)
{
a>>=1;
if(a<b) //进行判断,将较大值赋给a,较小值赋给b
{
t=a;
a=b;
b=t;
}
}
else
{
a>>=1;
b>>=1;
++factor;
}
}
}
cout<<"the highest common divisor is "<<(a<<factor)<<endl;
return(0);
}
六.验证.测试及调试
1.验证
我的想法是提前定义一个数组,将随机数存入数组中,在一个一个赋值给m和n,为了保证验证准确性,每一组数的数值都相同,四种方法所用到的数字都是相同的,不存在不同的算法有不同的随机数。
我提前定义一个N,通过循环得到每一组m和n,具体在代码中,所以每定义一个N都意味着有N^2组数据进行验证。
2.测试(验证每种方法是否可用)
1)辗转相除法
图一
2)穷举法
图二
3)更相减损法
图三
4)Stein算法
图四
测试结果:将四种算法分别进行了验证,都可以成功的输出结果,且结果均正确,接下来将四种算法合并到一个程序中进行验算以及调试。
3.调试
调试时我定义N为2,这样方便调试
图五
图六
图七
图八
图九
七.总结
就四种算法的时间比较看来,当数据越多,更相减损法和Stein算法花费的
时间较少。
整段代码还存在着一些问题,像定义一个N时需要去重新改正,调用函数的时候可能过于麻烦,接下来还需要时间去研究学习一些方法去优化。
这个代码整体不算复杂,每一步都有相对应的程序代码,但是为了更好地掌握还是需要时间去研究。