现在的位置: 首页 > 综合 > 正文

从计算杨辉三角(Pascal Triangle)看算法优化

2012年09月20日 ⁄ 综合 ⁄ 共 1835字 ⁄ 字号 评论关闭

杨辉,字谦光,北宋时期杭州人。在他1261年所著的《详解九章算法》一书中,辑录了三角形数表,称之为“开方作法本源”图。 杨辉三角是一个由数字排列成的三角形数表,一般形式如下:          

      1
         1 1
        1 2 1
       1 3 3 1
      1 4 6 4 1
     1 5 10 10 5 1

杨辉三角最本质的特征是,它的两条斜边都是由数字1组成的,而其余的数则是等于它肩上的两个数之和。根据这一特征,我们可以用程序方便地实现输出杨辉三角。实现算法有很多,下面给出其中两种。

1、递归算法: F(i, j) = F(i-1, j-1) + F(i-1, j)

#include <stdio.h>

#include <stdlib.h>

long long pascal_triangle(int row, int col)
{
    if (col == 1 || row == col)
        return 1;
    return pascal_triangle(row-1, col-1) + pascal_triangle(row-1, col);
}

int main(int argc, char *argv[])
{
    int i, j;
    int row = atoi(argv[1]);
   
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= i; j++)
            printf("%u ", pascal_triangle_inc(i, j));
        printf("/n");
    }

    return 0;
}

 

2、增量算法,使用一组数据保存已计算的值,占用O(n)额外存储空间

#include <stdio.h>

#include <stdlib.h>

long long pascal_triangle_inc(int row, int col, long long *a)
{
    if (col == 1 || row == col)
    {
        a[row*(row-1)/2 + col - 1] = 1;
        return 1;
    }
    //a[row-1][col-1] = a[row-2][col-2] + a[row-2][col-1];
    a[row*(row-1)/2 + col - 1] = a[(row-1)*(row-2)/2 + col - 2] + a[(row-1)*(row-2)/2 + col - 1];
    return a[row*(row-1)/2 + col - 1];
}

int main(int argc, char *argv[])
{
    int i, j;
    int row = atoi(argv[1]);
    long long *a = (long long *)malloc((row*(row+1))/2 * sizeof(long long));
    if (a == NULL)
    {
        perror("malloc");
        return -1;
    }

    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= i; j++)
            printf("%u ", pascal_triangle_inc(i, j, a));
        printf("/n");
    }

    free(a);
    return 0;
}

上面两种算法,递归算法简洁,但性能很大,存在太多的重复计算,当杨辉三角大时,计算非常慢。而增量算法,使用数组对先前计算结果进行保存,用于计算后续的数值,有效消除了冗余计算,以空间复杂性换取了计算复杂性,性能得到了很大的提升。在我自己的机器进行测试,递归算法计算row = 30时就比较困难了,而增量算法可以很快输出row = 1000的杨辉三角。当 row = 30时,两种算法的消耗时间分别如下:

time ./triangle 30

real    0m36.314s

user   0m21.201s

sys     0m0.004s

 

time ./triangle_inc 30

real    0m0.002s

user   0m0.000s

sys     0m0.000s

可见,增量算法在时间复杂性方面要远远优于递归算法,只是增加了一定的空间复杂性。所以,鱼和熊掌常常不可得兼。

其实,我先写了递归算法,发现其性能不可接受,于是给出了增量算法。数据结构和算法,是软件开发人员的基本功。当需要对程序性能进行调优时,就可以发现其巨大的威力。

 

(Aiguille LIU / 刘爱贵 / aigui.liu@gmail.com)

抱歉!评论已关闭.