美文网首页计算机技术宅计算机
21天C语言代码训练营(第三天)

21天C语言代码训练营(第三天)

作者: 天花板 | 来源:发表于2015-11-22 18:02 被阅读5982次

    上一篇最后留了一个打印杨辉三角的问题。这是C语言程序设计练习题中比较常见的一道题,今天我们将通过多种解法帮助大家熟悉C语言程序设计的基本思想。请大家跟随我的思路一步步练习,程序设计中解决问题的思路才是最珍贵的。

    杨辉三角

    1. 题目分析

    上面这张图就是杨辉三角,相信大家在中学数学课中学习过。它实际上是二项式(a + b)的n次方展开后各项的系数排成的三角形,它有如下特点:

    • 每行左右两边都是1
    • 从第二行起,中间的每一个数是上一行里相邻两个数之和
    • 第n行有n个数字

    2. 解法一

    看到这个问题,最容易想到的是创建一个二维数组。之后像填表一样把每一行的数据依次填进二维数组中。如图所示:

    杨辉三角二维数组

    2.1 二维数组初始化

    首先,我们需要创建一个二维数组(我们以10 * 10的二维数组为例),全部元素初始化为0,之后把所有1的位置填上。代码如下:

    # define MAX 10
    
    int main()
    {
        int i, j, n = MAX;
        int array[MAX][MAX] = { 0 };
    
        for (i = 0; i < n; i++)
        {
            array[i][0] = 1;
            array[i][i] = 1;
        }
    
        // 打印二维数组中的三角形
        for (i = 0; i < n; i++)
        {
            for (j = 0; j <= i; j++)
                printf("%5d", array[i][j]);
    
            printf("\n");
        }
    }
    

    执行结果:

    执行结果

    这段代码中需要注意:

    • 用宏MAX定义数组长度,方便改写
    • 数组初始化为0
    • 打印时使用“%5d”,防止后面数字位数太多破坏打印格式

    2.2 计算剩余单元格

    代码如下:

    for (i = 2; i < n; i++)
        for (j = 1; j < i; j++)
            array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
    

    这段代码中需要注意:

    • 从第三行开始计算(i = 2)
    • 每一个空格的内容都是它左上方和上方两个元素之和

    2.3 最终结果

    于是我们得到了完整的程序:

    # define MAX 10
    
    int main()
    {
        int i, j, n = MAX;
        int array[MAX][MAX] = { 0 };
    
        for (i = 0; i < n; i++)
        {
            array[i][0] = 1;
            array[i][i] = 1;
        }
    
        for (i = 2; i < n; i++)
            for (j = 1; j < i; j++)
                array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
    
        // 打印二维数组中的三角形
        for (i = 0; i < n; i++)
        {
            for (j = 0; j <= i; j++)
                printf("%5d", array[i][j]);
    
            printf("\n");
        }
    
        return 0;
    }
    

    执行结果如下:

    执行结果

    最终打印形式和杨辉三角还有距离,请大家自己思考一下,如何把这些数字打印成标准的杨辉三角格式。

    这个解法是最朴素的方法,一般大家都能想到。我们要做的只是把这个方法用代码实现而已。在真正的程序设计工作中,往往都是这样先相处朴素解法,之后再分析哪些环节可以优化。下面我们就看看这个方法能否优化。

    3. 解法二

    解法一种两组for循环看似比较冗余,我们希望能够用一组循环完成所有工作。

    # define MAX 10
    
    int main()
    {
        int i, j, n = MAX;
        int array[MAX][MAX] = { 0 };
    
        for (i = 0; i < n; i++)
        {
            array[i][0] = 1;
            for (j = 1; j <= i; j++)
                array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
        }
    
        // 打印二维数组中的三角形
        for (i = 0; i < n; i++)
        {
            for (j = 0; j <= i; j++)
                printf("%5d", array[i][j]);
    
            printf("\n");
        }
    
        return 0;
    }
    

    执行结果完全相同。此解法把填写数字1的工作放入循环中,减少了一个循环。

    4. 解法三

    解法二中的两组循环其实都是对二维数组的遍历,第一遍填数字,第二遍打印。那我们能不能一次遍历就完成既填空又打印的动作呢。请看下面这段代码:

    # define MAX 10
    
    int main()
    {
        int i, j, n = MAX;
        int array[MAX][MAX] = { 0 };
    
        for (i = 0; i < n; i++)
        {
            array[i][0] = 1;
            printf("%5d", 1);
    
            for (j = 1; j <= i; j++)
            {
                array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
                printf("%5d", array[i][j]);
            }
    
            printf("\n");
        }
    
        return 0;
    }
    

    同样的功能,这样实现是否又简洁了一些呢?

    5. 解法四

    解法三还能优化吗?当然可以,我们最终的目的是打印,并非保存,那么我们其实没有必要用一个二维数组把所有的数字保存起来。我们只需要在打印的时候读取上一行的内容,同时计算出当前行内容保存起来即可。那么我们试着用两个一维数组来完成。

    # define MAX 10
    
    int main()
    {
        int i, j, n = MAX;
    
    // 两个数组用来保存两行数字
        int array1[MAX] = { 0 };
        int array2[MAX] = { 0 };
    
        int* pUp = array1; // 指向保存上一行数字的数组
        int* pDown = array2; // 指向保存当前行数组的数组
        int* p = NULL; // 空指针用来进行指针交换
    
        int index = 0; // 访问下标
    
        for (i = 0; i < n; i++)
        {
            printf("%5d", 1);
            *(pDown + index++) = 1;
    
            for (j = 1; j <= i; j++)
            {
                *(pDown + index) = *(pUp + index - 1) + *(pUp + index);
                printf("%5d", *(pDown + index));
                 index++;
            }
    
            index = 0;
    
        // 两个指针指向内容交换
            p = pUp;
            pUp = pDown;
            pDown = p;
    
            printf("\n");
        }
    
        return 0;
    }
    

    这段代码的执行效率很高,存储空间使用的也比较少。但可读性相对差一些。我们用了两个数组array1和array2,又用了两个指针来管理这两个数组。为什么不直接用数组名操作呢,因为两个数组的使用时交替进行的,一个保存当前行,一个保存上一行。

    这个解法难度比较大,初学者可以先不做了解。如果留言中需要具体讲解的人数多,我会在下一篇中重点讲解。

    程序设计千变万化,这道题也远不止这四种解法。请大家在学习这四种的同时自己思考新的方法。

    6. 课后练习

    今天的课后练习题出个简单的,请编程打印出9*9乘法表。

    最后,我想说这个专题重在训练而不在讲解。如果只看讲解不做练习,那么提高的空间将会非常有限。

    我是天花板,让我们一起在软件开发中自我迭代。
    如有任何问题,欢迎与我联系。


    上一篇:21天C语言代码训练营(第二天)
    下一篇:21天C语言代码训练营(第四天)

    相关文章

      网友评论

      • 8adafd09129a:#include <stdio.h>
        #include <stdlib.h>

        int main()
        {
        int i,j;
        for(i=1;i<=9;i++)
        {
        for(j=1;j<=i;j++)
        {
        if(i==j)
        {
        printf("%d*%d=%d\n",i,j,i*j);
        }
        else
        {
        printf("%d*%d=%d ",i,j,i*j);
        }

        }
        }
        return 0;
        }
      • 寒山半秋:#include <stdio.h>

        int main(int argc, const char * argv[]) {
        int a, b, c;
        for (a = 1; a < 10; a++) {
        for (b = 1; b <= a; b++) {
        c = a * b;
        printf("%d * %d = %2d ", b, a, c);
        if (b == a) {
        printf("\n");
        }
        }
        }
        return 0;
        }
      • xyy的简书:pdown为什么要等于p呢
        天花板:@叩_97ca 因为要交换呀
      • 59d3e1a116cd:从哪里下载编程工具,能告诉我吗?
      • ID一龍族丨:#include <stdio.h>
        #define n 10
        int main()
        {
        int i, j;
        int a[n][n];



        for (i = 0; i < n; i++)
        {
        for (j = n - i ; j > 0 ; j --)
        {
        printf(" ");
        }
        for (j = 0; j <= i; j++)
        {
        if (i == j || j == 0)
        {
        a[i][j] = 1;
        }
        else
        {
        a[i][j] = a[i - 1][j - 1] + a[i-1][j];
        }
        printf("%4d", a[i][j]);

        }
        printf("\n");
        }





        system("pause");
        return 0;
        }
      • 流影之愁:第四种解法终于明白了,自己也编译出来了,谢谢天花板的讲解 ,对我很有用😊😊
      • NiceBlueChai:打印这个不难啊关键是打印出来的排版怎么搞,自己搞不出第一张图片那样(金字塔形状),复制楼主的代码结果也是没排好的杨辉三角
      • cd002734b69a:有一点不懂,方法二中出现了array[-1]为什么不会报错?
        cd002734b69a:嗯嗯,明白了,谢谢
        天花板:@当凹遇上凸 你说的是array[i - 1]这句吗,当 i = 0 时这句话根本执行不到。所以array[-1]根本没有出现。不信你运行一下这段代码试试。
      • 钇v:厉害了
      • annoy:程序的图片怎么显示不全啊?
      • bdb27209c62e:打卡喽
      • 清风景行:够专业
      • b00a68d5e092:看起来好高大上的样纸
      • a01ab4ecf567:有没有vb的呀
      • 79521e6b52e8:21天。。。。也太短了。。。
      • c9ab8809f4cf:就喜欢你的文章
      • 社会你威哥:感兴趣,不知道怎么入门,求教!
        天花板:@社会你威哥 请看我的另一个博文系列 http://www.jianshu.com/p/24e4b70c4bbd
      • 浪里的郎轶事:解法四不能实现,求详解。。
      • ab841cabb2de:我现在刚学习c语言,希望你能多讲些哦,最好是能多介绍能让初学者提升的书籍或者资料。你写的这些我每天都看,很好的。感谢有你这样的大神
      • 9cd83ad216e3:#include<stdio.h>
        int main()
        {
        int i,j;
        int a[9][9];
        for(i=0;i<9;i++)
        {
        for(j=0;j<9;j++)
        a[i][j]=(i+1)*(j+1);
        }
        for(i=0;i<9;i++)
        {
        for(j=0;j<=i;j++)
        {
        printf("%3d*%d=",i+1,j+1);
        printf("%d",a[i][j]);
        }
        printf("\n");
        }
        }
      • 4ed6afef78f9:打卡,难的做不出来,简单的还行。
        int main()
        {
        int a,b,c;
        for (a =1; a<10; a++) {
        for (b = 1; b<=a; b++) {
        printf("%d*%d=%d ",b,a,a*b);
        }
        printf("\n");
        }
        }
      • 浅念boy:大一新生,表示上一篇的菱形也没有看懂,C语言上课基本没有学,怎么破?
        浅念boy:@d4b1f32041af 谢谢
        天花板:@浅念boy 从头开始学吧,慢慢来~
        3011f7aab80f:@浅念boy 只能先背下来了,以后慢慢理解了

      本文标题:21天C语言代码训练营(第三天)

      本文链接:https://www.haomeiwen.com/subject/upcrhttx.html