-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
145 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
--- | ||
layout: post | ||
title: "如何更通俗易懂的解释 C++ 二维数组" | ||
date: 2024-03-21 14:21:14 +0800 | ||
categories: cpp multidimensional-arrays | ||
--- | ||
|
||
## 图书馆的书架 | ||
|
||
![9NIP9a](https://raw.githubusercontent.com/jamiesun/images/master/default/9NIP9a.jpg) | ||
|
||
想象一下,一家大型的图书馆。在这座图书馆里,有无数个书架,每个书架上都整齐地排列着一行行的书籍。如果你想找到一本特定的书,你需要知道它在哪个书架上,以及它在这个书架上的具体位置。在这里,书架就像是一个一维数组,它代表这本书的“行”位置,而书架上的每个位置就像是一维数组中的一个元素,代表这本书的“列”位置。把这个概念扩展到二维,你实际上就有了一大堆书架,且每个书架都有自己的书籍排列,构成了一个二维数组。 | ||
|
||
在 C++ 中,一个二维数组就像这个图书馆。你可以想象它为一个大表格,表格里有很多行(书架)和列(书本)。就像在图书馆你需要行和列的信息来找到一本书一样,你在 C++ 的二维数组中需要两个坐标:一个代表行的索引和一个代表列的索引。用代码来说,如果你有一个名为 `bookshelves` 的二维数组,`bookshelves[3][2]` 就像是在图书馆中跑到第四个书架上,然后拿起了这个书架上从左边数的第三本书。 | ||
|
||
使用二维数组时,每个维度都可以想象成是数组中的一个级别。第一个维度通常代表“行”,就像书架一样;而第二个维度代表“列”,就像书本在书架上的摆放。同样,在 C++ 中,如果你创建了一个二维数组 `int seats[2][3]`,可以想象这是一个拥有两排(`2` 行)和每排三个座位(`3` 列)的小型电影院。 | ||
|
||
让我们构建一个关于图书馆的书架的例子。我们会创建一个包含书架和书籍的二维数组,并且尝试访问其中一个特定的书籍。 | ||
|
||
```cpp | ||
#include <iostream> | ||
|
||
int main() { | ||
// 创建一个有 4 个书架的图书馆,每个书架可以存放 5 本书 | ||
std::string library[4][5] = { | ||
{"Book1-1", "Book1-2", "Book1-3", "Book1-4", "Book1-5"}, | ||
{"Book2-1", "Book2-2", "Book2-3", "Book2-4", "Book2-5"}, | ||
{"Book3-1", "Book3-2", "Book3-3", "Book3-4", "Book3-5"}, | ||
{"Book4-1", "Book4-2", "Book4-3", "Book4-4", "Book4-5"} | ||
}; | ||
|
||
// 想找到第 3 个书架上的第 2 本书 | ||
int shelf = 2; // 由于数组索引从 0 开始,第 3 个书架其索引是 2 | ||
int book = 1; // 同样地,第 2 本书的索引是 1 | ||
std::cout << "Book at shelf " << shelf + 1 << ", position " << book + 1 << ": "; | ||
std::cout << library[shelf][book] << std::endl; | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
## 操场上的方阵 | ||
|
||
![69wAsx](https://raw.githubusercontent.com/jamiesun/images/master/default/69wAsx.png) | ||
|
||
想象一个宽阔的操场,在特别的活动日上,学校的学生们被安排成一个完美的方阵形式进行表演。每个学生站在操场的一个特定位置上,一排排的学生形成了横行,一列列则形成了纵列。这和C++中的二维数组非常相似。 | ||
|
||
如果我们将这个操场抽象成一个二维数组,那么每一行学生可以看作是数组的一行,每一列学生就是数组的一列。当我们指涉“操场上的方阵”时,我们实际上是在说一个由行(row)和列(column)组成的结构。 | ||
|
||
以 C++ 中的数组表示,如果操场上的方阵用变量 `students` 来代表,那么 `students[2][3]` 就代表着第三排的第四个学生。这是因为,在编程中,索引是从零开始的。所以,`students[0][0]` 表示的是第一排的第一个学生,而 `students[2][3]` 则定位在第三排的第四个学生。 | ||
|
||
使用这个类比,二维数组的概念变得生动且具象化。学生们站成的方阵就如同一个表格,里面的每个位置既有行的坐标也有列的坐标。我们可以轻松地通过这两个坐标找到任意一个特定的学生,就像我们在 C++ 中使用行索引和列索引来访问数组元素那样简单。 | ||
|
||
示例如下: | ||
|
||
```cpp | ||
#include <iostream> | ||
|
||
int main() { | ||
// 设定一个学生方阵,3 行 4 列 | ||
std::string students[3][4] = { | ||
{"Alice", "Bob", "Charlie", "David"}, | ||
{"Eva", "Frank", "Grace", "Helen"}, | ||
{"Irene", "Jack", "Kathy", "Leo"} | ||
}; | ||
|
||
// 想找到第 3 排的第 4 个学生 | ||
int row = 2; // 第 3 排的索引是 2 | ||
int col = 3; // 第 4 个学生的索引是 3 | ||
std::cout << "Student at row " << row + 1 << ", column " << col + 1 << ": "; | ||
std::cout << students[row][col] << std::endl; | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
现在我们使用两层嵌套循环来模拟每个学生轮流报出自己名字的情景。外层循环将遍历每一排(二维数组的第一个维度),而内层循环将遍历每一排中的每个学生(二维数组的第二个维度)。 | ||
|
||
下面是示例代码: | ||
|
||
```cpp | ||
#include <iostream> | ||
|
||
int main() { | ||
// 定义了一个 3 行 4 列的学生方阵 | ||
std::string students[3][4] = { | ||
{"Alice", "Bob", "Charlie", "David"}, | ||
{"Eva", "Frank", "Grace", "Helen"}, | ||
{"Irene", "Jack", "Kathy", "Leo"} | ||
}; | ||
|
||
// 外层循环遍历操场上的每一排(行) | ||
for (int row = 0; row < 3; ++row) { | ||
// 内层循环遍历每排(行)的每个学生(列) | ||
for (int col = 0; col < 4; ++col) { | ||
// 输出当前学生的名字,并行报数 | ||
std::cout << "Student at row " << row + 1 << ", column " << col + 1 << " is: "; | ||
std::cout << students[row][col] << std::endl; | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
当这段代码执行时,它将逐个访问二维数组 `students` 中的每个元素。`row` 和 `col` 变量分别表示当前遍历到的行索引和列索引。在数组里,行和列的索引都是从 `0` 开始计数的,所以第一个学生的位置是 `students[0][0]`。每访问到一个学生,程序都会输出学生所在的行和列,以及学生的名字。这个过程会重复进行直到数组中的所有学生都被访问一次,仿佛每个学生轮流报出自己的名字。 | ||
|
||
## 二维数组的特点 | ||
|
||
1. **像个格子状的表格**:二维数组就像是一个Excel表格,有行有列。想象一下,你在看一个足球队的排名表,上面有不同的队伍(行)和他们在每个赛季的得分(列)。 | ||
|
||
2. **由一维数组组成**:每一行(或者说每个书架)其实就是一个一维数组。正如图书馆中的每个书架都放着一排书一样,这些一维数组合在一起就形成了一个二维数组。 | ||
|
||
3. **通过两个索引来访问**:想找到特定的信息,比如书架上的某一本书,你需要两个索引:一个代表书架的行,另一个代表书的列。这跟你在游乐园地图里找厕所是一个道理,你需要知道它在哪个区域的哪个位置。 | ||
|
||
4. **存储相同类型的元素**:每个格子(或者学生的位置)里存放的元素都是同一类型的。比如,整个学生方阵里的每个位置都填着学生的名字。 | ||
|
||
5. **固定的行和列大小**:通常,当你定义了一个二维数组,你就固定了它的行数和列数。这就跟买衣服一样,一旦标签上写的是中号,你就不能随意把它拉伸成大号。 | ||
|
||
6. **可以用循环遍历**:你可以使用两层循环来遍历二维数组的每个元素。就像在学校操场的方阵练习中,教练会从第一个学生开始检查,一列一列地走过去,确保每个学生都在正确的位置。 | ||
|
||
7. **动态和静态都行**:虽然我们上面的例子用的是静态数组,也就是在编译时就固定大小的数组,但C++也允许创建动态的二维数组,那种可以在程序运行时确定大小的数组。这就像你决定在家里搭一个书架,随时可以根据需要添加新的层。 | ||
|
||
8. **初始化时可选**:在创建二维数组时,你可以选择是否立即填满它。就像买了一个书架,你可以先放几本你最爱的书,也可以一次性把它装满。 | ||
|
||
9. **可以嵌套多层**:二维数组的概念可以扩展到三维、四维,以此类推,每增加一个维度就像是再增加一个维度的索引。这就有点像三维电影,你不仅知道角色的左右和上下位置,还可感受到他们离你有多远。 | ||
|
||
|
||
## 典型的应用场景 | ||
|
||
1. **游戏开发中的棋盘和地图设计**:在游戏设计领域,二维数组是构建棋盘和各类游戏地图的理想工具。比如说,一个国际象棋游戏就可以用一个8x8的数组来表示。开发者可以使用二维数组来跟踪每个棋子的位置,判断移动是否合法,以及保存游戏的状态。 | ||
|
||
2. **电子表格的数据存储**:我们都知道微软的Excel或谷歌表格都是处理表格数据的利器。在幕后,这些数据通常以二维数组的形式存储,这样可以轻易地通过行和列来访问每一个数据单元。这就像我们前面提到的足球队排名表,有清晰的行(队伍)和列(赛季得分)。 | ||
|
||
3. **图像处理应用**:图像实际上可以被视为一个二维数组,每个元素代表图片中的一个像素点。在图像处理应用中,二维数组被用来存储和操作像素值,进行图片编辑,诸如滤镜、旋转、缩放等操作。 | ||
|
||
4. **社交网络分析**:在社交网络分析中,二维数组可能被用来表示用户之间的关系。例如,数组的行和列都可以代表不同的用户,而数组中的值可以表示一对用户之间的关系状态,如好友、屏蔽或者关注。 | ||
|
||
5. **矩阵计算在科学中的应用**:在物理、工程和计算机科学等领域,矩阵是一种基本的数学工具,通常用二维数组来表示。它们用于描述和模拟复杂的系统,例如天气模型、飞机设计模拟或者在量子计算中的状态变换。 | ||
|
||
6. **存储表结构数据**:在软件开发中,不少情况下需要处理和存储来自数据库的表结构数据。二维数组提供了一个便利的方式来缓存这些数据,供程序处理和显示。 | ||
|
||
7. **教育工具中的示范和实践**:在编程教学中,二维数组是一个很好的教学工具。它可以帮助学生们更好地理解数据的组织方式和多维数据结构。比如,可以通过二维数组教导学生如何进行棋类游戏编程,或者创建简单的地图应用等。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters