如果要实现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();
}
}
}
如:
/**
* @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();
}
}
}
直接开撸代码:
/**
* @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();
}
}
}
至于如何求出外层循环变量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();
}
}
}
请听题:
/**
* 编写一个方法,根据参数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();
}
}
}
分析:
在方法一中,我们所用的代码可谓是封建时期老太婆的裹脚布 ——又臭又长,竟然用了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();
}
}
}
同样,请听题:
/**
* 编写一个方法,根据参数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();
}
}
}
其实绘制沙漏的方法二跟绘制菱形的方法二在本质上是一样的,同样的我们找出临界点:
但是此处做了一个改进:
即判断退出外层循环的条件,没有必要重新定义一个变量,只要保证"* "的数量<=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();
}
}
}