四种算法实现最大公约数并机计算运行时间

一、题目:求一组数的最大公约数
            题目要求:
            分别采用 :
             <1>辗转相除法 (非递归和递归),
             <2>穷举法,
             <3>更相减损法,
            <4>Stein算法(非递归和递归)
            计算一组数据求得最大公约数,并对各种算法的运行时间进行比较。
            首先需要知道:假设两个数A、B的最大公约数为k,那么(A-B)、(A%B)的值也肯定是k的倍数。
    二、算法分析
   <1>、辗转相除法
           辗转相除法(又名欧几里德法)C语言中用于计算两个正整数a,b的最大公约数和最小公倍数,实质它依赖于下面的定理:
           两个正整数a、b (a>b),它们的最大公约数等于 a 除以 b 的余数 c 和 b 之间的最大公约数。
           其算法过程为:
           前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数
           1、大数放a中、小数放b中;
           2、求a/b的余数;
           3、若temp=0则b为最大公约数;
           4、如果temp!=0则把b的值给a、temp的值给a;
           5、返回第二步;
       
 <2>、穷举法(利用数学定义)
         穷举法(也叫枚举法)穷举法求两个正整数的最大公约数的解题步骤:
         从两个数中较小数开始由大到小列举,直到找到公约数立即中断列举,得到的公约数便是最大公约数 。
         ①定义1:对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。
         ②定义2:对两个正整数a,b,如果若干个a之和或b之和能被b所整除或能被a所整除,则该和数即为所求的最小公倍数。
<3>、 更相减损法
         第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
         第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
         则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。
<4>、Stein算法    
         对两个正整数 x>y :
       (1)、均为偶数 gcd( x,y ) =2gcd( x/2,y/2 );
       (2)、均为奇数 gcd( x,y ) = gcd( (x+y)/2,(x-y)/2 );
       (3)、x奇y偶   gcd( x,y ) = gcd( x,y/2 );
       (4)、x偶y奇   gcd( x,y ) = gcd( x/2,y )  或 gcd( x,y )=gcd( y,x/2 );
        现在已经有了递归式,还需要再找出一个退化情况。注意到 gcd( x,x ) = x ,就用这个。

在这里插入代码片
#include<stdio.h>
#incl

ude<math.h>
#include<time.h>
#include<windows.h>
int num[1000][2],  grop=20,  out[6][1000];
//out[6][1000]存储组大公约数,6表示6个算法函数。grop表示有20组数据。num[1000][2]存放20组数据。
//辗转相除法
int divisor1(int a,int b)         //自定义函数求两数的最大公约数
{
    int temp ;
    if( a < b )                  //使得a必须大于b 
    {
        temp = b ;
        b = a ;
        a = temp ;
    }
    while(b!=0)
    {
        temp = a % b ;
        a = b ;
        b = temp ;
    } 
    return ( a ) ;                      //返回最大公约数
 }
