最大公约数几种算法分析

程序设计方法学上机——(一)

 

  • 题目:

运行最大公约数的常用算法,进行程序的调试与测试,要求程序设计风良好,并添加异常处理模块(如非法输入)。

 

  1. 辗转相除法:

其算法过程为: 前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数

==>大数放a中、小数放b中;

==>求a/b的余数;

==>若temp=0则b为最大公约数;

==>如果temp!=0则把b的值给a、temp的值给a;

==>返回第二步;

(1)非递归

(2)递归

  1. 穷举法:

穷举法(也叫枚举法)穷举法求两个正整数的最大公约数的解题步骤:从两个数中较小数开始由大到小列举,直到找到公约数立即中断列举,得到的公约数便是最大公约数 。

  1. 更相减损法:

==>任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。

==>以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。

则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。

其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。

  1. Stein算法

对两个正整数 x>y :

1.均为偶数 gcd( x,y ) =2gcd( x/2,y/2 );

2.均为奇数 gcd( x,y ) = gcd( (x+y)/2,(x-y)/2 );

2.x奇y偶   gcd( x,y ) = gcd( x,y/2 );

3.x偶y奇   gcd( x,y ) = gcd( x/2,y )  或 gcd( x,y )=gcd( y,x/2 );

现在已经有了递归式,还需要再找出一个退化情况。注意到 gcd( x,x ) = x ,就用这个。

  1. 非递归
  2. 递归
  • 算法构造:
  1. 辗转相除流程图:

(1)非递归:

 

(2)递归:

 

 

 

  1. 穷举法流程图:

 

 

  1. 更相减损法流程图:

 

  1. Stein算法流程图:
  1. 非递归:

 

  1. 递归:

 

  • 算法实现:(源码)
  1. 辗转相除法:

(1)非递归:

//辗转相除法

/*函数嵌套调用*/



#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<time.h>

#include<windows.h>



int GCD (int a,int b)    /*自定义函数求两数的最大公约数*/

{

  int  temp;          /*定义整型变量,用于交换变量时做临时变量*/

  if(a<b)             /*通过比较求出两个数中的最大值和最小值*/

    { temp=a;a=b;b=temp;} /*设置中间变量进行两数交换*/

   while(b!=0)           /*通过循环求两数的余数,直到余数为0*/

    {

      temp=a%b;

      a=b;              /*变量数值交换*/

      b=temp;

    }

  return (a);            /*返回最大公约数到调用函数处*/

}





int main()

{

/*计时函数所需定义语句*/

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd; /*公约数*/

 int i,a[100001],b[100001]; /*定义两个数组*/

 srand(1);                  /*随机函数*/

 for(i=0;i<20;i++)         /*循环来控制数据规模*/

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }

 QueryPerformanceCounter(&time_start);

for(i=0;i<20;i++)

{

  gcd=GCD(a[i],b[i]);    /*自定义函数*/

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/

  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);

 return 0;

}
  1. 递归:
//辗转相除法

/*函数递归*/





#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<windows.h>



int GCD (int a,int b) /*自定义函数求两数的最大公约数*/

{  if(a%b==0) /*看b是否是最大公约*/

       return b;

else

       return GCD(b,a%b);

}



int main() /*主函数*/

{

/*计时函数所需定义语句*/

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd; /*变量用于存最大公约数*/

 int i,a[100001],b[100001]; /*定义两个数组*/



 srand(10);                     /*随机函数*/

 for(i=0;i<100000;i++)

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }



 QueryPerformanceCounter(&time_start);

for(i=0;i<100000;i++)

{



  gcd=GCD(a[i],b[i]);           /*自定义主调函数*/

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/



  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);





 return 0;

}

 

 

  1. 穷举法:
//穷举法

#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<time.h>

#include<windows.h>

#include<math.h>

int GCD (int a,int b) /*自定义函数求两数的最大公约数*/

{

    int  temp;          /*定义义整型变量*/

    temp=(a>b)?b:a;    /*采种条件运算表达式求出两个数中的最小值*/

    while(temp>0)

    {

       if (a%temp==0&&b%temp==0) /*只要找到一个数能同时被a,b所整除,则中止循环*/

          break;

       temp--;      /*如不满足if条件则变量自减,直到能被a,b所整除*/

    }

  return (temp); /*返回满足条件的数到主调函数处*/

}



int main()

{

/*计时函数所需定义语句*/

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd; /*变量用于存最大公约数*/

 int i,a[100001],b[100001];     /*定义两个数组*/



 srand(10);                     /*随机函数*/

 for(i=0;i<100000;i++) /*通过循环输入规模*/

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }



 QueryPerformanceCounter(&time_start);

for(i=0;i<100000;i++)

{



  gcd=GCD(a[i],b[i]); /*自定义主调函数*/

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/

  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);





 return 0;

}

 

  1. 更相减损:
//更相减损



#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<time.h>

#include<windows.h>

#include<math.h>

int GCD(int m,int n)

{

int i=0,temp,x;

while(m%2==0 && n%2==0)  //判断m和n能被多少个2整除

{

m/=2;

n/=2;

i+=1;

}

if(m<n)     //m保存大的值

{

temp=m;

m=n;

n=temp;

}

while(x)

{

x=m-n;

m=(n>x)?n:x;

n=(n<x)?n:x;

if(n==(m-n))

break;

}

if(i==0)

return n;

else

return (int )pow(2,i)*n;

}

int main()

{

//计时函数所需的定义语句

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd; //定义变量用于存放最大公约数

 int i,a[100001],b[100001];//定义两个数组



 srand(10);      //随机函数

 for(i=0;i<100000;i++) //通过循环控制规模

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }

 QueryPerformanceCounter(&time_start);

