程序设计作业之求最大公约数不同算法的时间性能比较
一、题目分析:
因为老师已经给出了四种不同的算法程序,所以该题主要是对不同的算法理解调用并对各算法使用时间进行比较,比较各算法的性能。
二、算法代码
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); /*返回最大公约数到调用函数处*/
}
int multiple(int a, int b) /*自定义函数求两数的最小公倍数*/
{
int divisor(int a, int b); /*自定义函数返回值类型*/
int temp;
temp = divisor(a, b); /*再次调用自定义函数,求出最大公约数*/
return (a*b / temp); /*返回最小公倍数到主调函数处进行输出*/
}
//函数递归调用
int gcd(int a, int b)
{
if (a%b == 0)
return b;
else
return gcd(b, a%b);
}
2、穷举法
int divisor1(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 multiple1(int a, int b) //求最大公倍数
{
int p, q, temp;
p = (a > b) ? a : b; /*求两个数中的最大值*/
q = (a > b) ? b : a; /*求两个数中的最小值*/
temp = p; /*最大值赋给p为变量自增作准备*/
while (1) /*利用循环语句来求满足条件的数值*/
{
if (p%q == 0)
break; /*只要找到变量的和数能被a或b所整除,则中止循环*/
p += temp; /*如果条件不满足则变量自身相加*/
}
return (p);
}
3、 更相减损法
int gcd1(int m, int n)
{
int i = 0, temp, x=1;
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!=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)pow(2, i)*n;
}
4、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);
}
//函数递归调用
int gcd2(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 gcd2(u >> 1, v);
else // both u and v are even
return gcd2(u >> 1, v >> 1) << 1;
}
if (~v & 1) // u is odd, v is even
return gcd2(u, v >> 1);
// reduce larger argument
if (u > v)
return gcd2((u - v) >> 1, v);
return gcd2((v - u) >> 1, u);
}
三、因为关键代码已经给出因此自己只需要设计计算程序执行的时间部分就行了。
由于要比较不同规模的数据,所以通过随机数组赋值给数组a[i],b[i].通过数组来传参给函数。因为这个随机数组执行一次后,后面每次产生的随机数都与之前的相同,因此这里设置了一个种子seed用来保证每次产生的随机数是不同的,在程序执行后随机输入一个整数即可。
int a[100000], b[100000],t1,t2;
int i = 0;
unsigned int seed; //申明初始化器的种子,注意是unsigned int 型的
clock_t start, finish;
double duration;
printf("Enter a positive integer seed value: \n");
scanf_s("%u", &seed);
srand(seed);
for (i; i < 100000; i++)
{
a[i] = 2+rand() % 100000;
}
for (i = 0; i < 100000; i++)
{
b[i] = 1+rand() % 100000;
}
这部分即为第一个算法的调用过程(接上个代码)
i = 0;
start = clock();
while (i < 10000)
{
t1=divisor(a[i], b[i]);/*自定义主调函数*/
i++;
}
finish = clock();
duration = (double)(finish - start)/CLOCKS_PER_SEC ;
printf("此次总共为%d组数据\n", i);
printf("辗转相除法\n");
printf("1 函数嵌套调用\n");
printf("函数嵌套调用求得最大公约数所用时间为:%fs\n", duration);
printf("The higest common divisor is %d\n", t1); //输出最大公约数
printf("2 函数递归调用\n");
i = 0;
start = clock();
while (i <10000)
{
t1=gcd(a[i],b[i] );//自定义主调函数
i++;
}
finish = clock();
duration = (double)(finish - start)/CLOCKS_PER_SEC ;
printf("函数递归调用求得最大公约数所用时间为:%fs\n", duration);
printf("The higest common divisor is %d\n", t1); //输出最大公约数
其余几个算法的代码与此相同只有不同函数调用差别。
四、算法耗时比较
该过程通过clock()函数对时间进行计算
clock()是C/C++中的计时函数,而与其相关的数据类型是clock_t。
clock函数定义如下:clock_t clock(void) ;简单而言,就是该程序从启动到函数调用占用CPU的时间。这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock);若挂钟时间不可取,则返回-1。其中clock_t是用来保存时间的数据类型。
该截图为对10组数据测试的结果,能够看到时间均为零,说明数据量太小。
该截图为100组的数据量,可以看到只有穷举法的时间为1ms,其余的都为零。
该截图为1000组的数据量,可以看到各算法都有时间显示,说明1000组左右的数据量才能够测出时间来。其中穷举法的耗时最多,其余的都是1ms左右,
该截图为10000组的数据量,可以看到各算法都有了明显的时间变化,其中辗转相除法耗时最少,穷举法耗时最多。
该截图为100000组的数据量,可以看到时间变化已经很大了,并且等待结果的时间也明显长了一些。对这些结果进行分析可以看到,穷举法是最耗时的运行时间长达3秒多,辗转相除法耗时最少,只有十几毫秒左右,其余的两个算法时间则相差不大。说明穷举法时间性能是最差的,因为它调用次数最多,数据越大调用次数也越多。辗转相除法时间性能最优,耗时最少,因此这种方法解决最大公约数问题是最好的。
下图为完整的结果,包括时间和最大公约数以及最小公倍数的计算结果。
四、总结:通过这次对不同算法时间性能的比较过程,看到了不同方法在处理问题上会产生不同的结果,好的算法应该做到时间、空间的占用尽量的少,这样执行效率才较高。特别是数据量越大,算法间的差异越明显。因此在以后的程序设计学习中应该重视程序的时间性能,对问题的解决用尽可能少的时间,利用好数据结构学到的知识,这样才能写出更好的程序。