C++ 嵌套循环

939 阅读7分钟

也称为多循环,在一个循环中嵌套使用一个或多个循环。
嵌套循环的基本结构就是在一个循环中,循环体包含了另一个循环的情况。下面我用几个嵌套循环的例子来深入理解嵌套循环。

循环图案打印

分别打印下面三种图案:

思路分析

一般来说,单循环打印的图案都是线性的,要么是横线要么是竖线。那么我们这里需要打印一个二维图形,就需要从线跨越到面。那么我们只要有很多条线就能构成一个平面,所以我们这里打印二维图形就需要两个循环来实现。

那么我们这里规定外层循环控制行,内层循环控制列。然后找到图形中行与列的关系,通过控制内层循环的循环条件,就可以打印出需要的图形。

1. 实心菱形星星

菱形可以看做两个三角形组成的,一个正等腰三角,一个倒等腰三角。这里就可以通过 if 语句来根据行数改变列的循环条件,从而实现打印两个图形并组合。
下面是参考代码:

#include <iostream>

using namespace std;

int main() {
    // 打印菱形星星
    int row_max = 7;
    int col_max, space_max;

    // 外层循环控制行 (行数,换行)
    // 内层循环控制列 (列数,列的图形)
    for (int row = 0; row < row_max; row++) {
        if (row < 4) {      // 第4行之前*号数量为 2*row ,空格数量为 2-row
            col_max = 2 * row;
            space_max = 2 - row;
        } else {            // 第4行之后*号数量递减2,空格数量递增1
            col_max -= 2;
            space_max += 1;
        }
        // 打印*号前的空格
        for (int space = 0; space <= space_max; space++) {
            cout << " ";
        }
        // 打印*号
        for (int col = 0; col <= col_max; col++) {
            cout << "*";
        }
        cout << endl;   // 进行换行
    }
    
    system("pause");
    return 0;
}

输出结果如下:

   *
  ***
 *****
*******
 *****
  ***
   *
请按任意键继续. . . 

2. 实心菱形字母

这里和实心菱形星星改变的只有打印的内容,整体的图形还是没变的。所以我们这里只要改变上面程序中打印的内容就行。
下面是参考代码:

...
    for (...) {
        ...
        // 打印字母
        for (int col = 0; col <= col_max; col++) {
            cout << (char)('A' + row);          //使字母根据行数变化
        }
        ...
    }
...

输出结果如下:

   A
  BBB
 CCCCC
DDDDDDD
 EEEEE
  FFF
   G
请按任意键继续. . .

3. 空心菱形星星

这里和实心菱形星星改变的也是内循环的内容,整体图形没有变化。所以只需要改变打印内容即可。
下面是参考代码:

...
    for (...) {
        ...
        // 按规则打印星星
        for (int col = 0; col <= col_max; col++) {
            if (col == 0 || col == col_max)         // 只在开始和末尾打印星星
                cout << '*';
            else
                cout << ' ';
        }
        ...
    }
...

输出结果如下:

   *
  * *
 *   *
*     *
 *   *
  * *
   *
请按任意键继续. . .

打印蛇形矩阵

顾名思义,蛇形矩阵:矩阵的一种,常被应用在编程题目与数学数列中。
它由1开始的自然数依次排列成的一个矩阵,有上三角、环形或对角线等走法,输入文件由一行或多行组成,每行由一个正整数N组成(N不大于100)。

下面练习一些常见的蛇形矩阵:

1. 上三角

要实现如下效果:

请输入一个(1-10)的正整数:5
1       3       4       10      11
2       5       9       12      19
6       8       13      18      20
7       14      17      21      24
15      16      22      23      25

可以发现上述表格的规律是,从左上角第一个格开始(起始为1),然后沿右上角到左下角的斜线,先从下到上,再从上到下。开始数字递增排列。

我们可以想象有一个游戏角色在一个 5*5 的格子上进行走动,每个数字就是他走的步数。这个角色只有4个移动方向,分别为向下、向右上、向右和向左下。那么我们就可以创造一个 (x,y)来表示角色的坐标。再用一个数组来记录每个坐标当中的步数是什么。
下面是参考代码:

#include <iostream>

using namespace std;

