C++ Vector嵌套完全指南:从基础到高阶应用
C++ Vector嵌套完全指南:从基础到高阶应用
文章目录
- C++ Vector嵌套完全指南:从基础到高阶应用
- 引言
- 1. 固定大小的n×n二维vector
- 1.1 基本声明方法
- 1.2 分步构建方法
- 1.3 访问和修改元素
 
- 2. 外层确定,内层大小不同的vector(不规则二维数组)
- 2.1 直接初始化方法
- 2.2 动态构建方法
- 2.3 访问和遍历不规则数组
 
- 3. 外层不确定,内层大小确定的vector
- 3.1 动态添加外层vector
- 3.2 使用resize方法
- 3.3 实际应用示例
 
- 4. 外层和内层都不确定的vector
- 4.1 完全动态构建
- 4.2 基于用户输入或外部数据的动态构建
- 4.3 复杂数据结构的动态构建
 
- 5. 使用auto简化代码
- 5.1 auto在声明中的应用
- 5.2 auto在遍历中的应用
- 5.3 auto在函数返回值和参数推导中的应用
 
- 6. 三维及更高维度的vector
- 6.1 三维vector的基本操作
- 6.2 不规则多维vector
- 6.3 四维及更高维度
 
- 7. 实用技巧和最佳实践
- 7.1 提高代码可读性
- 7.2 性能优化技巧
- 7.3 错误处理和边界检查
- 7.4 内存管理技巧
 
- 结论
 
