程序设计方法与优化第二次作业

 

实验报告

一、题目分析

本次题目是探讨求两个数的最大公约数的算法,并比较各种算法的在不同规模测试数据下的平均运行时间,以此评定各种算法的效率。

二、算法构造

流程图:

辗转相除法(函数嵌套调用):

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

穷举法:

更相减损法:

Stein算法函数非递归调用):

Stein算法(函数递归调用):

 

三、算法实现

Java

package package1;

 

public class Example {

   //辗转相除法(函数嵌套调用)

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

   }

   //辗转相除法(函数递归调用)

   public static int gcdFirst (int a,int b)

   {  if(a%b==0)//递归调用自身知道满足条件并返回最大公约数到调用函数处

          return b;  

   else 

          return gcdFirst(b,a%b);

     }

   //穷举法(利用数学定义)

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

   }

   // 更相减损法

   public static int gcdSecond(int m,int n)

   {

      int i=0,temp,x=1;

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

      {

          m/=2;

          n/=2;

          i+=1;

      }

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

      {

          temp=m;

          m=n;

          n=temp;

      }

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

      {

          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)Math.pow(2,i)*n;

   }

public static void main(String[] args){

   //辗转相除法(函数嵌套调用)的实例

   int arr[][]={{4,98},{46,445},{545,8584},{6568,84566},{56566,845464},{765856,4845800},{1655615,96515655},{85656562,545665860},{685855646,465006544},{656665585,465465585}};

   for (int j = 0; j < 10; j++)

   {

      if (arr[j][0] <= 0 || arr[j][1] <= 0)

      {

          System.out.println("data error!");

          System.exit(1);

      }

   }

   double beginTime=System.nanoTime();

   for(int i=0;i<10;i++)

   {

      System.out.println(arr[i][0]+""+arr[i][1]+"的最大公约数是:"+divisorFirst(arr[i][0],arr[i][1]));

   }

   double endTime=System.nanoTime();

   System.out.println("辗转相除法(函数嵌套调用)的总共运行时间为:"+(endTime-beginTime)/1000.0+"微秒");

   //辗转相除法(函数递归调用)的实例

   double beginTime1=System.nanoTime();

   for(int i=0;i<10;i++)

   {

      System.out.println(arr[i][0]+""+arr[i][1]+"的最大公约数是:"+gcdFirst(arr[i][0],arr[i][1]));

   }

   double endTime1=System.nanoTime();

   System.out.println("辗转相除法(函数递归调用)的总共运行时间为:"+(endTime1-beginTime1)/1000.0+"微秒");

   //穷举法(利用数学定义)的实例

   double beginTime2=System.nanoTime();

   for(int i=0;i<10;i++)

   {

      System.out.println(arr[i][0]+""+arr[i][1]+"的最大公约数是:"+divisorSecond(arr[i][0],arr[i][1]));

   }

   double endTime2=System.nanoTime();

   System.out.println("穷举法(利用数学定义)的总共运行时间为:"+(endTime2-beginTime2)/1000.0+"微秒");

   // 更相减损法的实例

   double beginTime3=System.nanoTime();

   for(int i=0;i<10;i++)

   {

      System.out.println(arr[i][0]+""+arr[i][1]+"的最大公约数是:"+gcdSecond(arr[i][0],arr[i][1]));

   }

   double endTime3=System.nanoTime();

   System.out.println("更相减损法的总共运行时间为:"+(endTime3-beginTime3)/1000.0+"微秒");

}

}

C++

#include<iostream>

#include<ctime>

using namespace std;

//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)//如果x<y,交换x,y的值

    {

       temp = x;

       x = y;

       y = temp;

    }

    if (0 == y)//如果y=0,结束程序运行

    {

       return 0;

    }

    while (x != y)//当x!=y,进行循环

    {

       if (x & 0x1)// 判断x与16进制数0x1进行按位与运算的表达式的值,不为0则进入语句中

       {/* when x is odd */

           if (y & 0x1)// 判断y与16进制数0x1进行按位与运算的表达式的值,不为0则进入语句中

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

              y = (x - y) >> 1;//将x-y并右移一位的值赋给y

              x -= y;将x-y的值赋给x

           }

           else

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

              y >>= 1;//将y右移一位的值赋给y

           }

       }

       else

       {/* when x is even */

           if (y & 0x1) // 判断y与16进制数0x1进行按位与运算的表达式的值,不为0则进入语句中

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

              x >>= 1; //将x右移一位的值赋给x

              if (x < y)//如果x<y,交换xy的值

              {

                  temp = x;

                  x = y;

                  y = temp;

              }

           }

           else

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

              x >>= 1; //将x右移一位的值赋给x

              y >>= 1; //将y右移一位的值赋给y

               ++factor;//factor的值加一

           }

       }

    }

    return (x << factor);//返回x左移factor位的值

}