int main() {
    // 上三角
    int num;
    cout << "请输入一个(1-10)的正整数:";
    cin >> num;     //定义格子的长宽
    int* arr = new int[num*num];
    // 移动方向,分别是向下,向右上,向右,向左下
    const int step[4][2] = {0,1, 1,-1, 1,0, -1,1};
    // 初始坐标为(0,0),方向向下
    int x = 0, y = 0, direction = 0;
    arr[0] = 1;

    for (int value = 2;value <= (num*num); value++) {
        // 进行移动
        x += step[direction][0];
        y += step[direction][1];
        // 记入当前坐标对应的数据
        arr[y*num + x] = value;

        // 判断下一步方向
        switch (direction) {
        case 0:     // 向下之后
            direction = x == 0 ? 1 : 3;
            break;
        case 1:     // 向右上之后
            if (y == 0 || x == (num-1))
                direction = x == (num-1) ? 0 : 2;
            break;
        case 2:     // 向右之后
            direction = y == 0 ? 3 : 1;
            break;
        case 3:     // 向左下之后
            if (x == 0 || y == (num-1))
                direction = y == (num-1) ? 2 : 0;
            break;
        }
    }
    // 按照存储在数组 arr 中的数据,将每个坐标的值打印
    for (y = 0; y < num; y++) {
        for (x = 0; x < num; x++) {
            cout << arr[y*num + x] << '\t';
        }
        cout << endl;
    }

    delete [] arr;

    system("pause");
    return 0;
}

输出结果如下:

请输入一个(1-10)的正整数:7
1       3       4       10      11      21      22
2       5       9       12      20      23      34
6       8       13      19      24      33      35
7       14      18      25      32      36      43
15      17      26      31      37      42      44
16      27      30      38      41      45      48
28      29      39      40      46      47      49
请按任意键继续. . .

2. 环形

要实现如下效果:

请输入一个(1-10)正整数:5
1       2       3       4       5
16      17      18      19      6
15      24      25      20      7
14      23      22      21      8
13      12      11      10      9

可以发现上述表格的规律是,从左上角第一个格开始(起始为1),进行顺时针绕圈圈移动。开始数字递增排列。

这里则可以认为这个角色在绕圈圈。这个角色只有4个移动方向,分别为向右、向下、向左和向上。这个角色每绕一圈,他所能走的格子宽度就减小 1。
下面是参考代码:

#include <iostream>

using namespace std;

int main() {
    // 环形
    int num;
    cout << "请输入一个(1-10)正整数:";
    cin >> num;
    int* arr = new int[num*num];
    // 移动方向,分别是向右,向下,向左,向上
    const int step[4][2] = {1,0, 0,1, -1,0, 0,-1};
    // 初始坐标为(0,0),方向向右
    int x = 0, y = 0, direction = 0;
    // 这里初始化角色能走的格子尺寸
    int limit = num - 1;
    arr[0] = 1;

    for (int value = 2;value <= (num*num); value++) {
        //进行移动
        x += step[direction][0];
        y += step[direction][1];
        arr[y*num + x] = value;
        //判断是否需要改变方向
        switch (direction) {
        case 0:     // 向右之后,到可走格子边界就向下否则继续向右
            direction = x == limit ? 1 : 0;
            break;
        case 1:     // 向下之后,到可走格子边界就向左否则继续向下
            direction = y == limit ? 2 : 1;
            break;
        case 2:     // 向左之后,到可走格子边界就向上否则继续向左
            direction = x == (num - limit -1) ? 3 : 2;
            break;
        case 3:     // 向上之后,到可走格子边界就向右,并且可走格子尺寸减少 1 ,否则继续向上
            if (y == (num - limit)) {
                limit -= 1;
                direction = 0;
            }
            break;
        }
    }
    // 按照存储在数组 arr 中的数据,将每个坐标的值打印
    for (y = 0; y < num; y++) {
        for (x = 0; x < num; x++) {
            cout << arr[y*num + x] << '\t';
        }
        cout << endl;
    }

    delete [] arr;

    system("pause");
    return 0;
}

输出结果如下:

请输入一个(1-10)正整数:7
1       2       3       4       5       6       7
24      25      26      27      28      29      8
23      40      41      42      43      30      9
22      39      48      49      44      31      10
21      38      47      46      45      32      11
20      37      36      35      34      33      12
19      18      17      16      15      14      13
请按任意键继续. . .