打印正方形
前言
我们已经学会了使用for和while
来控制循环,但是有的时候循环不止一层,这就需要使用到“循环嵌套”,即在一个循环内部包含另一个或多个循环,内层的循环会在外部循环的每次迭代中都完整执行一次。
或许这样说还不够直观,那本节我们就通过一道题目来带你使用循环嵌套。
循环嵌套
我们在之前的学习中,已经知道了如何遍历数组结构,比如下面一个长度为5的数组。
for(int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
但数据的组织形式除了是一维的,还可能是多维的,比如数学中的矩阵、表格、游戏棋盘。
上图中的数据就是一个二维数组,它是由行和列组成的表格状数据结构,可以理解为包含其他数组的数组,二维数组的元素可以通过两个索引来访问,一个索引表示行,另一个表示列, 比如arr[0][0]
表示第一行第一列的元素,值为1,arr[2][2]
表示第三行第三列的元素,值为13。
由于是二维的,显然这个时候想要直接通过一层for循环来实现遍历是不太现实的,这就需要使用到前言中所讲的循环嵌套。
// 遍历二维数组
for (int i = 0; i < 5; i++) { // 外部循环迭代行,也就是第一行,第二行... 第n行
for (int j = 0; j < 5; j++) { // 内部循环迭代列,也就是第一列,第二列...第n列
std::cout << arr[i][j] << " "; // 输出元素值
}
std::cout << std::endl; // 在每行结束后换行
}
这里就使用了两层for循环
, 外部的 for
循环 i
用于控制迭代行,在每一行的迭代内部,有了第二个for循环,用于控制每一行中各列的迭代(即一个一维数组),通过这两个循环的嵌套,可以遍历整个二维数组,并使用 arr[i][j]
访问每个元素的值。在每行结束后,使用 std::endl
换行到下一行。
代码编写
题目要求我们模拟打印一个正方形的框,根据题目可以联想到我们需要使用循环嵌套来控制行和列的打印,并根据当前行和列的位置来决定打印 "*"(外部边界)还是空白(内部)。
我们先把代码的基础结构给书写完整
#include<iostream>
using namespace std;
int main() {
// n代表正方形的边长
int n;
// 输入n
cin >> n;
}
然后我们需要一个循环嵌套来控制打印
// 外层for循环控制每一行
for(int i = 0; i < n; i++) {
// 内层for循环控制每一列
for(int j = 0; j < n; j++) {
}
// 每行打印完之后,输出换行,行数i + 1, 转到下一行中
cout << endl;
}
题目要求我们只打印边界,也就是说对于边界的内容打印"*"
,非边界的内容打印空白,这种结构满足之前所讲的根据某个条件来选择不同的代码路径执行,需要使用到if-else
。
// 如果处于边界,打印 *
if () {
cout << "*";
} else {
// 否则,打印空格
cout << " ";
}
所需要判定的边界其实指的是第一行、最后一行、第一列、最后一列,只需要满足这四个条件中的任何一个就表示当前遍历的位置处在边界中。
i == 0; // 表示第一行
i == n - 1; // 表示最后一行
j == 0; // 表示第一列
j == n - 1; // 表示最后一列
四个条件,不可能使用四个if语句
来进行判定,我们可以使用之前所讲的逻辑或运算符||
来组合多个条件,只要其中任何一个条件为真(true
),整个表达式就会被认为是真(true
)
if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {
// 只要满足上面条件的一个,就会判定为真,执行逻辑体中的代码
}
完整代码如下:
#include<iostream>
using namespace std;
int main() {
// 输入正方形的边长
int n;
cin >> n;
// 打印正方形框
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
// 判断是否在边界位置,如果是,则打印 "*"
if (i == 0 || i == n -1 || j == 0 || j == n - 1) {
cout << "*";
} else {
// 否则,打印空格
cout << " ";
}
}
// 换行到下一行输出
cout << endl;
}
}
延伸
除了for
循环嵌套之外,C++中的循环嵌套还有多种形式,比如while循环嵌套
int i = 0, j = 0;
while (i < 5) {
while (j < 5) {
// 嵌套循环的代码
j++;
}
i++;
j = 0; // 重置内部循环的计数器
}
还可以混合使用不同类型的循环,例如将for循环嵌套在while循环内,或者将while循环嵌套在do-while循环内
int i = 0;
while (i < 5) {
for (int j = 0; j < 5; j++) {
// 嵌套循环的代码
}
i++;
}
如果有多层嵌套循环,
break
和continue
只会退出最内层的循环
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (j == 1) {
break; // 这将退出内层循环,但外层循环仍然继续执行
}
}
}
总结
本节课我们学习了通过循环嵌套来控制二维结构的遍历,其基本结构如下:
// 外层控制遍历行
for (int i = 0; i < numRows; i++) {
// 内层控制遍历列
for (int j = 0; j < numCols; j++) {
// 在这里执行操作,处理二维数组的元素 arr[i][j]
}
}
循环嵌套在编程中非常常见,常用于处理各种复杂的迭代,但是需要注意的是,如果嵌套层级过深,可能会导致性能问题,所以即便嵌套好用,但不要过度依赖它!