for(i=0;i<100000;i++)

{



  gcd=GCD(a[i],b[i]); //自定义主调函数

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/

  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);





 return 0;

}

 

  1. Stein算法:
  1. 非递归:
 //stein

 /*非递归*/

#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<time.h>

#include<windows.h>

#include<math.h>





 int SteinGCD( unsigned int x, unsigned int y )

  /* return the greatest common divisor of x and y */

{

        int factor = 0;

        int temp;

        if ( x < y )

        {

                temp = x;

                x = y;

                y = temp;

        }

        if ( 0 == y )

        {

                return 0;

        }

        while ( x != y )

        {

                if ( x & 0x1 )

                {/* when x is odd */

                        if ( y & 0x1 )

                        {/* when x and y are both odd */

                                y = ( x - y ) >> 1;

                                x -= y;

                        }

                        else

                        {/* when x is odd and y is even */

                                y >>= 1;

                        }

                }

                else

                {/* when x is even */

                        if ( y & 0x1 )

                        {/* when x is even and y is odd */

                                x >>= 1;

                                if ( x < y )

                                {

                                        temp = x;

                                        x = y;

                                        y = temp;

                                }

                        }

                        else

                        {/* when x and y are both even */

                                x >>= 1;

                                y >>= 1;

                                ++factor;

                        }

                }

        }

        return ( x << factor );

}



int main()

{

//计时函数所需要定义的语句

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd;//定义变量用于存放最大公约数

 int i,a[100001],b[100001];//定义两个数组



 srand(10);   //随机函数

 for(i=0;i<100000;i++)//通过循环控制规模

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }



 QueryPerformanceCounter(&time_start);

for(i=0;i<100000;i++)

{



  gcd=SteinGCD(a[i],b[i]);

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/

  //printf("所需时间%f\n",(double)(end-start)/CLOCKS_PER_SEC);

  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);





 return 0;

}

  1. 递归:
//stein

/*递归实现*/

#include<stdio.h>  /*输入输出类头文件*/

#include<stdlib.h>

#include<time.h>

#include<windows.h>

#include<math.h>

int SteinGCD(int u,int v)

{

    if (u == 0) return v;

    if (v == 0) return u;

    // look for factors of 2

    if (~u & 1) // u is even

    {

        if (v & 1) // v is odd

            return SteinGCD(u >> 1, v);

        else // both u and v are even

            return SteinGCD(u >> 1, v >> 1) << 1;

    }

     if (~v & 1) // u is odd, v is even

        return SteinGCD(u, v >> 1);

     // reduce larger argument

    if (u > v)

        return SteinGCD((u - v) >> 1, v);

     return SteinGCD((v - u) >> 1, u);

}

int main()

{

//计时函数所需要定义的语句

double dur;

LARGE_INTEGER time_start;

LARGE_INTEGER time_over;

double dqFreq;

LARGE_INTEGER f;

QueryPerformanceFrequency(&f);

dqFreq=(double)f.QuadPart;



 int gcd;//定义变量用于存放最大公约数

 int i,a[100001],b[100001];//定义两个数组



 srand(10);   //随机函数

 for(i=0;i<100000;i++)//通过循环控制规模

 {

  a[i]=1+rand()%100;

  b[i]=1+rand()%100;

 }



 QueryPerformanceCounter(&time_start);

for(i=0;i<100000;i++)

{



  gcd=SteinGCD(a[i],b[i]);

  printf("随机数为%d,%d",a[i],b[i]);

  printf("这两个整数的最大公约数是 %d\n\n",gcd);  /*输出最大公约数*/

  //printf("所需时间%f\n",(double)(end-start)/CLOCKS_PER_SEC);

  QueryPerformanceCounter(&time_over);

  dur=(time_over.QuadPart-time_start.QuadPart)/dqFreq;

}

printf("所需时间%f seconds\n",dur);





 return 0;

}

 

  • 调试、测试:
  1. 调试:
  1. 随机数调试:(以3组数据为例)

 

===>观察a[i],b[i]当i在变化是每次的不同随机数,此时为未开始,二者为0;

 

===>i=0时,a[i]=72,b[i]=100

 

 

===>i=1时,a[i]=73,b[i]=95

 

===>i=2,a[i]=98,b[i]=97

 

 

 

  1. 测试:

 

--Stein递归--

 

 

 

--Stein非递归--

 

 

--更相减损--

 

--穷举法--

 

 

--辗转相除递归--

 

 

--辗转相除非递归--

  • 分析:

 

 

--测试时间的表格结果--

  1. 6种算法比较:规模相同,数据范围相同:

在100组数据和1000组数据:辗转相除非递归算法效率比较高;

在10000组数据:stein算法效率较高

 

 

  1. 同一种算法比较,数据范围不同时,运行时间的变化幅度:

对于6种方法,当规模相同,随着随机数的范围不同,运行时间都有所增加,其中辗转相除非递归增加最为明显,

 

  • 总结:

本程序运用六种代码来测试效率,采取了平均值来避免偶然性误差。

 

本实验为了测试求最大公约数的算法效率,在实验过程中,遇到了一些问题。

  1. 刚开始手动输入两位两位数据,发现效率低且不能进行大规模数据测试
  2. 计时函数在用的时候是在网上看了一些程序采用到本程序上

不足:

  1. 测试数据没有实现数据为0时求公约数
  2. 每次运行时间差异较大,没有找到原因所在
  3. 感觉数据测试不是很准确,数据规模范围没有达到比较好的地步

 


如果有什么错误请各位大神指出来,完成之后记得撒花撒花~~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值