![bdef7eaa7c73e8824b3dd41c3fb5eaab.png](https://i-blog.csdnimg.cn/blog_migrate/ec6d3b588ca3bb6f39e2680c17fdba7a.png)
点击蓝字关注我哦
![90aa5b5fa2bcb9ecd78edb96cafa952c.png](https://i-blog.csdnimg.cn/blog_migrate/2601887e1fadc15ece0694dbf9fef482.png)
![ea3c60b561231846c824d2ca3ac79d79.png](https://i-blog.csdnimg.cn/blog_migrate/da8ec050ea980153270a575b7ede0cf1.png)
![eea3488654586a7e2cdfc3543d9b5b9a.png](https://i-blog.csdnimg.cn/blog_migrate/56f28f926b26adf3a451e605f4cd3e28.png)
0. 概述
二维数组是日常开发中使用高频的一种管理数据的方式,比如迷宫地图,邻接矩阵等,操作起来也非常方便。在面试中也经常被问到,本文主要对vector构造的二维数组进行说明。1.传统二维数组的缺陷
传统定义二维数组的方式,采用宏定义给出二维数组的行和列,然后定义出二维数组并对其进行初始化,最后就是对该二维数组进行操作,比如:#define ROW 5#define COL 5void Test2Array(){ int array[ROW][COL] = { { 0, 1, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 1, 1, 1, 0 }, { 0, 1, 0, 1, 0 }, { 0, 0, 0, 1, 0 } }; // 打印二维数组 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { cout << array[i][j] << " "; } cout << endl; } cout << endl; }
该种方式使用起来确实比较方便,但缺陷是:数组被限制死了,只能表示5行5列的数组,但有些情况下需要的可能是动态的二维数组,传统二维数组就无能为力。
2. 使用vector定义二维数组
2.1 矩阵(每行元素个数相同)
(1)元素内容都相同:直接使用vector中vector 来进行构造
int main(){ size_t row, col; int val; cin>>row>>col>>val; // 创建一个row行col列的矩阵,并使用val进行填充 vector<vector<int>> v(row, vector<int>(col, val)); return 0;}
(2)元素内容不同:先创建好矩阵,然后给每行元素依次赋值
int main(){ int row,col; cin>>row>>col; // 创建一个row行col列的二维数组,逐个给每行元素进行赋值 vector<vector<int>> v(row, vector<int>(col)); // 将每行的元素赋值为1~col for(int i = 0; i < v.size(); ++i) { for(int j = 0; j < v[i].size(); ++j) { v[i][j] = j+1; } } return 0;}
2.2 动态二维数组
先开辟行,再根据每列中具体元素个数来开辟空间以及给每行元素进行赋值,比如:杨辉三角/*杨慧三角的前5行0行:11行:1 12行:1 2 13行:1 3 3 14行:1 4 6 4 1观察发现:第0列和对角线全部为1,其余位置为上一行同列元素以及上一行同列前一个元素之和*/void PascalTriangle(int N){ vector<vector<int>> vv; // 先给出二维数组的行,此时每行还没有空间 vv.resize(N); for (int i = 0; i < N; ++i) { // 将第i行元素个数设置为i+1,初始值用1填充 vv[i].resize(i + 1, 1); for (int j = 1; j < i; ++j) { vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1]; } } // 打印二维数组 for (int i = 0; i < N; ++i) { for (int j = 0; j <= i; ++j) { cout<" "; } cout << endl; }}
2.3 不确定行列个数
该种场景也比较常见,从问题给的描述中只知道结果为二维数组,但是二维数组的行列需要根据题目的输入来确定,直接无法确定。 此种方式的常见解法是:先构造一个空的二维数组,然后构造一个一维的不断向二维数组中插入 例如:二叉树的封层遍历class Solution {public: vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> ret; if(nullptr == root) return ret; queue q; q.push(root); while(!q.empty()){ // 为了提高效率,先插入一个空的vector ret.push_back(vector<int>()); // 拿到数组的最后一行,借助引用直接在最后一行插入 vector<int>& level = ret.back(); // 本层中节点总的个数 size_t size = q.size(); for(int i = 0; i < size; ++i) { TreeNode* cur = q.front(); q.pop(); level.push_back(cur->val); if(cur->left) q.push(cur->left); if(cur->right) q.push(cur->right); } } return ret; }};
2.4 二维数组的误用
用vector创建的二维数组,一般情况下是先给出有多少行,然后再对每行进行操作。最常见的误用就是还没有给每行分配空间,就直接对行进行操作而引起代码崩溃。void Test2Vector(){ vector<vector<int>> vv; vv.resize(5); // 二维数组总共有5行,但是每行现在还没有空间 vv[0][0] = 10; // 此时直接操作每行中元素时会崩溃}
3. 面试题
二维数组先行后列遍历效率高
还是先列后行遍历效率高?
3.1 先行后列
先行后列是最常见的二维数组的遍历方式,而且效率非常高,因为二维数组的每一行都是一段连续的空间,根据局部性原理,操作系统再访问每个元素时,会将该元素附近多个元素一次性加载到缓存中来提高程序效率。void Print2Vector(){ // 采用C++11提供的列表初始化构造二维数组,每行元素使用{1,2,3,4,5}进行填充 vector<vector<int>> vv(5, { 1, 2, 3, 4, 5 }); // 常规方式 for (size_t i = 0; i < vv.size(); ++i) { for (size_t j = 0; j < vv[i].size(); ++j) { cout << vv[i][j] << " "; } cout << endl; } cout << endl; // 采用范围for打印 for (auto& rowV : vv){ for (auto e : rowV){ cout << e << " "; } cout << endl; } cout << endl;}程序输出:1 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 5
3.2 先列后行
该种方式使用比较少,因为效率比较低,一般情况下适合矩阵使用场景。
void Print2Vector2(){ // 采用C++11提供的列表初始化构造二维数组,每行元素使用{1,2,3,4,5}进行填充 vector<vector<int>> vv(5, { 1, 2, 3, 4, 5 }); // 先行后列 for (size_t row = 0; row < vv.size(); ++row) { for (size_t col = 0; col < vv[i].size(); ++col) { cout << vv[row][col] << " "; } cout << endl; } cout << endl; // 先列后行 for (size_t col = 0; col < vv[0].size(); ++col) { for (size_t row = 0; row < vv.size(); ++row) { cout << vv[row][col] << " "; } cout << endl; } cout << endl;}程序输出:1 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 51 1 1 1 12 2 2 2 23 3 3 3 34 4 4 4 45 5 5 5 5
4. 总结
本文主要介绍了vector构造二维数组的常见方式以及遍历,具体如下:好看,就要点个"在看"
![c8d5caaa9e9ecf3a0038239b75bd519d.gif](https://i-blog.csdnimg.cn/blog_migrate/eafd505d16323758d9d5659da3f77b9b.gif)