水仙花数是一个三位数,它的个位、十位、百位上的数值的三次方的和等于它本身。求水仙花数的算法如下:
迭代算法:
求水仙花数的直接方式是直接遍历所有的三位数(100 - 999)对每一个三位数进行判断,代码如下:
int getNarcissisticNumber(void){ start = clock(); int num, i, j, k; num = 1000; while(--num >= 100){ i = num / 100; j = num / 10 % 10; k = num % 10; if(num == i*i*i + j *j *j + k *k *k) printf("%d ", num); } end = clock(); printf("time = %f\n", ((double)end - start)/CLK_TCK); return 0; }
迭代优化一
上述算法在每次循环中都会进行三次0 - 9中三个数字的立方计算,这其中有大量的重复计算,我们可以提前计算并保存下来,在循环中直接使用,如下所示:
int * getNarcissisticNumber2(void){ start = clock(); int num, i, j, k; int arr[10]; for(int i = 0; i <= 9; ++i){ arr[i] = i * i * i; } num = 1000; while(--num >= 100){ i = num / 100; j = num / 10 % 10; k = num % 10; if(num == (arr[i] + arr[j] + arr[k])) printf("%d ", num); } end = clock(); printf("time = %ld\n", end - start); }
下面我们来看一看采用这种优化方式对北斗七星数进行优化后的算法效率:
优化前:
void initArr(){ for(int i = 0; i <= 9; i++){ arr[i] = i*i*i*i*i*i*i; } } void getBigDipperNum(void){ start = clock(); unsigned num, i, j, k, l, m, n, o; initArr(); num = 10000000; while(--num >= 1000000){ i = num / 1000000; j = num / 100000 % 10; k = num / 10000 % 10; l = num / 1000 % 10; m = num / 100 % 10; n = num / 10 % 10; o = num % 10; if(num == (arr[i] + arr[j] + arr[k] + arr[l] + arr[m] + arr[n] + arr[o])){ printf("%u ", num); } } end = clock(); printf("Time = %f\n", ((double) end - start) / CLK_TCK); }
优化一:
void getBigDipperNum2(void){ start = clock(); unsigned i, j, k, l, m, n, o; unsigned a[10], b[10], c[10], d[10], e[10], f[10], g[10]; for(int i = 0; i < 10; i++){ a[i] = i * 1000000; b[i] = i * 100000; c[i] = i * 10000; d[i] = i * 1000; e[i] = i * 100; f[i] = i * 10; g[i] = i; } initArr(); for(i = 1; i <= 9; ++i) for(j = 0; j <= 9; ++j) for(k = 0; k <= 9; ++k) for(l = 0; l <= 9; ++l) for(m = 0; m <= 9; ++m) for(n = 0; n <= 9; ++n) for(o = 0; o <= 9; ++o){ if((arr[i] + arr[j] + arr[k] + arr[l] + arr[m] + arr[n] + arr[o]) == (a[i] + b[j] + c[k] + d[l] + e[m] + f[n] + g[o])) printf("%u%u%u%u%u%u%u ", i, j, k, l, m, n, o); } end = clock(); printf("Time = %f\n", ((double) end - start) / CLK_TCK); }<pre class="cpp" name="code">
迭代优化二:
对上述算法再最内层循环进行了多次加法运算,我们可以化简该运算表达式,将加法提到循环外部,减少加法执行次数,如下:
void getBigDipperNum3(void){
start = clock();
unsigned i, j, k, l, m, n, o;
unsigned t1, t2, t3, t4, t5, t6;
unsigned a[10], b[10], c[10], d[10], e[10], f[10], g[10];
for(int i = 0; i < 10; i++){
a[i] = i * 1000000;
b[i] = i * 100000; c[i] = i * 10000;
d[i] = i * 1000; e[i] = i * 100; f[i] = i * 10; g[i] = i;
}
initArr();
for(i = 1; i <= 9; ++i)
for(j = 0; j <= 9; ++j){
t6 = a[i] + b[j] - arr[i] - arr[j];
for(k = 0; k <= 9; ++k){
t5 = t6 + c[k] - arr[k];
for(l = 0; l <= 9; ++l){
t4 = t5 + d[l] - arr[l];
for(m = 0; m <= 9; ++m){
t3 = t4 + e[m] - arr[m];
for(n = 0; n <= 9; ++n){
t2 = t3 + f[n] - arr[n];
// if(t2 < 0) continue;
for(o = 0; o <= 9; ++o){
t1 = t2 + g[o] - arr[o];
if(t1 == 0)
printf("%u%u%u%u%u%u%u ", i, j, k, l, m, n, o);
}
}
}
}
}
}
end = clock();
printf("Time = %f\n", ((double) end - start) / CLK_TCK);
}
上述三种求北斗七星数的方式在i3-380M 2.53GHz机器上执行情况如下:
9926315 9800817 4210818 1741725 Time = 0.390000
1741725 4210818 9800817 9926315 Time = 0.125000
1741725 4210818 9800817 9926315 Time = 0.047000
大家可以看到明显的优化效果。