int gcd ( int a, int b )                //辗转相除法的函数递归调用
{
    if ( a % b == 0 )
         return b ;
    else
         return gcd ( b, a % b ) ;
}
//穷举法
int divisor2(int a,int b)             
{
      int    temp;
      temp = ( a > b ) ? b : a ;
      while ( temp > 0 )
      {
           if ( a % temp == 0 && b % temp == 0 )
                break ;
           temp--;
      }
      return (temp);
} 
int gcd1 ( int m, int n )                   //更相减损法
{
     int i = 0, temp, x ;
     while ( m % 2 == 0 && n % 2 == 0 )
     {
           m / = 2 ;
           n / = 2 ;
           i + = 1 ;
     }
    if ( m < n )
    { 
          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 ; 
 } 
 //Stein算法 
int Stein ( unsigned int x, unsigned int y )            //函数非递归调用
 {
      int factor=0,temp;
      if ( x < y )
     {
            temp = x ;
            x = y ;
            y = temp ;
     }
     if ( y == 0 )  
           return x ;
     while ( x != y )
     {
         if( x & 0x 1)
         {
             if( y & 0x1)
             {
                  y = ( x -y ) >> 1 ;
                  x -=y ;
             }
             else
             {
                   y >>= 1 ;
             }
         }
         else
         {
              if( y & 0x1 )
              {
                     x >>= 1 ;
                     if ( x < y )
                     {
                           temp = x ;
                           x = y ;
                          y = temp ; 
                     }
               }
               else
               {
                     x >>= 1 ;
                     y >>= 1 ;
                     factor ++ ; 
               }
         }
      }
      return (x<<factor);
  } 
 int gcd2( int  u, int  v)              //函数递归调用
  {
         if ( u == 0 )   return v ;
         if ( v == 0)    return u ;
         if ( ~u & 1)
          {
                if ( v & 1)
                        return gcd2 ( u >> 1, v ) ;
                else
                        return gcd2 ( u >> 1, v >> 1 ) << 1 ;
         } 
         if ( ~v & 1)
                 return gcd2 ( u, v >> 1) ; 
         if ( u > v ) 
                 return gcd2 ( ( u - v )  >> 1 , v ) ;
        return gcd2 ( ( v - u ) >> 1, u) ;
  }
int Create()                  //产生20组随机正整数 
{ 
   int h=10,t=100 ;
   for( int i = 0;  i < grop; i++ )
   {
        for(int j=0; j<2;j++)
        {   
            srand ( time ( NULL ) ) ;
            num[i][j] = rand() % ( t-h+1 ) + h ;
             h += 30 ;    t += 50 ;
         }
         h += 100 ;   t += 100 ;
    } 
   return 0;
}
void show()
{  int option, k=0;
   clock_t start, finish;
   double TheTimes;
   printf("-----------------------\n");
   printf("     1、辗转相除法     \n");
   printf("     2、穷举法         \n");
   printf("     3、更相减损法     \n");
   printf("     4、Stein算法      \n");
   printf("-----------------------\n"); 
   for( int j = 0; j < 6; j ++ )
   {  
    start = clock () ;             
    k=0;
       for(int i=0; i<grop; i++)
       {   
        switch(j+1)
           {  
                case 1 :
                        out[0][k]= divisor1 (num[i][0],num[i][1]);                     
                     break;
                case 2 :
                        out[1][k]= gcd (num[i][0],num[i][1]);                        
                        break;
                case 3 :
                        out[2][k]= divisor2 (num[i][0],num[i][1]);                        
                        break;
                case 4 :                        
                        out[3][k]= gcd1(num[i][0],num[i][1]);
                        break;
                case 5 :  
                     out[4][k]= Stein (num[i][0],num[i][1]);
                        break;
                case 6 :
                     out[5][k]= gcd2 (num[i][0],num[i][1]);
                        break;
              
        } 
     printf("第%d组数据的最大公约数: %d  ",i+1,out[j][k]);
     if((i+1)%2==0)
        printf("\n");
        k++;
       }  
    finish = clock(); 
    TheTimes = static_cast<double>(finish-start)/CLOCKS_PER_SEC;     //计算时间 
    printf("第%d种算法所用时间:%lf s\n\n\n\n\n",j+1,TheTimes); 
 }    
 
}
int main()
{  Create () ;
    for( int i=0; i<grop; i++)
    printf( "%d %d\n", num[i][0], num[i][1] );
    show () ;
    return 0; 
} 

四种算法实现最大公约数并机计算运行时间
四种算法实现最大公约数并机计算运行时间
四种算法实现最大公约数并机计算运行时间
四种算法实现最大公约数并机计算运行时间
四、经验归纳遇到的问题:
start=clock();
······
finish = clock();
TheTimes = static_cast((finish-start)/CLOCKS_PER_SEC);
输出的 TheTime 总是 0.0000000 s
解决方案:去掉一对括号,
使成为:TheTimes = static_cast(finish-start)/CLOCKS_PER_SEC;
原因:括号改变了运算的优先级
clock()返回类型为clock_t类型;
clock_t实际为long类型,typedef long clock_t;
CLOCKS_PER_SEC:表示一秒钟会有多少个时钟计时单元,也就是硬件滴答数。