//Stein算法(函数递归调用)

int gcd(int u, int v)

{

    if (u == 0) return v;//u如果等于0,返回v

    if (v == 0) return u;//v如果等于0,返回u

    // look for factors of 2

    if (~u & 1) // u is even//判断v按位取反后与1进行按位与运算的表达式的值,不为0则进入if语句中

    {

       if (v & 1) // v is odd//判断v与1进行按位与运算的表达式的值,不为0则进入if语句中

           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判断v按位取反后与1进行按位与运算的表达式的值,不为0则返回函数,递归调用函数

       return gcd(u, v >> 1);

    // reduce larger argument

    if (u > v)//如果u>v,则返回函数,递归调用函数

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

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

}

int main()

{

    //Stein算法(函数非递归调用)的实例

    int arr[10][2] = { { 4,98 },{ 46,445 },{ 545,8584 },{ 6568,84566 },{ 56566,845464 },{ 765856,4845800 },{ 1655615,96515655 },{ 85656562,545665860 },{ 685855646,465006544 },{ 656665585,465465585 } };

    for (int i = 0; i < 10; i++)

    {

       if (arr[i][0] <= 0 || arr[i][1] <= 0)

       {

           cout << "data error!";

           return 0;

       }

    }

    clock_t start, finish;

    double total_time;

    start = clock();

    for (int i = 0; i<10; i++)

    {

       cout << "The higest common divisor is:" << Stein(arr[i][0], arr[i][1]) << endl;

    }

    finish = clock();

    total_time = (double)(finish - start)*1000.0;//CLOCKS_PER_SEC=1000

    cout << "Stein算法(函数非递归调用)的总共运行时间为:" << total_time << "微秒" << endl;

    //Stein算法(函数递归调用)的实例

    clock_t start1, finish1;

    double total_time1;

    start1 = clock();

    for (int i = 0; i<10; i++)

    {

       cout << "The higest common divisor is:" << gcd(arr[i][0], arr[i][1]) << endl;

    }

    finish1 = clock();

    total_time1 = (double)(finish1 - start1)*1000.0;//CLOCKS_PER_SEC=1000

    cout << "Stein算法(函数递归调用)的总共运行时间为:" << total_time1 << "微秒";

    return 0;

}

四、调试、测试及运行结果

数据的规模:输入十组数据并进行测试

{ { 4,98 },{ 46,445 },{ 545,8584 },{ 6568,84566 },{ 56566,845464 },{ 765856,4845800 },{ 1655615,96515655 },{ 85656562,545665860 },{ 685855646,465006544 },{ 656665585,465465585 } }

测试结果:

辗转相除法(函数嵌套调用)的五次运行时间分别为:(单位为微秒)
880.822715.898404.103502.975818.052

平均运行时间为:

880.822+715.898+404.103+502.975+818.052/5=664.370微秒=0.664毫秒

辗转相除法(函数递归调用)的五次运行时间分别为:

421.744196.513192.001315.488647.386

平均运行时间为:

421.744+196.513+192.001+315.488+647.386/5=354.626微秒=0.355毫秒

穷举法的五次运行时间分别为:

3135457.8083037537.6883030507.9353163589.1243070465.727

平均运行时间为:

3135457.808+3037537.688+3030507.935+3163589.124+3070465.727

/5=3087511微秒=3.088

更相减损法的五次运行时间分别为:

418462412.718408.616432.001346.256

平均运行时间为:(

418462+412.718+408.616+432.001+346.256/5=403.617微秒=0.404毫秒

Stein算法(函数非递归调用的五次运行时间分别为:

1000015000180001200013000

平均运行时间为:

10000+15000+18000+12000+13000/5=13600微秒=13.6毫秒

Stein算法(函数递归调用)的五次运行时间分别为:

1100015000140001200028000

平均运行时间为:

11000+15000+14000+12000+28000/5=16000微秒=16毫秒

五、经验归纳

由第四步中的测试结果我们知道辗转相除法(函数嵌套调用)的平均运行时间为0.664毫秒, 辗转相除法(函数递归调用)的平均运行时间为0.355毫秒, 穷举法的平均运行时间为3.088, 更相减损法的平均运行时间为0.404毫秒,很容易看出辗转相除法(函数递归调用)最优,更相减损法次之,辗转相除法(函数嵌套调用)再次之,穷举法的效率最差,远远不及前三种算法。由于这四种是在Java环境下运行的,另外两种算法目前如何在Java下运行不是很懂,只能放在c++环境下运行。且Javac++运行环境不同,这使得程序运行时间没有太大的可比性。在c++环境下的Stein算法:

Stein算法函数非递归调用的平均运行时间为13.6毫秒

Stein算法(函数递归调用)的平均运行时间为16毫秒

容易看出Stein算法函数非递归调用的效率要优于Stein算法(函数递归调用)。

 

 


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值