刚刚上完软件开发实践课,下课那会想到前几天在书上看到的一个C题目,想到了一个改进方法有可能提高算法的运行效率(时间上的效率), 于是打算留下来try一下,反正这会儿吃饭人也多......
该题目的要求是:
求出在所有的三位数中能够满足一个数的每位数字的立方和等于该数本身的数的个数.b比如:abc=a*a*a+b*b*b+c*c*c
书上给出了两种答案:
第一就是穷举法,将所有的三位数都测试一次,其代码如下:
ARMS1.C
#include <stdio.h>
#include <sys/time.h>
int main()
{
int p, q, r; /* three digits */
int number;
int count = 0;
struct timeval fun_start, fun_end;
long start = 0, end = 0;
gettimeofday(&fun_start, NULL);
start = fun_start.tv_usec;
for (number = 100; number <= 999; number++) {
p = number/100; /* extract left most digit */
q = (number%100)/10; /* the middle digit */
r = number%10; /* the right most one */
if (p*p*p+q*q*q+r*r*r == number) /* Armstrong # ?*/
count++;
}
gettimeofday(&fun_end, NULL);
end = fun_end.tv_usec;
printf("The numbers of 3-digit ArmStrong number is: /n", count);
printf("The time cast in ARMS1.C is:%d/n", (end - start));
return 0;
}
第二种方法是把每一位的数字都算出来,而不是根据得到每一个数字然后再去拆分,这样就可以减去拆分一个数花的时间,其代码如下:
ARMS2.C
#include <stdio.h>
#include <sys/time.h>
int main()
{
int p, q, r; /* three digits */
int p_cube, q_cube, r_cube; /* their cubes */
int p100, q10; /* their position values */
int number; /* the computed number */
int cube_sum; /* the sum of the cubes */
int count = 0; /* counter */
struct timeval fun_start, fun_end;
long start = 0, end = 0;
gettimeofday(&fun_start, NULL);
start = fun_start.tv_usec;
for (p = 1, p100 = 100; p <= 9; p++, p100+=100) {
p_cube = p*p*p;
for (q = q10 = 0; q <= 9; q++, q10+=10) {
q_cube = q*q*q;
for (r = 0; r <= 9; r++) {
r_cube = r*r*r;
number = p100 + q10 + r;
cube_sum = p_cube + q_cube + r_cube;
if (number == cube_sum)
count++;
}
}
}
gettimeofday(&fun_end, NULL);
end = fun_end.tv_usec;
printf("The numbers of 3-digit ArmStrong number is: %d/n", count);
printf("The time cast in ARMS2.C is: %d/n", (end - start));
return 0;
}
我的想法如下:将0-9个数每个数字三次方都求出来存到一个大小为十的数组里面,然后再选取三个数字来组合成三位数,每个数字的三次方,直接通过查数组来得到.这样是对上面第二种计算方法的进一步的优化,因为,第二种算法中的三个循环里面的求数字的三次方的时候有重复的,每个循环一次,也就算是循环了三
次.
其次是,对一个数的三次访的求法,我按照书上说的方法做了优化,也就是相当于这样:
(q+1)*(q+1)*(q+1)=q*q*q+3q*(q+1+1)
转化成数组后的表达式如下:
a[i] = a[i-1] + 3*(i -1)*i + 1;
通过减少乘法的次数 (貌似每有减少,但书上说这样要快些,大概是因为乘数的数字要小得多吧)
ARMS.C
#include "stdio.h"
#include "sys/time.h"
int main(){
struct timeval fun_start, fun_end;
int a[10];
int i, j, k, m, count = 0;
long start = 0, end = 0;
a[0] = 0;
gettimeofday(&fun_start, NULL);
start = fun_start.tv_usec;
for(i = 1; i < 10; i++){
a[i] = a[i-1] + 3*(i -1)*i + 1;
}
for(j = 1; j < 10; j++){
for(k = 0; k < 10; k++){
for(m = 0; m < 10; m++){
if((j*100 + k*10 + m) == (a[j] + a[k] + a[m])){
count++;
}
}
}
}
gettimeofday(&fun_end, NULL);
end = fun_end.tv_usec;
printf("The numbers of 3_digit ArmStrong number is: %d/n", count);
printf("The time cast in ARMS.C is: %d/n", (end - start));
return 0;
}
最后测试一下各个算法花的时间,由于程序本身运行时间很短,只有微秒级,貌似在Windows下没提供这样的函数,还好机房都装了虚拟机,在LINUX下面通过测出的结果如下(三次测试):
The numbers of 3_digit ArmStrong number is: 4
The time cast in ARMS.C is: 12
The numbers of 3-digit ArmStrong number is:
The time cast in ARMS1.C is:27
The numbers of 3-digit ArmStrong number is: 4
The time cast in ARMS2.C is: 14
----------------------------------------------
The numbers of 3_digit ArmStrong number is: 4
The time cast in ARMS.C is: 13
The numbers of 3-digit ArmStrong number is:
The time cast in ARMS1.C is:27
The numbers of 3-digit ArmStrong number is: 4
The time cast in ARMS2.C is: 14
----------------------------------------------
The numbers of 3_digit ArmStrong number is: 4
The time cast in ARMS.C is: 12
The numbers of 3-digit ArmStrong number is: 4
The time cast in ARMS1.C is:26
The numbers of 3-digit ArmStrong number is: 4
The time cast in ARMS2.C is: 16
从上面的结果可以看到测试结果很明显看得出来第一种穷举法是最慢的,自己改进的方法相对而言还是提高的执行的时间,虽然差距不大。
声名:本人C语言很菜,所以最近才开始在学,所以该写出来的东西应该是很肤浅,只是我习惯把学习中的东西写出来。