数组
约 4580 字大约 15 分钟
2025-06-25
数组与数组下标
数组
在C++中,数组是存储相同类型元素的连续内存空间,通过下标访问元素,是信奥赛中处理批量数据的核心工具(如存储数列、矩阵、图的邻接表等)。
一、数组的基本概念
基本概念
1. 定义与初始化
数组定义的基本语法:
数据类型 数组名[元素个数];
初始化方式:
- 完全初始化:指定所有元素的值
int arr[5] = {1, 2, 3, 4, 5}; // 5个元素分别为1~5
- 部分初始化:未指定的元素自动为0(数值类型)或空(字符类型)
int arr[5] = {1, 2}; // 元素为1,2,0,0,0
- 省略长度初始化:编译器根据初始值数量自动确定长度
int arr[] = {1, 2, 3}; // 长度为3的数组
2. 数组的特性
- 同类型元素:数组中所有元素必须是同一数据类型(如
int
、double
)。 - 连续内存:元素在内存中连续存储,可通过地址偏移快速访问。
- 固定长度:数组长度在定义时确定,且不能动态修改(信奥赛中需提前预估最大需求)。
二、数组下标(索引)
下标
1. 下标的作用与语法
数组通过下标(索引) 访问元素,语法:
数组名[下标]
示例:
int arr[5] = {10, 20, 30, 40, 50};
cout << arr[0]; // 输出第1个元素10
arr[2] = 300; // 修改第3个元素为300
2. 下标规则(信奥赛核心考点)
- 从0开始:数组第1个元素的下标为0,第n个元素的下标为
n-1
。
长度为len
的数组,下标范围是0 ~ len-1
。 - 越界风险:访问下标
<0
或≥len
的元素会导致数组越界,可能读取垃圾值或修改其他内存数据,导致程序崩溃(信奥赛高频错误)。
错误示例:c++int arr[5] = {1,2,3,4,5}; cout << arr[5]; // 越界访问(下标5≥长度5),结果未知
三、数组的遍历(信奥赛必会技能)
遍历
遍历数组即依次访问所有元素,通常用for
循环结合下标实现:
1. 基本遍历
int arr[5] = {1,2,3,4,5};
for (int i = 0; i < 5; i++) { // i从0到4(下标范围)
cout << arr[i] << " ";
}
// 输出:1 2 3 4 5
2. 用常量定义长度(推荐)
为避免硬编码长度导致越界,用const
常量定义长度:
const int N = 5; // 定义常量表示长度
int arr[N] = {1,2,3,4,5};
for (int i = 0; i < N; i++) { // 用N控制循环范围,修改方便
cout << arr[i] << " ";
}
四、多维数组(以二维数组为例)
二维数组
信奥赛中常用二维数组表示矩阵、表格等,本质是“数组的数组”。
1. 定义与初始化
// 定义3行4列的二维数组
int matrix[3][4] = {
{1, 2, 3, 4}, // 第0行
{5, 6, 7, 8}, // 第1行
{9, 10, 11, 12} // 第2行
};
2. 二维数组的下标
二维数组通过行下标和列下标访问元素,均从0开始:
cout << matrix[1][2]; // 访问第1行第2列的元素7
matrix[0][3] = 100; // 修改第0行第3列的元素为100
3. 二维数组的遍历
用嵌套for
循环遍历,外层控制行,内层控制列:
const int ROW = 3, COL = 4;
int matrix[ROW][COL] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
for (int i = 0; i < ROW; i++) { // 行下标i
for (int j = 0; j < COL; j++) { // 列下标j
cout << matrix[i][j] << " ";
}
cout << endl; // 每行结束换行
}
五、信奥赛常见应用
应用
存储批量数据:如统计多个学生的成绩、多个点的坐标等。
c++const int STUDENTS = 50; int scores[STUDENTS]; // 存储50个学生的成绩
频率计数:用数组下标表示数值,元素值表示出现次数(哈希思想)。
c++int freq[10] = {0}; // 统计0~9的出现次数 int nums[] = {1,3,5,3,3,7}; for (int x : nums) { freq[x]++; // 对应数字的计数+1 } // freq[3]的值为3(数字3出现3次)
滑动窗口:在数组中通过下标范围截取子数组(如求连续子数组的最大和)。
六、避坑指南
注意
数组越界:始终确保下标在
0 ~ len-1
范围内,尤其循环中注意终止条件(如i < len
而非i <= len
)。未初始化的数组:局部数组(如函数内定义的数组)若未初始化,元素值为随机垃圾值,需手动初始化(如
int arr[5] = {0};
)。二维数组的长度:C++中二维数组的列数必须显式指定,行数可省略(如
int arr[][4] = {{1,2}, {3,4}};
)。大数组的定义位置:过大的数组(如
int arr[1000000]
)应定义在函数外(全局变量),避免栈内存溢出。
七、实战:数组求最值
数组求最值
题目:输入5个整数,找出其中的最大值和最小值。
#include <iostream>
using namespace std;
int main() {
const int N = 5;
int arr[N];
// 输入数组元素
cout << "输入" << N << "个整数:";
for (int i = 0; i < N; i++) {
cin >> arr[i];
}
// 求最值
int max_val = arr[0], min_val = arr[0];
for (int i = 1; i < N; i++) { // 从第2个元素开始比较
if (arr[i] > max_val) {
max_val = arr[i];
}
if (arr[i] < min_val) {
min_val = arr[i];
}
}
cout << "最大值:" << max_val << endl;
cout << "最小值:" << min_val << endl;
return 0;
}
要点
数组是信奥赛中处理数据的基础结构,熟练掌握下标操作和遍历技巧是解决批量数据问题的关键。尤其要注意下标越界和初始化问题,这是新手最易犯错的点。
数组的读入与输出
数组的读入与输出
在C++中,数组的读入与输出是信奥赛的基础操作,通常结合循环结构实现批量数据的处理。
一、一维数组的读入与输出
一维数组的读入与输出
一维数组的读写核心是通过下标循环访问每个元素,配合cin
(读入)和cout
(输出)完成操作。
1. 基本方法
#include <iostream>
using namespace std;
int main() {
const int N = 5; // 数组长度(用常量定义,方便修改)
int arr[N]; // 定义int类型数组
// 读入数组元素
cout << "请输入" << N << "个整数:";
for (int i = 0; i < N; i++) { // 下标i从0到N-1
cin >> arr[i]; // 依次读入每个元素
}
// 输出数组元素
cout << "数组元素为:";
for (int i = 0; i < N; i++) {
cout << arr[i] << " "; // 依次输出每个元素,用空格分隔
}
cout << endl; // 输出结束后换行
return 0;
}
2. 常见变体
输出格式控制:根据需求调整分隔符(如逗号、换行):
c++// 每行输出2个元素 for (int i = 0; i < N; i++) { cout << arr[i]; if ((i + 1) % 2 == 0) { // 每2个元素换行 cout << endl; } else { cout << " "; // 否则用空格分隔 } }
从文件读入/输出到文件(信奥赛常用,需包含
<fstream>
):c++#include <fstream> // ... ifstream fin("input.txt"); // 打开输入文件 ofstream fout("output.txt"); // 打开输出文件 // 从文件读入 for (int i = 0; i < N; i++) { fin >> arr[i]; } // 输出到文件 for (int i = 0; i < N; i++) { fout << arr[i] << " "; }
二、二维数组的读入与输出
二维数组的读入与输出
二维数组的读写需用嵌套循环,外层循环控制行,内层循环控制列。
1. 基本方法
#include <iostream>
using namespace std;
int main() {
const int ROW = 3, COL = 4; // 3行4列
int matrix[ROW][COL]; // 定义二维数组
// 读入二维数组
cout << "请输入" << ROW << "行" << COL << "列的矩阵:" << endl;
for (int i = 0; i < ROW; i++) { // 行下标i
for (int j = 0; j < COL; j++) { // 列下标j
cin >> matrix[i][j]; // 读入第i行第j列元素
}
}
// 输出二维数组(按矩阵格式)
cout << "矩阵内容为:" << endl;
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
cout << matrix[i][j] << " "; // 输出一行元素
}
cout << endl; // 一行结束后换行
}
return 0;
}
2. 注意事项
- 输入顺序:通常按行输入(先输入第0行所有元素,再输入第1行,以此类推)。
- 列数固定:C++中二维数组的列数必须显式指定,行数可省略(如
int matrix[][4] = ...
)。
三、信奥赛高频与技巧
高频与技巧
1. 未知长度的数组处理
若输入数据量未知(但不超过预设最大值),可先读入元素总数,再动态控制循环:
const int MAX_N = 1000; // 预设最大长度
int arr[MAX_N];
int n;
cout << "请输入元素个数:";
cin >> n;
// 读入n个元素(确保n ≤ MAX_N,避免越界)
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
2. 字符数组的读写
字符数组(字符串)可直接用cin
/cout
整行读写(无需循环):
char str[100];
cin >> str; // 读入字符串(遇空格/回车结束)
cout << str << endl; // 输出整个字符串
// 读入带空格的字符串(需用getline)
cin.ignore(); // 清除缓冲区的换行符
cin.getline(str, 100); // 读入整行(包括空格)
3. 数组输出的效率优化
当数组元素过多(如1e5个),用cout
输出可能较慢,可改用printf
(需包含<cstdio>
):
#include <cstdio>
// ...
for (int i = 0; i < N; i++) {
printf("%d ", arr[i]); // 比cout快,适合大数据量
}
四、避坑指南
避坑指南
下标越界:循环条件必须严格控制在
0 ~ len-1
,例如:c++// 错误:i从1开始,漏掉第0个元素 for (int i = 1; i <= N; i++) { ... } // 正确:i从0开始,到N-1结束 for (int i = 0; i < N; i++) { ... }
输入缓冲区残留:连续读写不同类型数据时(如先读整数再读字符串),需用
cin.ignore()
清除残留的换行符,否则可能读入空内容。大数组的定义:容量超过1e5的数组应定义为全局变量(在
main
函数外),避免栈内存溢出:c++const int MAX_N = 1000000; int big_arr[MAX_N]; // 全局数组,内存空间更大 int main() { // ... 使用big_arr ... }
五、实战:统计数组中偶数的个数并输出
统计数组中偶数的个数并输出
#include <iostream>
using namespace std;
int main() {
const int N = 6;
int arr[N];
int even_count = 0;
// 读入数组
cout << "输入" << N << "个整数:";
for (int i = 0; i < N; i++) {
cin >> arr[i];
}
// 统计偶数并输出
cout << "其中偶数有:";
for (int i = 0; i < N; i++) {
if (arr[i] % 2 == 0) {
even_count++;
cout << arr[i] << " ";
}
}
cout << "\n偶数个数:" << even_count << endl;
return 0;
}
要点
数组的读入与输出是信奥赛中处理批量数据的基础,核心是通过循环控制下标,确保访问范围合法。熟练掌握不同维度数组的读写技巧,以及输入输出的效率优化方法,能为解决复杂问题打下坚实基础。
二维数组与多维数组
二维数组与多维数组
在C++中,二维数组和多维数组是处理结构化数据(如矩阵、表格、三维模型坐标等)的重要工具,在信奥赛中广泛应用于动态规划、图论、矩阵运算等场景。
一、二维数组(核心重点)
二维数组
二维数组可理解为“数组的数组”,本质是按行优先顺序存储的连续内存块,适合表示矩阵、表格等二维结构。
1. 定义与初始化
基本语法:
数据类型 数组名[行数][列数];
初始化方式:
- 完全初始化(按行分组):
// 3行4列的二维数组,每行元素用{}包裹
int matrix[3][4] = {
{1, 2, 3, 4}, // 第0行
{5, 6, 7, 8}, // 第1行
{9, 10, 11, 12} // 第2行
};
- 部分初始化(未指定元素默认为0):
int matrix[3][4] = {{1}, {5,6}, {9}};
// 结果:
// 第0行:1, 0, 0, 0
// 第1行:5, 6, 0, 0
// 第2行:9, 0, 0, 0
- 省略行数(列数必须指定):
int matrix[][4] = {{1,2}, {3,4,5}, {6}}; // 自动推断行数为3
2. 元素访问与下标
二维数组通过行下标和列下标访问元素,两者均从0开始:
int val = matrix[1][2]; // 访问第1行第2列元素(值为7)
matrix[0][3] = 100; // 修改第0行第3列元素为100
关键规则:
- 行数范围:
0 ~ 行数-1
- 列数范围:
0 ~ 列数-1
- 越界风险:访问超出范围的下标会导致内存错误(信奥赛高频坑点)。
3. 遍历与操作
需用嵌套循环遍历,外层控制行,内层控制列:
const int ROW = 3, COL = 4;
int matrix[ROW][COL] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
// 遍历并输出所有元素
for (int i = 0; i < ROW; i++) { // 行循环
for (int j = 0; j < COL; j++) { // 列循环
cout << matrix[i][j] << "\t"; // 用制表符对齐
}
cout << endl; // 每行结束换行
}
// 计算所有元素的和
int sum = 0;
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
sum += matrix[i][j];
}
}
二、多维数组(以三维为例)
三维数组
三维及以上数组是二维数组的扩展,用于表示更高维度的数据(如立体坐标、时间序列矩阵等),信奥赛中较少直接使用,但原理相通。
1. 定义与初始化
基本语法:
数据类型 数组名[维度1][维度2][维度3];
示例(三维数组,可理解为“多个二维矩阵”):
// 2个3行4列的三维数组(如2个矩阵)
int cube[2][3][4] = {
{ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }, // 第0个矩阵
{ {13,14,15,16}, {17,18,19,20}, {21,22,23,24} } // 第1个矩阵
};
2. 元素访问与遍历
通过三重下标访问,遍历需三重循环:
// 访问第1个矩阵、第2行、第3列的元素(值为24)
int val = cube[1][2][3];
// 遍历三维数组
for (int k = 0; k < 2; k++) { // 第k个矩阵
cout << "第" << k << "个矩阵:" << endl;
for (int i = 0; i < 3; i++) { // 第i行
for (int j = 0; j < 4; j++) { // 第j列
cout << cube[k][i][j] << "\t";
}
cout << endl;
}
}
三、信奥赛核心应用
核心应用
1. 矩阵运算(如加法、乘法)
// 两个3x3矩阵相加
const int N = 3;
int a[N][N] = {{1,2,3}, {4,5,6}, {7,8,9}};
int b[N][N] = {{9,8,7}, {6,5,4}, {3,2,1}};
int c[N][N]; // 结果矩阵
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
c[i][j] = a[i][j] + b[i][j];
}
}
2. 动态规划(DP表)
二维数组常用于存储中间状态(如最长公共子序列、背包问题):
// 二维DP表,dp[i][j]表示前i个物品、容量j时的最大价值
int dp[101][1001] = {0}; // 假设100个物品,容量1000
3. 图论(邻接矩阵)
用二维数组表示图中顶点间的连接关系:
const int MAX_V = 100;
int graph[MAX_V][MAX_V]; // graph[i][j]表示i到j的边权
四、内存存储与性能特性
内存存储与性能特性
- 行优先存储:二维数组在内存中按行连续存储(先存第0行所有元素,再存第1行,以此类推)。访问时按行遍历效率更高(缓存友好)。
- 内存占用:
int a[m][n]
占用m * n * sizeof(int)
字节,大数组需注意内存限制(如int a[1000][1000]
约4MB,可接受;a[10000][10000]
约400MB,需谨慎)。
五、避坑指南
避坑指南
- 列数必须显式指定:定义二维数组时,列数不能省略(行数可省略):
int a[3][4]; // 正确
int a[][4]; // 正确(行数可推断)
int a[3][]; // 错误(列数必须指定)
避免过大的局部二维数组:函数内定义的大数组(如
int a[10000][10000]
)可能导致栈溢出,应定义为全局变量或使用动态分配。多维数组的越界检查:嵌套循环的终止条件需严格控制(如
i < ROW
而非i <= ROW
),避免访问非法内存。初始化不完全的陷阱:局部二维数组若未初始化,元素值为随机垃圾值,需手动初始化(如
int a[3][4] = {0};
可将所有元素置0)。
六、实战:二维数组找最大值及位置
二维数组找最大值及位置
题目:在3x4的矩阵中找到最大值,并输出其值及行、列下标。
#include <iostream>
using namespace std;
int main() {
const int ROW = 3, COL = 4;
int matrix[ROW][COL] = {
{12, 5, 23, 18},
{7, 31, 9, 16},
{25, 8, 14, 20}
};
int max_val = matrix[0][0];
int max_row = 0, max_col = 0;
// 遍历找最大值
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (matrix[i][j] > max_val) {
max_val = matrix[i][j];
max_row = i; // 记录行下标
max_col = j; // 记录列下标
}
}
}
cout << "最大值:" << max_val << endl;
cout << "位置:第" << max_row << "行,第" << max_col << "列" << endl;
// 输出:最大值:31,位置:第1行,第1列
return 0;
}
要点
二维数组是信奥赛中处理结构化数据的核心工具,多维数组则是其扩展。掌握其定义、初始化、访问及遍历技巧,能有效解决矩阵运算、动态规划、图论等领域的问题。需特别注意下标范围和内存限制,避免常见错误。