Bootstrap

巧用for循环绘制各种图形

矩形

如果要实现for循环绘制图形的话,双重for循环自然必不可少。
在我的上篇博客:《你真的懂for循环吗?》中介绍双重for循环时,已经将双重for循环的特点:“外层循环控制行,内层循环控制列” 解释的很清楚,并且就是用的矩形做例子,这里就不多加赘述。当然合理把控内层循环变量j和外层循环变量i之间的关系以便控制内层循环的次数,也是关键!

等腰三角形

正所谓不会写注释的程序猿不是一个合格的程序猿,解释都在注释里

代码如下:

/**
 * @author guqueyue
 * @Date 2020/3/4
 * 使用*号打印等腰三角形
 *     *
 *    ***
 *   *****
 *  *******
 * *********
 **/
public class For2 {
    public static void main(String[] args) {
        for(int i = 0; i < 5; i++) { // 5行,因此外层循环次数为5
            /**
             * i分别为:     0 1 2 3 4
             * 空格数分别为:4 3 2 1 0
             * i + j = 4 所以, j = 4 - i
             */
            for(int j = 0; j < 4 - i; j++){
                System.out.print(" ");
            }

            /**
             * i分别为:         0 1 2 3 4
             * 空格后*号数分别为:1 3 5 7 9
             * j = 2 * i + 1
             */
            for(int j = 0; j < 2 * i + 1; j++) {
                System.out.print("*");
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

直角三角形

如:

/**
 * @author guqueyue
 * @Date 2020/2/25
 * 使用*号打印直角三角形
 * 1 *
 * 2 **
 * 3 ***
 * 4 ****
 * 5 *****
 **/
public class For1 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {         //外层for循环 i: 0 1 2 3 4
            for (int j = 0; j < i + 1; j++) { //内层for循环 j: 1 2 3 4 5 j = i+1
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

九九乘法表

直接开撸代码:

/**
 * @author guqueyue
 * @Date 2020/3/4
 * 绘制九九乘法口诀表
 * 1*1=1
 * 1*2=2 2*2=4
 * ...
 * 1*8=8	2*8=16	3*8=24	4*8=32	5*8=40	6*8=48	7*8=56	8*8=64
 * 1*9=9	2*9=18	3*9=27	4*9=36	5*9=45	6*9=54	7*9=63	8*9=72	9*9=81
 **/
public class For3 {
    public static void main(String[] args) {
        for (int i = 1; i <= 9; i++) {
            /**
             * i:   j:
             * 1    1
             * 2    1 2
             * ... ...
             * 8    1 2 3 4 5 6 7 8
             * 9    1 2 3 4 5 6 7 8 9
             * 所以, j <= i
             */
            for (int j = 1; j <= i; j++) {
                System.out.print(j + "*" + i + "=" + i*j + "\t");
            }
            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

倒等腰三角形

至于如何求出外层循环变量i和内层循环变量j之间的关系,简单的一眼就能看出来;若是稍复杂些,设一元一次方程,求出一元一次方程即可。

代码如下:

/**
 * @author guqueyue
 * @Date 2020/3/9
 * 使用*号打印倒等腰三角形
 * *********
 *  *******
 *   *****
 *    ***
 *     *
 * 空格数:0 1 2 3 4
 * *号数: 9 7 5 3 1
 **/
public class For5 {
    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {

            /**
             * i分别为:     0 1 2 3 4
             * 空格数分别为:0 1 2 3 4
             * i = j, 又因为是从0开始,所以 j < i, 没有等于
             */
            for (int j = 0; j < i; j++) {
                System.out.print(" ");
            }

            /**
             * i分别为:     0 1 2 3 4
             * *号数分别为:9 7 5 3 1
             * j = 9 - 2i, 又因为是从0开始,所以 j < 9- 2i, 没有等于
             */
            for (int j = 0; j < 9 - 2 * i; j++) {
                System.out.print("*");
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

菱形

请听题:

/**
 * 编写一个方法,根据参数n,打印对应的图形:
 * n = 5时:
 *     *
 *    * *
 *   * * *
 *  * * * *
 * * * * * *
 *  * * * *
 *   * * *
 *    * *
 *     *
 **/

方法一:简单粗暴版

分析:之前已经得出了求等腰三角形和倒等腰三角形的方法。
如下图,我们只需要把菱形分割成两部分即可。

在这里插入图片描述
代码如下:

/**
 * @author guqueyue
 * @Date 2020/3/9
 * 使用*号绘制菱形
 **/
public class For6 {
    public static void main(String[] args) {

        int n = 5;

        // 第一部分:5行,因此外层循环次数为5, 即 n
        for(int i = 0; i < n; i++) {
            /**
             * i分别为:     0 1 2 3 4
             * 空格数分别为:4 3 2 1 0
             * i + j = 4 所以, j = 4 - i
             */
            for(int j = 0; j < 4 - i; j++){
                System.out.print(" ");
            }

            /**
             * i分别为:          0 1 2 3 4
             * 空格后“* ”数分别为:1 2 3 4 5
             * j = i + 1
             */
            for(int j = 0; j < i + 1; j++) {
                System.out.print("* ");
            }

            // 输出一行后换行
            System.out.println();
        }

        // 第二部分:4行,因此外层循环次数为4,即 n - 1
        for (int i = 0; i < n - 1; i++) {

            /**
             * i分别为:         0 1 2 3
             * 空格数分别为:1 2 3 4
             * j = i + 1, 又因为是从0开始,所以 j < i + 1, 没有等于
             */
            for (int j = 0; j < i + 1; j++) {
                System.out.print(" ");
            }

            /**
             * i分别为:         0 1 2 3
             * 空格后“* ”分别为:4 3 2 1
             * j = 4 - i, 又因为是从0开始,所以 j < 4 - i, 没有等于
             */
            for (int j = 0; j < 4 - i; j++) {
                System.out.print("* ");
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

方法二:进阶版

分析:

在方法一中,我们所用的代码可谓是封建时期老太婆的裹脚布 ——又臭又长,竟然用了6个for循环,真的是叔叔能忍但是婶婶不能忍,那么我们试着来优化一下。

如下图:
在这里插入图片描述
其实我们不难发现,当输出的"* "数到达n也就是5时,到达了一个临界点,情况是完全相反的,那么能不能把方法一中的两个双重for循环给合并成一个,并用一个标记变量控制一下绘制的方向?
当然是可以的(不然我写这么多干嘛呢)

所以,我们只需要注意判断什么时候到达临界点,开始反向绘制即可

代码如下:

/**
 * @author guqueyue
 * @Date 2020/3/13
 * 进阶:使用*绘制菱形
 **/
public class For7 {
    public static void main(String[] args) {

        int n = 5;

        // 定义变量number, 表示这一行"* "的数量
        int number = 1;
        // 定义变量space, 表示这一行空格的数量
        int space = n - 1;

        // 标记变量,用于控制方向: true表示"* "递增, 空格数递减;false则相反
        boolean flag = true;

        // 很明显,外层循环的次数为 n + (n - 1), 也就是 2n - 1
        for(int j = 0; j < 2 * n - 1; j++) {

            // 输出space个空格
            for(int i = 0; i < space; i++) {
                System.out.print(" ");
            }

            // 输出number个"* "
            for (int i = 0; i < number; i++) {
                System.out.print("* ");
            }

           // 到达临界点,调转方向,开始反向绘制
            if (number == 5) flag = false;

            if (flag) {
            	// 下一行"* "要递增,空格数要递减
                number ++; // "* "数:1 2 3 4 5
                space --;  // 空格数: 4 3 2 1 0
            } else {
            	// 当输出"* "数为5后,下一行"* "要递减,空格数要递增
                number --; // "* "数:4 3 2 1
                space ++; // 空格数:  1 2 3 4
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

大功告成,Output:
在这里插入图片描述

沙漏

同样,请听题:

/**
 * 编写一个方法,根据参数n,打印对应的图形:
 * n = 5时:
 * * * * * *
 *  * * * *
 *   * * *
 *    * *
 *     *
 *    * *
 *   * * *
 *  * * * *
 * * * * * *
 **/

方法一:简单粗暴版

分析:其实跟绘制菱形的方法一差不多
如下图,我们只需要把图形切割成两部分即可
在这里插入图片描述

代码如下:

/**
 * @author guqueyue
 * @Date 2020/3/13
 * 使用* 绘制沙漏
 **/
public class For8 {
    public static void main(String[] args) {
        int n = 5;

        // 第一部分:4行,因此外层循环次数为4, 即 n - 1
        for(int i = 0; i < n - 1; i++) {
            /**
             * i分别为:     0 1 2 3
             * 空格数分别为:0 1 2 3
             * j = i, 内层循环次数为i
             * 因为从0开始,所以没有等于, j < i
             */
            for(int j = 0; j < i; j++){
                System.out.print(" ");
            }

            /**
             * i分别为:          0 1 2 3
             * 空格后“* ”数分别为:5 4 3 2
             * j = - i + 5
             */
            for(int j = 0; j < - i + 5; j++) {
                System.out.print("* ");
            }

            // 输出一行后换行
            System.out.println();
        }

        // 第二部分:5行,因此外层循环次数为5,即 n
        for (int i = 0; i < n; i++) {

            /**
             * i分别为:     0 1 2 3 4
             * 空格数分别为:4 3 2 1 0
             * j = -i + 4, 又因为是从0开始,所以 j < -i + 4, 没有等于
             */
            for (int j = 0; j < -i + 4; j++) {
                System.out.print(" ");
            }

            /**
             * i分别为:         0 1 2 3 4
             * 空格后“* ”分别为:1 2 3 4 5
             * j = i + 1, 又因为是从0开始,所以 j < i + 1, 没有等于
             */
            for (int j = 0; j < i + 1; j++) {
                System.out.print("* ");
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

方法二:进阶版

其实绘制沙漏的方法二跟绘制菱形的方法二在本质上是一样的,同样的我们找出临界点:
在这里插入图片描述
但是此处做了一个改进:
判断退出外层循环的条件,没有必要重新定义一个变量,只要保证"* "的数量<=n即可,也就是本题中的5。

代码:

/**
 * @author guqueyue
 * @Date 2020/3/4
 **/
public class For4 {
    public static void main(String[] args) {
        // 设置变量n
        int n = 5;
        // 定义输出的字符串
        String str = "* ";

        // 设置变量number: 表示这一行str的数量
        int number = n;
        // 设置变量space: 表示这一行开始空格的数量
        int space = 0;

        // 设置标记变量,用于控制方向:其中true表示str数递减,false表示str数递增
        boolean flag = true;

        // 循环输出每行,当str数目开始大于n时,循环结束
        for (;number <= n;) {
            // 输出space个空格
            for(int i = 0; i < space; i++) {
                System.out.print(" ");
            }

            // 输出number个字符串
            for(int i = 0; i < number; i++) {
                System.out.print(str);
            }

            if(number == 1) { // 到达临界点,调换方向
                flag = false;
            }

            if(flag){
                // 下一行空格要递增,str要递减
                space++;  // 空格数分别为: 0 1 2 3 4
                number--; //  str数分别为:5 4 3 2 1
            } else {
                // 当只输出一个str后,下一行空格数要递减,str数要递增
                space--;  // 空格数分别为: 3 2 1 0
                number++; // str数分别为: 2 3 4 5
            }

            // 输出一行后换行
            System.out.println();
        }
    }
}

Output:
在这里插入图片描述

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;