zoukankan      html  css  js  c++  java
  • 12天学好C语言——记录我的C语言学习之路(Day 7)

    12天学好C语言——记录我的C语言学习之路

    Day 7:

    昨天进行了一天的数组学习,今天大家可以先写几个昨天的程序热热身,回顾回顾,然后今天第一个新程序也是关于数组的,比较难,准备好就开始啦!

    //输出奇数魔方阵,每一列、每一行以及对角线之和均相等(输入n为魔方阵的阶数,n为奇数)

    //首先说明一下魔方阵的形成规律:①将元素1放在第一行中间一列;②依次将数字放在前一个数字的右上角,如果超过了魔方阵的范围,就拿另一侧的位置补齐,这个步骤需要想象成一个可以穿过边界到达另一头的贪吃蛇游戏;③如果另一侧补齐的位置处有元素在,则不考虑这个位置了,就直接把元素写在上一个元素的正下方的位置

    //程序分析,我们是分了四部分来写这个方阵的形成规律。①右上角②第一行除右上角③最后一列除右上角④左下角剩下的所有元素(这些元素是最普通的,无特殊处理,顶多就是如果下一个元素位置上面不为0,那么就直接写在正下方)

    /* 如下图是五阶魔方阵
     17  24  1   8   15
     23  5   7   14  16
     4   6   13  20  22
     10  12  19  21  3
     11  18  25  2   9
     */

    /*//program 7.1
     #include "stdio.h"
     int main()   //这个程序是下标从0开始的
     {
     printf("请输入数字n,n代表魔方阵的阶数: ");
     int a[20][20]={0},i,j,k,n;
     i=0;
     scanf(“%d",&n);   //输入魔方阵的维度n
     j=n/2;     // j是维度的一半取整,这里一定要注意,如果下标是从0开始的,那么3阶的时候元素1的位置就是(0,1),5阶的时候元素1的位置就是(0,2),可见元素的j坐标是n/2。如果下标从1开始的话,j=n/2+1。注意注意!!!!!
     a[i][j]=1;   //确定第一排的中间一个数为1
     for (k=2; k<=n*n; k++)   //从2开始,一直到n*n,按规律存放
     {
     i=i-1;   //正常情况下的走向是往右上角走,那么确定一个值的位置后(i,j),它的下一个值坐标正常情况下应该为(i-1,j+1)
     j=j+1;
     if(i<0&&j>n-1)   //最后的问题就是i<0的情况难道不就是i=-1吗?为什么不能用i=-1来代替i<0??? 这里说的很对,i<0的情况只有一个,就是i=-1,但是我们写判定条件的时候,要这样写if(i==-1&&j>n-1),也就是两种情况都可以。
     {   //如果该值已经在整个方阵的右上角(上图元素15的位置,第一行、第n列),那么放在这个值的正下方,又因为之前经过了行数-1,列数+1的变化,所以要变回原值的正下方,故得到下面两个变化。
     i=i+2;
     j=j-1;
     }
     if(i<0&&j<=n-1)
     {   //如果该值是处于第一行的位置(但是不包括上个条件排除的右上角的值),那么它的下一个值就应该处于最底行。
     i=n-1;
     }
     
     if(j>n-1)
     {   //如果该值是处于第n-1列(最后一列)的位置,那么它的下一个值一定处于第一列了
     j=0;
     }
     if (a[i][j]==0)
     {   //如果计算出来的位置上面还没有赋值,那么就将该数值赋给该位置
     a[i][j]=k;
     }
     else
     {   //如果计算出来的位置上面已经有数值存在了,那么也是将下一个数值放在其上一个数值的正下方
     i=i+2;
     j=j-1;   //这个地方其实也是是对变化过的i、j进行再操作
     a[i][j]=k;
     }
     }
     for (i=0; i<n; i++)
     {
     for (j=0; j<n; j++)
     {
     printf("%-4d",a[i][j]);
     }
     printf(" ");
     }
     return 0;
     }
    */

    上面那个程序的下标是从0开始的(第0行,第0列),可能有些刚打程序的读者有些别扭,那么下面我用下标从1开始写一下这个魔方阵程序,改了初始下标,希望读者能看出来程序哪里发生了实质上的改变。

    /*//program 7.2
    #include<stdio.h> //这个程序是下标从1开始的
     int main()
     {
     int a[20][20]={0},i,j,n;
     i=1;
     printf("请输入一个数");
     scanf("%d",&n);//输入魔方阵的维度n
     j=n/2+1;     // j是维度的一半加1.
     a[i][j]=1;   //确定第一排的中间一个数为1
     for(int k=2;k<=n*n;k++)//已经确定1的位置了,再循环确定2~n*n的位置
     {
     i=i-1;      //挪位,横坐标往上挪一位。
     j=j+1;      //挪位,纵坐标往右挪一位。
     if((i<=0)&&(j<=n))   //如果横坐标挪到顶,同时纵坐标还没有超过最右,横坐标就到从最下再继续。原位置是第一行 除了 右上角的
     i=n;
     if((i<=0)&&(j>n)) //如果横坐标挪到顶,同时纵坐标超过最右,横坐标往下挪两位,纵坐标排往左移一位。原位置是第一行右上角
     {
     i=i+2;
     j=j-1;
     }
     if(j>n)  //如果只有纵坐标超过最右,纵坐标挪到左边第一行。
     {
     j=1;
     }
     if(a[i][j]==0)
     a[i][j]=k;  //如果这个位置还没有赋值,那么赋值为k。
     else        //已经赋值过了。那么竖排往下挪两位,横排往左移一位,再赋值为k。
     {
     i=i+2;
     j=j-1;
     a[i][j]=k;
     }
     }
     for(i=1;i<=n;i++) //循环输出位置。
     {
     for(j=1;j<=n;j++)
     printf("%5d",a[i][j]);
     printf(" ");
     }
     }
    */

    魔方阵程序不难,如果说读者一时消化不了,可能难点就在魔方阵的算法难理解,还有就是对临界点几个情况的分析。另外一旦下标初始值发生改变了,可能就单单改了一个从0开始还是从1开始,就又让人迷糊一阵子。这里慢慢琢磨总能琢磨出来的,现在有程序给大家参考,想起来还是比较方便的,可以先把程序拷下来运行一下,然后自己理解了这道题的含义在自己试着去敲。希望大家能牢牢的掌握这个程序。

    下面这个程序是要输出一个平行四边形的。这个程序有一个地方我觉得初学者可能会犯错,给大家拿出来说一下。

    *****     
     *****    
      *****   
       *****  
        *****
     
    输出上面的图形。
             
    /*//program 7.3
    #include<stdio.h>
    int main()
    {
        int i,j;
        char a[10][10];
        for(i=0;i<10;i++)    //先把每一个数组中的元素都赋上空格~然后把需要替代的元素用'*'替代就好了
            for (j=0; j<10; j++) {
                a[i][j]=' ';
            }
        
        for (i=0; i<=4; i++) {
            for (j=i; j<=i+4; j++) {
                a[i][j]='*';
                // printf(“%c",a[i][j]);    //不要赋值一个就输出一个,你输出的只是你赋值的这些元素,而那些被初始化为空格的元素是没有输出的,所以就会出现输出一个长方形的现象(这就是读者需要注意的一个地方,在此我已经注释掉了)
            }
            //printf(" ");
        }
        for (i=0; i<10; i++) {
            for (j=0; j<10; j++) {
                printf(“%c",a[i][j]);    //把该赋值的都赋值完了,然后将所有元素输出,自然得到想要的结果了~
            }
            printf(" ");
        }
        return 0;
    }
    */

    数组方面的学习到此为止了,用了一天多点的时间,我觉得学习重在自己的理解和练习,只要是打够代码,一定能在短时间里有质的提升。下面我们开始函数的学习:

    //   注意一下无参函数和有参函数的调用形式
    //   abc(); 这是调用无参函数      c=def(a,c,v); 这是调用有参函数(注意把结果要赋给一个变量),当然函数调用本身并不一定非要有分号或者是把结果赋给一个变量,如:printf(“%d",max(a,b));

    一个小程序(program 7.4)让大家感受一下函数。
    对了,也不知道提醒没提醒过大家,max函数是自己人为写的,可没有什么头文件中含有这个函数的,不要直接就用,虽然这个函数作用很简单

    /*//program 7.4
     #include "stdio.h"
     int main()
     {
     int max(int ab,int cd);    //ab、cd都是形参
     int a,b,k;     //这里是定义变量
     scanf("%d%d",&a,&b);
     k=max(a,b);    //a、b是实参,调用函数调用的是实参
     printf("%d",k);
     return 0;
     }
     int max(int x,int y){
     int c;
     c=(x>y)?x:y;
     return c;
     }
     */

    下面我们来学习一下函数的嵌套,看程序 program 7.5

    /*//program 7.5
    //输入四个数,找出最大值,用函数的嵌套实现。
    #include "stdio.h"
    int max1(int a,int b,int c,int d);
    int max2(int a,int b);
    int temp;
    int main()
    {
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        a=max1(a,b,c,d);    //可以把最后的结果赋给a,都是形参
        printf("max is %d ",a);
        return 0;
    }
    int max1(int f,int b,int c,int d)    //这里的f,b,c,d都是形参
    {
        int m;
        m=max2(f,b);    //应用了函数的嵌套,从上到下进行读取执行
        m=max2(m,c);
        m=max2(m,d);
        return m;
    }
    int max2(int a,int b)
    {
        if (a<b) {
            temp=a;
            a=b;
            b=temp;
        }
        return a;
    }
    */

    当然上面的方法感觉还是太过繁琐,我们还可以再优化一下:

    /*//program 7.6
    //对上题的改进。
    #include <stdio.h>
    int main()
    {
        int max3(int,int);
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        printf(“%d",max3(max3(max3(a,b),c),d));    //多重嵌套,这样只需要写一个函数max3就可以了~简单明了
        return 0;
    }
    int max3(int a,int b)
    {
        int temp;    //temp必须在这里声明,而不能在主函数中声明,两边不扯
        if (a<b) {
            temp=a;
            a=b;
            b=temp;
        }
        return a;
    }
     */

    在看这样一个题目,关于函数的 递归调用。

    //有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?(program 7.7)

    /*//program 7.7
    #include <stdio.h>
    int main()
    {
        int a,n;
        scanf("%d",&n);
        int age(int n);
        a=age(n);
        printf("age=%d",a);
        return 0;
    }
    int age(int n)
    {
        int c;   //注意,这里函数名和变量名不能重名
        if (n==1) {
            c=10;
        }
        else
        {
            c=age(n-1)+2;
        }
        return c;
    }
    */
       
    程序比较简单,读者耐心看一下就能看懂。

    那么再做一个题目来加深一下今天学习过的递归问题。
     
    //用递归方法求n!

    /*//program 7.8
    #include <stdio.h>
    int main()
    {
        int n,a;
        scanf("%d",&n);
        int mul(int n);
        a=mul(n);
        printf("n!=%d",a);
        return 0;
    }
    int mul(int n)
    {
        int m;
        if (n==1||n==0) {
            m=1;//不管n多大,n都肯定要慢慢减少最终等于1的,而最后n=1时,m是1,这个m是mul(1),而不是取代了之前算出来的m的值,递归的意义就在此。也可以这么想,最后的m=1是最内层的m,最内层的m求出来了,然后逐渐扩大到最外层的也就是最终的结果了
        }
        else
        {
            m=n*mul(n-1);
        }
        return m;
    }
     */

    最后一个程序结束今天的学习,这个题目比较的抽象,也是递归题目里面必做的一道题,那就是Hanoi塔问题,让我们一起来尝试一下吧。

    /*//program 7.9
    //Hanoi塔问题
    #include <stdio.h>
    int main()
    {
        int n;
        scanf("%d",&n);
        void Hanoi(int n,char a,char b,char c);   //把m个盘子从 圆柱a 上通过 圆柱b 移至 圆柱c
        Hanoi(n,'A','B','C');
        return 0;
    }
    void Hanoi(int n,char a,char b,char c)
    {
        void move1(char a,char b);    //Hanoi函数中需要用到Move1函数,所以Move1函数要在Hanoi函数中声明一下
        
        if(n==1)
        {
            move1(a,c);
        }
        else
        {
            Hanoi(n-1, a, c, b);    //想到这里的时候,一定得想到递归的逻辑是什么,做递归的题目,不要带入数进行验证,只要把递归到最底层的值写出来之后,剩下的就是n到n-1之间的递归,我认为此时可以在脑海里念着怎么移动,用通俗的语句来表示这复杂的代码
            move1(a, c);
            Hanoi(n-1, b, a, c);    //这句话就可以这样理解“将n-1个盘子从b通过a移动到c上”
        }
    }
    void move1(char a,char b)    //这里就不用解释了吧,将这个程序分解开来其实简单不过了
    {
        printf("将一个盘子由%c移至%c ",a,b);
    }
    */

    好了,第七天的学习结束了,不知道大家掌握的怎么样,希望今天的学习大家也能够牢牢的记在心里,一定要多做题,一道题再简单敲一遍是不够的,多多敲几遍,你会有不同的收获!

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    实验四
    实验一、二
    实验
    网上摘录
    网上摘录(琐碎信息)
    angularJsUIbootstrap系列教程1(使用前的准备)
    angularJS在本机运行时的注意事项
    angularJS在创建指令需要注意的问题(指令中使用ngRepeat)
    angularJsUIbootstrap系列教程2(According)
    ASP.NET Web Forms 4.5的新特性
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787908.html
Copyright © 2011-2022 走看看