HOWTO · C++
在 C++ STL 中声明向量数组
本文介绍如何在 C++ 中声明向量数组
本页内容
本指南介绍如何在 C++ 中声明行数固定的向量数组,或行数可调整的嵌套向量。外层容器决定可以添加多少行;每个内层 std::vector 决定该行可以容纳多少个值。行数固定时选择第一种形式;外层集合需要增减行时选择第二种形式。
在固定数组和嵌套向量之间选择
向量数组的行数在编译时固定,但每一行仍是可以独立增长的向量。嵌套向量的行数也可以改变,而且每行的长度可以不同。因此,嵌套向量不一定是矩形矩阵。它适合表示邻接表等数据,其中每个项目可能有不同数量的邻居。
这两种形式都将向量作为元素存储,因此内层向量会管理各自的内存。这两种声明都不能保证每行包含相同数量的值。如果算法要求数据呈矩形结构,就应将每行初始化为相同宽度,并在修改数据时维持这一约束。
使用 C 风格数组语法声明向量数组
如果行数固定,可以声明一个元素类型为 std::vector<int> 的数组,例如 std::vector<int> rows[3];。该数组包含三个向量元素。这些向量初始时不含任何值,但可以用 rows[0].push_back(10) 向其中一行追加值。数组本身无法扩展到容纳第四个向量;如果行数需要改变,请使用可调整大小的外层容器。
当行数属于程序固定结构的一部分时,这种语法很有用。数组的大小由声明决定,而每个向量的大小可以在程序运行期间改变。因此,这两个维度遵循不同规则:外层数组大小固定,内层向量可以调整大小。
声明可调整大小的嵌套向量
如果行数需要调整大小,可以使用 std::vector<std::vector<int>>。使用初始化列表可以创建初始长度各不相同的行。另一种方式是使用 std::vector<std::vector<int>> rows(3, std::vector<int>(2, 0));,创建三行、每行包含两个零的向量。在这种构造函数形式中,第一个参数是行数;第二个参数是用于初始化每一行的向量副本。
可以用 rows.push_back({8, 9}) 追加一行,也可以用 rows[0].push_back(7) 向已有行追加一个值。增加或缩短某一行不会自动调整其他行。若要创建规整的初始网格,可使用构造函数形式;若各行长度不同,则可使用初始化列表或逐行构造。
访问并遍历嵌套向量
当已知索引有效时,可以使用 rows[row][column] 直接访问元素。每个下标运算符作用于不同的向量:第一个选择外层行,第二个选择该行中的值。由于各行长度可能不同,对某一行有效的列索引未必适用于其他行。
如果需要带边界检查的访问,可以使用 rows.at(row).at(column);遇到越界访问时,at() 会报告错误,而不会悄悄访问所选向量范围之外的位置。若要遍历所有值而不假定各行长度相同,可以使用嵌套的范围循环。当循环需要修改已存储的元素时,用引用绑定内层值(int& value);只读处理则可使用值或常量引用。下面的完整示例展示了两种声明形式、索引访问、带边界检查的访问、追加操作,以及通过引用修改值。
这段完整程序展示了两种容器形态及其值的访问方式:
本节中的代码以及显示的标签或输出仍为英文。
#include <iostream>
#include <vector>
int main() {
std::vector<int> fixed_rows[3] = {{1, 2}, {3}, {4, 5, 6}};
std::vector<std::vector<int>> rows{{1, 2}, {3}, {4, 5, 6}};
fixed_rows[0].push_back(7);
rows.push_back({8, 9});
rows[1].push_back(7);
rows.at(0).at(1) = 20;
std::cout << fixed_rows[0][2] << '\n';
std::cout << rows.at(0).at(1) << '\n';
for (auto& row : rows) {
for (int& value : row) {
value *= 2;
std::cout << value << ' ';
}
std::cout << '\n';
}
}