二维数组学习笔记
一、二维数组的定义
当一维数组元素的类型也是一维数组时,便构成了“数组的数组”,即二维数组。
二维数组定义的一般格式:
数据类型 数组名[常量表达式][常量表达式]
例如:
int a[4][10]
a数组实质上是一个有 \(4\) 行、 \(10\) 列的表格,表格中课存储 \(40\) 个元素。第 \(1\) 行第 \(1\) 列对应 \(a\) 数组的 \(a[0][0]\),第n行第m列对应数组元素 \(a[n-1][m-1]\)。
说明:当定义的数组下表有多个时,我们称为多维数组,下标的个数并不局限在一个或两个,可以任意多个,如定义一个三维数组 \(a\) 和四维数组 \(b\):
int a[5][3][10];
int b[100][100][20][5];
多维的数组引用赋值等操作与二维数组类似。
二、二维数组元素的引用
二维数组的数组元素引用于一位数组元素引用类似,区别在于二维数组元素的引用必须给出两个下标。
引用的格式为:
<数组名>[下标1][下标2]
说明:显然,每个下标表达式取值不应超出下标所指定的范围,否则会导致致命的越界错误。
例如,设有定义:
int a[3][5];
则表示 \(a\) 是二维数组(相当于一个 \(3 \times 5\) 的表格),共有 \(3 \times 5 = 15\) 个元素,它们是:
a[0][0] a[0][1] a[0][2] a[0][3] a[0][4]
a[1][0] a[1][1] a[1][2] a[1][3] a[1][4]
a[2][0] a[2][1] a[2][2] a[2][3] a[2][4]
因此可以看成一个矩阵(表格),\(a[2][3]\) 即表示第 \(3\) 行第 \(4\) 列的元素。
三、二维数组的初始化
二维数组的初始化和一维数组类似。可以将每一行分开来写在各自的括号里,也可以把所有数据写在一个括号里。
例如:
int direct[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int direct[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };
例1 对角线翻转
题目描述
给你一个 \(n \times n\) 的二维数组,你需要对其按照对角线进行翻转,并输出翻转后的二维数组。
例如,下面左边是一个 \(3 \times 3\) 的二维数组,后边是它按照对角线进行翻转后的二维数组:
1 2 3 1 4 7
4 5 6 2 5 8
7 8 9 3 6 9
输入格式
输入的第一行包含一个整数 \(n(1 \le n \le 100)\)。
接下来 \(n\) 行,每行包含 \(n\) 个整数,用于表示二维数组中的每个元素(每个元素均为 \(1000\) 以内的正整数)。
输出格式
输出 \(n\) 行,每行包含 \(n\) 个整数,两两之间以一个空格分隔,用于表示按对角线翻转后的二维数组。
样例输入
3
1 2 3
4 5 6
7 8 9
样例输出
1 4 7
2 5 8
3 6 9
问题分析
我们假设数组 \(a[i][j]\) 用于表示原二维数组中第 \(i\) 行第 \(j\) 列的元素,而沿对角线翻转后它的位置变到了第 \(j\) 行第 \(i\) 列。
所以,输入的时候,我们开两层for循环,外层循环遍历行号 \(i\),内层循环遍历列号 \(j\) ,输入 \(a[i][j]\);
而输出的时候,我们开两层for循环,外层循环遍历列号 \(j\),内层循环遍历行号 \(i\),输出 \(a[i][j]\) 即可。
示例代码:
#include <bits/stdc++.h>
using namespace std;
int n, a[100][100];
int main() {
cin >> n;
for (int i = 0; i < n; i ++) // 输入的时候先遍历行号i,再遍历列号j
for (int j = 0; j < n; j ++)
cin >> a[i][j]; // 输入a[i][j]
for (int j = 0; j < n; j ++) { // 输出的时候先遍历列号j,在遍历行号i
for (int i = 0; i < n; i ++) {
if (i > 0) cout << " "; // 除了最前面那个元素以外的元素前先数一个空格,能保证两两之间以一个空格分隔
cout << a[i][j]; // 输出a[i][j]
}
cout << endl; // 内层循环结束记得加一个回车
}
return 0;
}
例2 对角线增加
题目描述
已知一个 \(n \times n\) 的矩阵(方阵),把所有处在矩阵的两条对角线上面的元素都加上 \(10\),然后输出这个新矩阵。
输入格式
输入的第一行包含一个整数 \(n(1 \le n \le 100)\)。
接下来 \(n\) 行,每行包含 \(n\) 个整数,用于表示二维数组中的每个元素(每个元素均为 \(1000\) 以内的正整数)。
输出格式
输出 \(n\) 行,每行包含 \(n\) 个整数,两两之间以一个空格分隔,用于表示两条对角线上的元素都 \(+10\) 之后的矩阵。
样例输入
3
1 1 1
1 1 1
1 1 1
样例输出
11 1 11
1 11 1
11 1 11
问题分析
首先我们假设行号和列号都从 \(0\) 开始,即左上角的元素为 \(a[0][0]\),右下角的元素为 \(a[n-1][n-1]\),然后我们去遍历每一行(假设行号是 \(i\)),那么只有列号 \(j\) 满足条件 \(j==i\) 或者 \(j == n-1-i\) 的格子上的元素需要 \(+10\)。
当然我们要注意,当 \(n\) 为奇数时,中间的那个点 \(a[n/2][n/2]\) 同时处在了两条对角线上,但是只需要加一遍即可。
示例代码如下:
#include <bits/stdc++.h>
using namespace std;
int n, a[100][100];
int main() {
cin >> n;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++)
cin >> a[i][j];
for (int i = 0; i < n; i ++) {
if (i == n-1-i) // 说明第i行两条对角线上的点重叠了
a[i][i] += 10; // 所以只需要给这一个点+10即可
else { // 否则,需要给两个点依次+10
a[i][i] += 10;
a[i][n-1-i] += 10;
}
}
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
if (j) cout << " ";
cout << a[i][j];
}
cout << endl;
}
return 0;
}
例3 稀疏矩阵存储方案
题目描述
大部分元素是 \(0\) 的矩阵称为 稀疏矩阵 ,假设有 \(k\) 个非 \(0\) 元素,则可把稀疏矩阵用 \(k \times 3\) 的矩阵简记之,其中第一列是行号,第二列是列号,第三列是该行、该列下的非零元素的值。如:
0 0 0 5 简记为: 1 4 5 // 第1行第4列有一个5
0 2 0 0 2 2 2 // 第2行第2列有一个2
0 1 0 0 3 2 1 // 第3行第2列有一个1
试编程读入一稀疏矩阵,转换成简记形式,并输出。
输入格式
输入的第一行包含两个整数 \(n,m(1 \le n \le 100)\),分别表示矩阵的行数和列数。
接下来 \(n\) 行,每行包含 \(m\) 个整数,用于表示二维数组中的每个元素(每个元素均为 \(1000\) 以内的正整数)。
输出格式
输出若干行,每行包含 \(3\) 个整数,以空格分隔,分别表示行号、列号和该非零元素的值。
请按照行号从小到大,行号相同的列号从小到大输出这些数据。
样例输入
3 4
0 0 0 5
0 2 0 0
0 1 0 0
样例输出
1 4 5
2 2 2
3 2 1
问题分析
本题中需要解决的主要问题是查找非零元素并记忆位置。将原始矩阵存于数组 \(a\)。转换后的矩阵存于数组 \(b\),当然 \(b\) 数组的行数可以控制在一个可控范围内。
我们可以开一个变量 \(k\),一开始 \(k=0\),然后我们去遍历每一行每一列。
如果第 \(i\) 行第 \(j\) 列的元素 \(a[i][j] \ne 0\),则执行如下操作:
k ++;
b[k][0] = i;
b[k][1] = j;
b[k][2] = a[i][j];
这样,最终我们可以的数据将会保存在 \(b\) 数组中坐标从 \(1\) 到 \(k\) 范围内。
示例代码:
#include <bits/stdc++.h>
using namespace std;
int n, m, a[101][101], b[10010][3], k;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
cin >> a[i][j];
if (a[i][j]) { // 输入的同时就进行判断
k ++;
b[k][0] = i; // 标记行号
b[k][1] = j; // 标记列号
b[k][2] = a[i][j]; // 标记数值
}
}
}
for (int i = 1; i <= k; i ++)
cout << b[i][0] << " " << b[i][1] << " " << b[i][2] << endl;
return 0;
}