求最大公约数的算法分析及实验报告

 

算法设计与分析

实验报告书

 

实验名称:   求两个自然数m和n的最大公约数                        

                                                

 

 

 

学   号:                            

 

姓   名:                          

 

 

 

 

实验时间:    2015年 4  月1   日

 


 一 实验目的和要求

(1)复习数据结构课程的相关知识,实现课程间的平滑过渡;

(2)掌握并应用算法的数学分析和后验分析方法;

(3)理解这样一个观点:不同的算法能够解决相同的问题,这些算法的解题思路不同,复杂程度不同,解题效率也不同。

二 实验内容

(1)      至少设计出三个版本的求最大公约数算法;

(2)      对所设计的算法采用大O符号进行时间复杂性分析;

(3)      上机实现算法,并用计数法和计时法分别测算算法的运行时间;

三 实验环境

    VC++6.0

四 设计思想及实验步骤 

  设计思想:

先分别用三种算法求出一组m和n的最大公约数,判断三个算法都是可行的,然后用text函数分别调用三个求最大公约数的函数,将k从100,每次扩大10倍,到50000000. 在每个k值附近求得1000对(m,n),调用一种函数运算1000次,用时间函数和计数器求得函数运行1000次的运行时间和计数,并求出每次的平均时间和平均计数。然后根据结果分别做出平均时间和平均计数的图标并进行分析。

   实验步骤:

1. 设计三种求最大公约数的算法和测算平均时间和平均计数的算法

2. 对所设计的算法采用大O符号进行时间复杂性分析

3. 实现算法并运行,分别测算每个算法的平均时间和平均计数

4. 根据结果分别作出平均时间和平均计数的图标

5. 根据图标分析的出结论。

主要基本算法描述如下:

 CommFactor1 (欧几里得)

输入:两个自然数m和n

返回:m和n的最大公约数

1.Count=0 ; r =m%n;

2. 循环直到r=0

  2.1 m=n;

  2.2 n=r;

  2.3 r=m%n;

  2.4 count++;

3. num+=count;

 

CommFactor2 (更相减损)

输入:两个自然数m和n

返回:m和n的最大公约数

1.  count=0

2. 循环知道m==n

  2.1 如果m>n ,则m=m-n;

  2.2 否则 n=n-m;

  2.3 count++;

3. num+=count;

 

CommFactor3 (蛮力法)

输入:两个自然数m和n

返回:m和n的最大公约数

1. Factor=1;

2. 循环变量i从2到min{m,n},执行下述操作:

2.1       ++count ,如果i是m和n的公因子,则执行下述操作:

2.1.1    factor=factor*i ;

2.1.2    m=m/i ;n=n/i ;

2.2       如果i不是m和n的公因子,则i=i+1;

3. num +=count;

 

text算法如下:

输入:待检测的函数

输出:待检测函数的运行时间和运算次数

1. 循环变量k,  for(intk=100;k<=50000000;k=k*10)

1.1    输出当前k值

1.2    t =0; num=0//num用来记录待测函数运行1000次的运算次数

1.3    获得时钟频率dfFreq

1.4    获得函数运行开始时间start

1.5    循环t知道t=1000

1.5.1   获得k附近的一对随机点(m,n)

1.5.2   调用待测函数求得(m,n)的最大公约数temp

1.5.3    t ++

1.6    获得函数运行的结束时间over

1.7    求得函数运行1000次的时间 dfMinus=(double)(over-start);

1.8    求得函数每次运行的平均时间dfTim=dfMinus/dfFreq/1000;

1.9    输出平均运行时间

1.10 输出平均计数

 

 

六 核心源代码

#include

#include

#include

#include

using namespace std;

double   num;

int CommFactor1(int m,int n)

{//欧几里得

    int r;

    r=m%n;

    int count=0;

    while(r!=0)

    {

        m=n;

        n=r;

        r=m%n;

        count++;

    }

    num+=count;

    return n;

}

int CommFactor2(int m,int n)

{//更相减损法

    int count=0;

    while(m!=n)

    {

        count++;

        if(m>n)

            m=m-n;

        else

            n=n-m;

    }

    num+=count;

    return n;

}

int CommFactor3(int m,int n)

{//蛮力法

    int factor=1,i;

    int count=0;

   for(i=2;i<=m&&i<=n;i++)

       while(++count&&m%i==0&&n%i==0)

    {

        factor*=i;

        m/=i;

        n/=i;

    }

    num+=count;

    return factor;

}

int Random(int a,int b)

{

    return(rand()%(b-a)+a);

}

void text( int(*CommFactor)(int,int))

{

 

    int m,n,t,temp;

    LARGE_INTEGER litmp;

    LONGLONG start,over;

    doubledfMinus,dfFreq,dfTim;

    for(intk=100;k<=50000000;k=k*5)

    {

       cout<<"k="<

        t=0;

        num=0;

        QueryPerformanceFrequency(&litmp);

        dfFreq=(double)litmp.QuadPart;

        QueryPerformanceCounter(&litmp);

        start=litmp.QuadPart;

        while(t<1000){

        m=Random(k-5,k+5);

        n=Random(k-5,k+5);

        temp=CommFactor(m,n);

        t++;

        }

        QueryPerformanceCounter(&litmp);

        over=litmp.QuadPart;

        dfMinus=(double)(over-start);

        dfTim=dfMinus/dfFreq/1000;

        num=num/1000;

        cout<<"平均时间T(k): ";

        //cout<

        printf("%e\t",dfTim);

        //cout<<"平均计算次数:"<

        printf("平均计算次数%.2lf\n",num);

        cout<

    }

 

}

int main()

{

    int m,n;

    cout<<"求m和n的最大公约数"<

    cout<<"输入m和n:";

    cin>>m>>n;

    cout<<"欧几里得"<<"\t";

    cout<<"最大公约数:"<<"\t"<

    cout<<"更相减损"<<"\t";

    cout<<"最大公约数:"<<"\t"<

    cout<<"蛮力方法"<<"\t";

    cout<<"最大公约数:"<<"\t"<

 

    cout<<"用计数法和计时法测试算法的运行时间"<

    cout<<"欧几里得"<

    text(CommFactor1);

    cout<<"更相减损"<

    text(CommFactor2);

    cout<<"蛮力方法"<

    text(CommFactor3);

 

    return 0;

七 实验结果及分析

1. 数学分析:采用大O符号进行的时间复杂性分析

1.1    CommFactor1(欧几里得)

欧几里得算法的时间复杂性O(log N)

假设m>n,函数会按照gcd(m,n)->gcd(n,m%n)->gcd(m%n,n%(m%n))这样递归下去,当n>m/2时有m%n=m-n

1.2    CommFactor2(更相减损)

更相减损算法的时间复杂性是O(N)

更相减损算法在两个数字大小区别很大时的效率很低,假设m很大,而n很小仅为1,则需要辗转相减m次,所以在最坏情况下,更相减损算法的时间复杂性是O(N)。

1.3    CommFactor3(蛮力法)

蛮力法的时间复杂性是O(N* )

对于蛮力法我也是按照最坏情况下分析其时间复杂性的。假设m和n是互质的,则i要从2开始一直到min(m,n),规模不能在比较中减小,所以蛮力法的时间复杂性应该也是O(N).

2 后验分析

 2.1 实验运行结果如下:

     

     求最大公约数的三个算法都是可行的

     

 欧几里得:

 

更相减损:

 

蛮力法:


2.2 平均时间的图标

   T(k)1:欧几里得的平均时间

   T(k)2:更相减损的平均时间

   T(k)3:蛮力方法的平均时间

 

 

2.3 平均次数的图标

Count1:欧几里得的平均计数

    Count2:更相减损的平均计数

    Count3:蛮力方法的平均计数

 

 

2.4后验比较分析

   2.4.1 从平均时间和平均次数两张图标上可以看出,各个算法所用时间和运算次数的增长是一致的。

   2.4.2 欧几里得算法是三个算法中最高效的,随着规模的不断增大,欧几里得算法的斜率几乎为0,它的时间花费和运算次数没有明显的增加,基本上保持不变,可见欧几里得算法的高效性。

  2.4.3 蛮力法效率是最低的,并且随着规模的不断增大,其耗时和运算次数增长很快。

  2.4.4在由实验结果所得到的图中更相减损算法的时间复杂性要小于O(N),应该是因为m,n为k附近的两个随机数,所以m和n的值不会相差太多,也就不会出现最坏的情况。

八 实验体会(包括本实验中遇到的问题、具体的解决方法、还没有解决的问题、实验收获等)

1.  这个实验让我对求两个数的最大公约数的有了更清晰的认识。虽然很耗费时间,但是知道了做一个实验的基本步骤和流程。之间分析一个算法的时间复杂性,我喜欢凭直觉,现在知道并学会使用这两种分析时间复杂性的方法。同时也学会如何使用时间函数来对程序计时了。

 

2.在该实验中遇到个感觉很特别的问题,在开始的实验中,为了得到每个k附近的1000对随机点,因为考虑到如果范围太小的话,那么得到的随机对的重复率很高,所以我就把范围定位k+-99 的范围内,m=Random(k-99,k+99); n=Random(k-99,k+99); 但是因为前面的k值比较小,所以前面的数据不够准确,就得到了下面的图标,在开始的数据中,更相减损和欧几里得相差很小,反而和蛮力法的时间复杂性相差很大,这和前面分析的时间复杂性有差别,经过2天的思考才终于找到问题所在,把范围减小后就可以解决这个问题了m=Random(k-5,k+5); n=Random(k-5,k+5);


3.在分析更相减损和蛮力法的时间复杂性的过程中,我都是直接考虑最坏的情况,并用最坏情况下的时间复杂性来表示算法的时间复杂性,不知道这样合理不合理。也有想过像推导欧几里得算法那样用数学方法那样推导,但是不知道要怎样推,所以我在这一点上还是有些问题的。

 

 


你可能感兴趣的:(求最大公约数的算法分析及实验报告)