引言
在C++编程中,std::vector是最常用的动态数组容器之一。当我们需要处理更复杂的数据结构时,vector的嵌套使用变得尤为重要。本文将全面详细介绍C++中vector嵌套的各种情况,从简单的二维数组到复杂的不规则多维结构,帮助读者彻底掌握这一重要概念。
1. 固定大小的n×n二维vector
1.1 基本声明方法
#include <vector>
using namespace std;int main() {int n = 5;// 方法1:使用构造函数,所有元素默认初始化vector<vector<int>> matrix1(n, vector<int>(n));// 此时所有元素的值是未定义的(取决于编译器和环境)// 方法2:使用构造函数,指定初始值vector<vector<int>> matrix2(n, vector<int>(n, 0)); // 全部初始化为0vector<vector<int>> matrix3(n, vector<int>(n, -1)); // 全部初始化为-1// 方法3:使用初始化列表(C++11及以上)vector<vector<int>> matrix4 = {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},{11, 12, 13, 14, 15},{16, 17, 18, 19, 20},{21, 22, 23, 24, 25}};return 0;
}
1.2 分步构建方法
#include <vector>
using namespace std;int main() {int n = 5;// 方法1:先声明外层,再逐个添加内层vector<vector<int>> matrix1;for(int i = 0; i < n; i++) {matrix1.push_back(vector<int>(n)); // 添加n个默认初始化的内层vector}// 方法2:先声明外层大小,再初始化每个内层vector<vector<int>> matrix2(n);for(int i = 0; i < n; i++) {matrix2[i] = vector<int>(n); // 为每个外层元素赋值}// 方法3:使用resize方法vector<vector<int>> matrix3;matrix3.resize(n); // 调整外层大小为nfor(int i = 0; i < n; i++) {matrix3[i].resize(n); // 调整每个内层vector的大小为n}return 0;
}
1.3 访问和修改元素
#include <vector>
#include <iostream>
using namespace std;int main() {int n = 3;vector<vector<int>> matrix(n, vector<int>(n, 0));// 初始化矩阵(示例:单位矩阵)for(int i = 0; i < n; i++) {matrix[i][i] = 1; // 对角线元素设为1}// 打印矩阵for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {cout << matrix[i][j] << " ";}cout << endl;}// 输出:// 1 0 0 // 0 1 0 // 0 0 1return 0;
}
2. 外层确定,内层大小不同的vector(不规则二维数组)
2.1 直接初始化方法
#include <vector>
using namespace std;int main() {// 方法1:使用初始化列表直接创建不规则二维数组vector<vector<int>> jagged1 = {{1, 2},                    // 第一个内层:2个元素{3, 4, 5, 6},              // 第二个内层:4个元素{7},                       // 第三个内层:1个元素{8, 9, 10, 11, 12, 13}     // 第四个内层:6个元素};// 方法2:逐个push_back不同大小的内层vectorvector<vector<int>> jagged2;jagged2.push_back(vector<int>{1, 2});jagged2.push_back(vector<int>{3, 4, 5, 6});jagged2.push_back(vector<int>{7});jagged2.push_back(vector<int>{8, 9, 10, 11, 12, 13});return 0;
}
2.2 动态构建方法
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;int main() {srand(time(0)); // 设置随机种子int outerSize = 5; // 外层有5个vector// 方法1:根据算法动态确定内层大小vector<vector<int>> jagged1(outerSize);for(int i = 0; i < outerSize; i++) {int innerSize = i + 1; // 内层大小递增:1,2,3,4,5jagged1[i] = vector<int>(innerSize);// 可以进一步初始化内层元素for(int j = 0; j < innerSize; j++) {jagged1[i][j] = i * j; // 示例:元素值为i*j}}// 方法2:使用预定义的大小数组vector<vector<int>> jagged2;vector<int> innerSizes = {2, 5, 3, 4, 1}; // 各内层的大小for(int size : innerSizes) {jagged2.push_back(vector<int>(size));}// 方法3:随机大小的内层vectorvector<vector<int>> jagged3;for(int i = 0; i < outerSize; i++) {int randomSize = rand() % 10 + 1; // 随机大小:1-10vector<int> innerVec(randomSize);// 初始化随机值for(int j = 0; j < randomSize; j++) {innerVec[j] = rand() % 100; // 0-99的随机数}jagged3.push_back(innerVec);}return 0;
}
2.3 访问和遍历不规则数组
#include <vector>
#include <iostream>
using namespace std;int main() {vector<vector<int>> jagged = {{1, 2},{3, 4, 5, 6},{7},{8, 9, 10, 11, 12, 13}};// 遍历不规则二维数组for(int i = 0; i < jagged.size(); i++) {cout << "第" << i << "行: ";for(int j = 0; j < jagged[i].size(); j++) {cout << jagged[i][j] << " ";}cout << endl;}// 输出:// 第0行: 1 2 // 第1行: 3 4 5 6 // 第2行: 7 // 第3行: 8 9 10 11 12 13 // 获取特定内层的大小cout << "第1个内层的大小: " << jagged[0].size() << endl; // 输出: 2cout << "第2个内层的大小: " << jagged[1].size() << endl; // 输出: 4return 0;
}
3. 外层不确定,内层大小确定的vector
3.1 动态添加外层vector
#include <vector>
using namespace std;int main() {int innerSize = 4; // 每个内层vector都有4个元素// 方法1:根据条件动态构建vector<vector<int>> dynamic1;// 模拟根据某些条件添加外层vectorfor(int i = 0; i < 10; i++) {if(i % 2 == 0) { // 示例条件:只添加偶数索引dynamic1.push_back(vector<int>(innerSize, i)); // 用i值初始化所有元素}}// 方法2:从数据源动态构建vector<vector<int>> dynamic2;vector<int> dataSource = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 每innerSize个数据创建一个内层vectorfor(size_t i = 0; i < dataSource.size(); i += innerSize) {vector<int> inner;for(int j = 0; j < innerSize && (i + j) < dataSource.size(); j++) {inner.push_back(dataSource[i + j]);}dynamic2.push_back(inner);}return 0;
}
3.2 使用resize方法
#include <vector>
using namespace std;int main() {int innerSize = 3;// 方法1:先创建外层,再调整内层vector<vector<int>> dynamic1;// 假设我们需要动态扩展外层int currentOuterSize = 0;int targetOuterSize = 5;dynamic1.resize(targetOuterSize);for(auto& inner : dynamic1) {inner.resize(innerSize); // 确保每个内层都有正确的大小}// 方法2:分阶段构建vector<vector<int>> dynamic2;// 第一阶段:添加一些外层vectorfor(int i = 0; i < 3; i++) {dynamic2.push_back(vector<int>(innerSize));}// 第二阶段:根据需要继续添加if(dynamic2.size() < 6) {dynamic2.resize(6); // 扩展到6个外层for(auto& inner : dynamic2) {if(inner.empty()) { // 只初始化空的内层inner.resize(innerSize);}}}return 0;
}
3.3 实际应用示例
#include <vector>
#include <iostream>
using namespace std;// 模拟从文件或网络读取数据的场景
vector<vector<int>> readMatrixData() {vector<vector<int>> result;int innerSize = 3; // 假设我们知道每行应该有3个数据// 模拟读取多行数据vector<vector<int>> rawData = {{1, 2, 3},{4, 5, 6},{7, 8, 9},{10, 11, 12}};for(const auto& row : rawData) {if(row.size() == innerSize) {result.push_back(row);} else {// 处理大小不匹配的情况vector<int> correctedRow(innerSize, 0);for(size_t i = 0; i < min(row.size(), static_cast<size_t>(innerSize)); i++) {correctedRow[i] = row[i];}result.push_back(correctedRow);}}return result;
}int main() {auto data = readMatrixData();cout << "读取到的数据:" << endl;for(const auto& row : data) {for(int val : row) {cout << val << " ";}cout << endl;}return 0;
}
4. 外层和内层都不确定的vector
4.1 完全动态构建
#include <vector>
#include <iostream>
using namespace std;int main() {// 完全动态的二维vectorvector<vector<int>> fullyDynamic;// 添加不同大小的内层vectorfullyDynamic.push_back({1, 2, 3});           // 第一个内层:3个元素fullyDynamic.push_back({4, 5});              // 第二个内层:2个元素fullyDynamic.push_back({6, 7, 8, 9, 10});    // 第三个内层:5个元素// 动态添加更多数据int newData[] = {11, 12, 13, 14};fullyDynamic.push_back(vector<int>(newData, newData + 4)); // 第4个内层:4个元素// 使用算法生成数据for(int i = 0; i < 3; i++) {vector<int> temp;// 根据条件决定内层大小int elementsToAdd = (i % 2 == 0) ? 2 : 4;for(int j = 0; j < elementsToAdd; j++) {temp.push_back(i * 10 + j);}fullyDynamic.push_back(temp);}return 0;
}
4.2 基于用户输入或外部数据的动态构建
#include <vector>
#include <iostream>
using namespace std;int main() {vector<vector<int>> dynamicData;// 模拟用户输入或从文件读取cout << "请输入数据行数: ";int numRows;cin >> numRows;for(int i = 0; i < numRows; i++) {cout << "请输入第" << i << "行的数据个数: ";int numCols;cin >> numCols;vector<int> row;cout << "请输入" << numCols << "个整数: ";for(int j = 0; j < numCols; j++) {int value;cin >> value;row.push_back(value);}dynamicData.push_back(row);}// 显示结果cout << "\n您输入的数据:" << endl;for(size_t i = 0; i < dynamicData.size(); i++) {cout << "行" << i << " (" << dynamicData[i].size() << "个元素): ";for(int val : dynamicData[i]) {cout << val << " ";}cout << endl;}return 0;
}
4.3 复杂数据结构的动态构建
#include <vector>
#include <string>
#include <iostream>
using namespace std;struct Student {string name;vector<int> scores; // 每个学生的分数数量可能不同
};int main() {vector<Student> classData;// 动态构建学生数据vector<string> names = {"Alice", "Bob", "Charlie"};vector<vector<int>> allScores = {{85, 90, 78},{92, 88},{76, 85, 90, 82}};for(size_t i = 0; i < names.size(); i++) {Student student;student.name = names[i];student.scores = allScores[i];classData.push_back(student);}// 动态添加新学生Student newStudent;newStudent.name = "Diana";// 动态添加分数newStudent.scores.push_back(95);newStudent.scores.push_back(87);newStudent.scores.push_back(91);classData.push_back(newStudent);// 显示所有数据for(const auto& student : classData) {cout << student.name << "的分数 (" << student.scores.size() << "门): ";for(int score : student.scores) {cout << score << " ";}cout << endl;}return 0;
}
5. 使用auto简化代码
5.1 auto在声明中的应用
#include <vector>
#include <iostream>
using namespace std;int main() {int n = 4;// 使用auto简化复杂类型的声明auto matrix = vector<vector<int>>(n, vector<int>(n, 0));// 等价于:// vector<vector<int>> matrix(n, vector<int>(n, 0));// 使用auto推导函数返回类型auto createIdentityMatrix = [](int size) -> vector<vector<int>> {vector<vector<int>> result(size, vector<int>(size, 0));for(int i = 0; i < size; i++) {result[i][i] = 1;}return result;};auto identity = createIdentityMatrix(3);// 使用auto推导复杂表达式的结果类型auto complexMatrix = vector<vector<vector<int>>>(2, vector<vector<int>>(3, vector<int>(4)));return 0;
}
5.2 auto在遍历中的应用
#include <vector>
#include <iostream>
using namespace std;int main() {vector<vector<int>> data = {{1, 2, 3},{4, 5, 6, 7},{8, 9}};// 使用auto&遍历(可以修改元素)cout << "修改前:" << endl;for(auto& row : data) {for(auto& element : row) {cout << element << " ";element *= 2; // 修改元素}cout << endl;}cout << "修改后:" << endl;// 使用const auto&遍历(只读,不能修改)for(const auto& row : data) {for(const auto& element : row) {cout << element << " ";// element = 0; // 错误:不能修改const引用}cout << endl;}// 使用auto(创建副本,不影响原数据)cout << "使用auto创建副本:" << endl;for(auto row : data) { // 这里会创建row的副本for(auto element : row) { // 这里会创建element的副本element = 0; // 只修改副本,不影响原数据cout << element << " ";}cout << endl;}cout << "原数据未改变:" << endl;for(const auto& row : data) {for(const auto& element : row) {cout << element << " ";}cout << endl;}return 0;
}
5.3 auto在函数返回值和参数推导中的应用
#include <vector>
#include <iostream>
using namespace std;// 使用auto推导返回类型(C++14及以上)
auto createJaggedArray(int outerSize) {vector<vector<int>> result;for(int i = 0; i < outerSize; i++) {result.push_back(vector<int>(i + 1, i)); // 三角形数组}return result;
}// 使用decltype(auto)完美转发返回类型
template<typename T>
decltype(auto) getRow(const vector<vector<T>>& matrix, size_t index) {return matrix[index];
}int main() {// 使用auto接收函数返回值auto jagged = createJaggedArray(4);// 使用auto和范围for简化遍历for(const auto& row : jagged) {for(auto val : row) {cout << val << " ";}cout << endl;}// 使用decltype(auto)vector<vector<int>> matrix = {{1, 2}, {3, 4, 5}};auto&& row = getRow(matrix, 1); // 返回引用cout << "第二行: ";for(auto val : row) {cout << val << " ";}cout << endl;return 0;
}
6. 三维及更高维度的vector
6.1 三维vector的基本操作
#include <vector>
#include <iostream>
using namespace std;int main() {int x = 2, y = 3, z = 4;// 创建三维vectorvector<vector<vector<int>>> cube(x, vector<vector<int>>(y, vector<int>(z, 0)));// 使用auto简化声明auto cube2 = vector<vector<vector<int>>>(x, vector<vector<int>>(y, vector<int>(z, 1)));// 初始化三维数组int counter = 0;for(int i = 0; i < x; i++) {for(int j = 0; j < y; j++) {for(int k = 0; k < z; k++) {cube[i][j][k] = counter++;}}}// 访问三维vectorcout << "三维数组内容:" << endl;for(int i = 0; i < x; i++) {cout << "第" << i << "层:" << endl;for(int j = 0; j < y; j++) {for(int k = 0; k < z; k++) {cout << cube[i][j][k] << " ";}cout << endl;}cout << endl;}return 0;
}
6.2 不规则多维vector
#include <vector>
#include <iostream>
using namespace std;int main() {// 创建不规则的三维vectorvector<vector<vector<int>>> irregular3D;// 第一层:2个二维数组irregular3D.push_back({{1, 2, 3},           // 第一个二维数组的第一行{4, 5}               // 第一个二维数组的第二行});// 第二层:3个二维数组irregular3D.push_back({{6, 7},              // 第二个二维数组的第一行{8, 9, 10},          // 第二个二维数组的第二行{11}                 // 第二个二维数组的第三行});// 第三层:1个二维数组irregular3D.push_back({{12, 13, 14, 15}     // 第三个二维数组的唯一一行});// 遍历不规则三维数组for(size_t i = 0; i < irregular3D.size(); i++) {cout << "第" << i << "层 (" << irregular3D[i].size() << "个二维数组):" << endl;for(size_t j = 0; j < irregular3D[i].size(); j++) {cout << "  第" << j << "个数组 (" << irregular3D[i][j].size() << "个元素): ";for(size_t k = 0; k < irregular3D[i][j].size(); k++) {cout << irregular3D[i][j][k] << " ";}cout << endl;}}return 0;
}
6.3 四维及更高维度
#include <vector>
#include <iostream>
using namespace std;int main() {// 四维vector:2×3×4×5int dim1 = 2, dim2 = 3, dim3 = 4, dim4 = 5;auto hypercube = vector<vector<vector<vector<int>>>>(dim1, vector<vector<vector<int>>>(dim2, vector<vector<int>>(dim3, vector<int>(dim4, 0))));// 初始化四维数组int counter = 0;for(int i = 0; i < dim1; i++) {for(int j = 0; j < dim2; j++) {for(int k = 0; k < dim3; k++) {for(int l = 0; l < dim4; l++) {hypercube[i][j][k][l] = counter++;}}}}// 访问特定元素cout << "hypercube[1][2][3][4] = " << hypercube[1][2][3][4] << endl;// 使用typedef/using提高可读性using Vector1D = vector<int>;using Vector2D = vector<Vector1D>;using Vector3D = vector<Vector2D>;using Vector4D = vector<Vector3D>;Vector4D anotherHypercube(dim1, Vector3D(dim2, Vector2D(dim3, Vector1D(dim4, -1))));return 0;
}
7. 实用技巧和最佳实践
7.1 提高代码可读性
#include <vector>
#include <iostream>
using namespace std;// 使用类型别名提高可读性
using Matrix = vector<vector<int>>;
using Row = vector<int>;
using Cube = vector<Matrix>;// 使用枚举或常量说明维度含义
enum Dimensions {BATCH_SIZE = 2,CHANNELS = 3,HEIGHT = 4,WIDTH = 5
};Matrix createMatrix(int rows, int cols, int defaultValue = 0) {return Matrix(rows, Row(cols, defaultValue));
}Cube createCube(int depth, int rows, int cols, int defaultValue = 0) {return Cube(depth, createMatrix(rows, cols, defaultValue));
}int main() {// 使用类型别名Matrix mat = createMatrix(3, 3);Cube cube = createCube(2, 3, 3);// 使用有意义的维度常量auto imageBatch = vector<vector<vector<vector<float>>>>(BATCH_SIZE, vector<vector<vector<float>>>(CHANNELS, vector<vector<float>>(HEIGHT, vector<float>(WIDTH, 0.0f))));return 0;
}
7.2 性能优化技巧
#include <vector>
#include <iostream>
#include <chrono>
using namespace std;int main() {const int SIZE = 1000;// 方法1:不预先分配空间(性能较差)auto start1 = chrono::high_resolution_clock::now();vector<vector<int>> slowMatrix;for(int i = 0; i < SIZE; i++) {vector<int> row;for(int j = 0; j < SIZE; j++) {row.push_back(i * j);}slowMatrix.push_back(row);}auto end1 = chrono::high_resolution_clock::now();// 方法2:预先分配空间(性能较好)auto start2 = chrono::high_resolution_clock::now();vector<vector<int>> fastMatrix;fastMatrix.reserve(SIZE); // 预先分配外层空间for(int i = 0; i < SIZE; i++) {vector<int> row;row.reserve(SIZE); // 预先分配内层空间for(int j = 0; j < SIZE; j++) {row.push_back(i * j);}fastMatrix.push_back(move(row)); // 使用move避免拷贝}auto end2 = chrono::high_resolution_clock::now();auto duration1 = chrono::duration_cast<chrono::milliseconds>(end1 - start1);auto duration2 = chrono::duration_cast<chrono::milliseconds>(end2 - start2);cout << "不预分配时间: " << duration1.count() << "ms" << endl;cout << "预分配时间: " << duration2.count() << "ms" << endl;return 0;
}
7.3 错误处理和边界检查
#include <vector>
#include <iostream>
#include <stdexcept>
using namespace std;class SafeMatrix {
private:vector<vector<int>> data;public:SafeMatrix(size_t rows, size_t cols) : data(rows, vector<int>(cols, 0)) {}// 安全的元素访问int& at(size_t row, size_t col) {if(row >= data.size()) {throw out_of_range("行索引越界: " + to_string(row));}if(col >= data[row].size()) {throw out_of_range("列索引越界: " + to_string(col));}return data[row][col];}// 获取大小信息size_t rowCount() const { return data.size(); }size_t colCount(size_t row) const { if(row >= data.size()) return 0;return data[row].size(); }// 添加行void addRow(const vector<int>& row) {data.push_back(row);}// 打印矩阵void print() const {for(const auto& row : data) {for(int val : row) {cout << val << " ";}cout << endl;}}
};int main() {try {SafeMatrix mat(3, 3);// 安全访问mat.at(0, 0) = 1;mat.at(1, 1) = 2;mat.at(2, 2) = 3;// 这会抛出异常// mat.at(5, 5) = 10;mat.print();// 添加不规则行mat.addRow({4, 5, 6, 7}); // 现在矩阵变成不规则的了cout << "添加行后:" << endl;mat.print();} catch(const exception& e) {cerr << "错误: " << e.what() << endl;}return 0;
}
7.4 内存管理技巧
#include <vector>
#include <iostream>
#include <memory>
using namespace std;int main() {// 使用智能指针管理嵌套vectorauto smartMatrix = make_shared<vector<vector<int>>>();// 添加数据smartMatrix->push_back({1, 2, 3});smartMatrix->push_back({4, 5});// 自动内存管理,不需要手动删除// 使用unique_ptr(如果不需要共享所有权)auto uniqueMatrix = make_unique<vector<vector<int>>>();uniqueMatrix->push_back({6, 7, 8});// 移动语义优化vector<vector<int>> source = {{1, 2}, {3, 4, 5}};vector<vector<int>> destination = move(source); // 移动而不是拷贝cout << "移动后source的大小: " << source.size() << endl; // 0cout << "destination的大小: " << destination.size() << endl; // 2return 0;
}
结论
掌握vector的嵌套使用对于处理复杂数据结构至关重要,希望本文能够帮助读者在实际编程中更加得心应手地使用这一强大特性。
