通过计算运行时间比较几种求最大公约数的方法

1.题目分析
分别用辗转相除法、穷举法、更相减损法、stein算法求最大公约数,并测试比较几种算法在不同规模测试数据下的平均运行时间。
2.算法构造(流程图)
辗转相除法(函数嵌套)
辗转相除法(函数递归调用)
穷举法
更相减损术
Stein算法

3.算法实现
(1)辗转相除法的函数嵌套调用实现

int  divisor (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);            /*返回最大公约数到调用函数处*/ 
    }

2)辗转相除法的函数递归调用

int  gcd (int a,int b)
{
	 if(a%b==0)
                  return b;   
	else  
                return gcd(b,a%b);
  }

(3)穷举法:

int  divisor (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); /*返回满足条件的数到主调函数处*/
           }

(4)更相减损术

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;
}

(5)Stein算法非递归实现

int Stein( 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 );
}

(6)Stein算法递归实现

	int gcd(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	gcd(u >> 1, v);
                     	 else                          		  // both u and v are even
 			 return  gcd(u >> 1, v >> 1) << 1;
                    }
                 if (~v & 1) // u is odd, v is even
                             return gcd(u, v >> 1);
                 //reduce larger argument
                    if(u > v)
                             return gcd((u - v) >> 1, v);
                   return gcd((v - u) >> 1, u);
	}

具体实现:

#include<iostream>		//主函数通过调用gcd函数,测算时间
#include"stdio.h"
#include<windows.h>
using namespace std;
LONGLONG GetLastTime()
{
 // CPU频率
	 LARGE_INTEGER liQPF;
 // 记录开始和结束时间
	 LARGE_INTEGER liStartTime, liEndTime;
 // 记录过程时间
	 LONGLONG llLastTime;
 // 获取CPU频率
 	QueryPerformanceFrequency(&liQPF);
 // 获取开始时间
	 QueryPerformanceCounter(&liStartTime);
	 Sleep(10);
 // 获取结束时间
	 QueryPerformanceCounter(&liEndTime);
 // 计算持续时间(us)
	 llLastTime = 1000000 * (liEndTime.QuadPart - liStartTime.QuadPart) / liQPF.QuadPart;
 	return llLastTime;
}
int IsInteger(int a)//判断输入是否合法
{
	 if(a%1==0)
 		 return 1;
	 return 0;
}

int main()
{
 //定义两个数组,存放测试数据
 int a[20] ={10032,24534,32323,4738,534345,645426,24456,8536,9632,10364,1231,23353,45352,345245,3245234,5923,45234,559,234,56765 	};
 int b[20]= { 234234,252344,374328,412432,53343224,664245,743425,84426,9643254,1340654,123,234,56,455,456,45,56,435,345,345 };
	 for (int i = 0; i < 20; i++)
	 {
  		if(!(IsInteger(a[i])&&IsInteger(b[i])))
	 	 { 
   			cout<<"非法输入!";
   			exit(1);
		  }
		  cout <<"最大公约数:" <<gcd(a[i], b[i]) << "\t";
	 	 cout << "运行时间:" <<  GetLastTime() << "us" << endl; 
	 }
	 system("pause");
	 return 0;
}

4.调试、测试及运行结果
使用gettickcount();方法效果:在这里插入图片描述
优化后的效果:在这里插入图片描述
测试及调试:在这里插入图片描述
在这里插入图片描述
比较结果:
在这里插入图片描述

5.经验归纳
在这次程序设计中,通过对几种不同的求最大公约数算法的比较学习中。更明显感受到几种算法各自的优点。欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来。Stein算法提供了一个优化的方法。总结两种计算时间的方法:方法一:gettickcount();这个函数并不需要开始,任何时候,调用它就会得到一个时间值,这个时间值是从开机到现在的毫秒数。头文件Windows.h。而与其相关的数据类型是DWORD 方法二:clock();用于计算该程序从启动到函数调用占用CPU的时间;精度为毫秒,头文件:time.h/ctime,与其相关的数据类型是clock_t。另外,在求算法运行时间的过程中,发现有些测试数据运算的时间为0ms,计算时间太短,
解决方法:(1),增多数据求平均值(2),精确计算时间的技术(这里用us),我用第二种方法,通过使用更加精确的方法来求时间; 获得应用程序中精确获取系统时间,则使用下面函数QueryPerformanceCounter(IN OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL);但这是获取CPU频率就需要下面这个函数了:QueryPerformanceFrequency(IN OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL);

猜你喜欢

转载自blog.csdn.net/qq_44002167/article/details/88598851