当前位置:   article > 正文

【十二】【C++】vector用法的探究

【十二】【C++】vector用法的探究

vector类创建对象

 
  1. /*vector类创建对象*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. class Date {
  10. public:
  11. Date(int year = 1900, int month = 1, int day = 1)
  12. : _year(year)
  13. , _month(month)
  14. , _day(day)
  15. {}
  16. private:
  17. int _year;
  18. int _month;
  19. int _day;
  20. };
  21. //创建对象
  22. void TestVector1() {
  23. vector<int> v1(10, 5);
  24. vector<int> v2(10);
  25. vector<Date> v3(10);
  26. vector<int> v4{ 1, 2, 3 }; // C++11
  27. vector<int> vec; // 创建一个空的int类型vector
  28. vector<int> vec2(10); // 创建一个包含10个初始化为0的int元素的vector
  29. vector<int> vec3(10, 1); // 创建一个包含10个初始化为1的int元素的vector
  30. vector<int> vec4{1, 2, 3, 4, 5}; // 列表初始化
  31. vector<int> vec5(vec4.begin(), vec4.end()); // 范围初始化
  32. vector<int> vec6(vec4); // 拷贝初始化
  33. }
  34. #endif

进入调试可以看到变量已经创建成功,里面的具体情况如下图所示。

vector类capacity的扩容规律

 
  1. /*vector类capacity的扩容规律*/
  2. #if 0
  3. /*
  4. 1. vs中:vector是按照1.5倍方式扩容 linux下是按照2倍方式扩容
  5. 2. 放元素时如果已经知道大概要放多少个元素,可以提前将空间设置好
  6. 避免:一边插入一边扩容效率低下
  7. */
  8. #define _CRT_SECURE_NO_WARNINGS
  9. #include <iostream>
  10. using namespace std;
  11. #include <vector>
  12. #include <algorithm>
  13. #include <crtdbg.h>
  14. void TestVector2() {
  15. vector<int> v;
  16. v.reserve(10);
  17. // v.reserve(100);提前分配空间
  18. size_t cap = v.capacity();
  19. for (size_t i = 0; i < 100; ++i) {
  20. v.push_back(i);
  21. if (cap != v.capacity()) {
  22. cap = v.capacity();
  23. cout << cap << endl;
  24. }
  25. }
  26. }
  27. int main(){
  28. TestVector2();
  29. }
  30. #endif

这段代码演示了如何在C++中使用std::vector,特别关注其动态扩容的行为,并提供了一个实用的建议,即如果预先知道将要存储的元素数量,可以使用reserve方法来提前分配足够的空间,以避免在添加元素时频繁的动态扩容操作,从而提高效率。

代码解释

vector<int> v; 创建了一个名为v的空vector,用于存储int类型的元素。

v.reserve(10); 使用reserve方法为v预先分配足够的空间,以存储至少10个int类型的元素。这是基于先前的建议:如果已知将要存储的元素数量,预先分配空间可以提高效率。

size_t cap = v.capacity(); 初始化cap变量,用于存储v当前的容量。

接下来的循环中,通过push_back方法向v中添加了100个整数(从0到99)。每次添加元素后,都会检查v的容量是否发生变化:

如果容量发生变化(意味着vector进行了扩容),则更新cap变量,并输出新的容量值。

扩容机制

代码中的注释提到了std::vector扩容机制的平台相关性:

在Visual Studio(VS)环境下,std::vector通常按照1.5倍的方式扩容。

在Linux环境下,std::vector可能按照2倍的方式扩容。

这种差异意味着在不同的平台上,相同的代码可能会有不同的内存使用和性能表现。

vector访问元素的方式

 
  1. /*vector访问元素的方式*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector3() {
  10. vector<int> v{ 1, 2, 3, 4, 5 };
  11. cout << v.front() << endl;
  12. cout << v.back() << endl;
  13. v.front() = 10;
  14. v.back() = 50;
  15. cout << v[13] << endl;
  16. cout << v.at(14) << endl;
  17. v.clear();
  18. cout << v.front() << endl;
  19. cout << v.back() << endl;
  20. }
  21. int main(){
  22. TestVector3();
  23. }
  24. #endif

注释16、17、19行的代码,运行代码。

v.front()返回v对象第一个元素,v.back()返回v对象最后一个元素。

注释19行的代码,运行代码。

v[13]访问下标为13的元素,越界访问,但是不会检查范围。

v.at(14)访问下标为14的元素,越界访问,会报错,会检查范围,报错后,后面的代码不会再运行。

assign用法,用数组代替vector内容

 
  1. /*已经存在的vector对象,用一个数组代替vector内容*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector4() {
  10. vector<int> v(3, 5);
  11. int array[] = { 1, 2, 3, 4, 5 };
  12. // v = array; 编译失败
  13. v.clear();
  14. for (int i = 0; i <(int)(sizeof(array) / sizeof(array[0])); ++i)
  15. {
  16. v[i] = array[i]; // 越界
  17. v.push_back(array[i]);
  18. }
  19. v.assign(array, array + sizeof(array) / sizeof(array[0]));
  20. v.assign(10, 5);
  21. }
  22. int main(){
  23. TestVector4();
  24. }
  25. #endif

注释20,23,25行代码,运行代码。

调试代码运行到结尾,发现v对象中lengthcapacity没有变化,原因很简单,我们只是简单修改v对象对应位置的值,但是v对象还有lengthcapacity成员变量需要改变。

注释19,23,25行代码,运行代码。

注释17-21,25行代码,运行代码。

v.assign(array, array + sizeof(array) / sizeof(array[0]));array数组的0位置到结尾,代替v里面的内容。

注释17-21,23行代码,运行代码。

vec4.assign(5, 10); 将vector中的内容替换为5个10

vector的插入操作insert探究

 
  1. /*vector插入操作insert探究*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector5() {
  10. vector<int> v{ 1, 2, 3 };
  11. v.insert(v.begin(), 0);
  12. v.insert(v.end(), 4);
  13. // 0 1 2 3 4
  14. // 在1号元素的位置插入10个5
  15. v.insert(v.begin() + 1, 10, 5);
  16. // 要在data元素所在的位置插入array数组
  17. int data;
  18. cin >> data;
  19. int array[] = { 10, 20, 30 };
  20. // vector<int>::iterator pos = find(v.begin(), v.end(), data);
  21. auto pos = find(v.begin(), v.end(), data);
  22. if (pos != v.end()) {
  23. v.insert(pos, array, array + sizeof(array) / sizeof(array[0]));
  24. }
  25. }
  26. int main() {
  27. TestVector5();
  28. }
  29. #endif

小结论:

迭代器begin()指向第一个元素,end()指向最后一个元素后面一个位置。

插入操作传参表示位置,传的都是迭代器。

都是在迭代器位置前面插入数据。

vector的删除操作erase探究

 
  1. /*vector的删除erase操作探究*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector6() {
  10. vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  11. v.erase(v.begin());
  12. v.erase(v.begin(), v.begin() + 5);
  13. v.erase(v.begin(), v.end()); // clear()
  14. }
  15. int main(){
  16. TestVector6();
  17. }
  18. #endif

小结论:

删除多个元素,区间是左开右闭。

vector的交换操作swap探究

 
  1. /*swap交换操作探究*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector7() {
  10. vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  11. vector<int> v2{ 12, 23, 34 };
  12. swap(v1, v2);
  13. v1.swap(v2);
  14. }
  15. int main(){
  16. TestVector7();
  17. }
  18. #endif

vector的访问操作探究

 
  1. /*vector访问操作探究*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector8() {
  10. vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  11. for (size_t i = 0; i < v1.size(); ++i) {
  12. cout << v1[i] << " ";
  13. }
  14. cout << endl;
  15. for (auto e : v1) {
  16. cout << e << " ";
  17. }
  18. cout << endl;
  19. auto it = v1.begin();
  20. while (it != v1.end()) {
  21. cout << *it << " ";
  22. ++it;
  23. }
  24. cout << endl;
  25. sort(v1.begin(), v1.end());
  26. }
  27. int main(){
  28. TestVector8();
  29. }
  30. #endif

访问vector的三种方式:

  1. operator[]访问

  2. 范围for

  3. 迭代器

vector的迭代器失效探究

 
  1. // 迭代器失效
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector9() {
  10. vector<int> v{ 1, 2, 3, 4, 5 };
  11. // it指向的是v的当前的起始位置
  12. auto it = v.begin();
  13. // 扩容之后,可能会导致扩容
  14. // 开辟新空间 拷贝元素 释放旧空间
  15. v.push_back(6);
  16. // it指向v之前的空间已经被释放了,it指向的空间就是非法的
  17. // it的迭代器已经失效了
  18. // 解决迭代器失效的方法:
  19. it = v.begin();
  20. while (it != v.end()) {
  21. cout << *it << " ";
  22. ++it;
  23. }
  24. cout << endl;
  25. }
  26. int main(){
  27. TestVector9();
  28. }
  29. #endif

扩容操作,开辟新的空间,而老迭代器还指向旧的空间,此时迭代器指向的空间是已经被消灭的空间,解决这个问题就必须重新让迭代器指向新空间的位置。

vector删除操作后返回下一个元素的迭代器位置

 
  1. /*vector删除操作后返回下一个位置的迭代器位置*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector10() {
  10. vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  11. auto it = v.begin();
  12. while (it != v.end()) {
  13. if (*it & 1 || *it == 0)
  14. it = v.erase(it);
  15. else
  16. ++it;
  17. }
  18. }
  19. int main() {
  20. TestVector10();
  21. }
  22. #endif

用vector创建二维数组

 
  1. /*用vector创建二维数组*/
  2. #if 1
  3. /*
  4. 用vector创建二维数组:
  5. 1. 矩阵
  6. a. 所有元素都相同
  7. b. 元素不同
  8. 2. 每行元素个数不同---比如杨慧三角
  9. */
  10. #define _CRT_SECURE_NO_WARNINGS
  11. #include <iostream>
  12. using namespace std;
  13. #include <vector>
  14. #include <algorithm>
  15. #include <crtdbg.h>
  16. // a. 所有元素都相同
  17. void TestVector11() {
  18. // 5行10列 所有元素都是8
  19. // 1.依次尾插
  20. vector<vector<int>> v1;
  21. v1.resize(5);
  22. for (int i = 0; i < 5; ++i)
  23. {
  24. for (int j = 0; j < 10; ++j)
  25. {
  26. v1[i].push_back(8);
  27. }
  28. }
  29. // 2.无参构造,resize
  30. vector<vector<int>> v2;
  31. v2.resize(5, vector<int>(10, 8));
  32. // 3.vector构造函数嵌套
  33. vector<vector<int>> v3(5, vector<int>(10, 8));
  34. }
  35. int main(){
  36. TestVector11();
  37. }
  38. #endif

vector<vector<int>> v3(5, vector<int>(10, 8));创建对象v3,元素数据类型是vector<int>类型,元素个数有五个,对这五个元素进行初始化,全部初始化为vector<int>(10,8),匿名对象构造函数。

常用于创建矩阵

 
  1. /*用vector创建二维数组---杨慧三角*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. // 2. 每行元素个数不同---比如杨慧三角
  10. void TestVector12() {
  11. int n;
  12. cin >> n;
  13. // vector(size_t n, const T& val = T())
  14. // vector<vector<int>> vv(n, vector<int>());
  15. vector<vector<int>> vv(n);
  16. for (size_t i = 0; i < vv.size(); ++i) {
  17. vv[i].resize(i + 1, 1);
  18. }
  19. /*
  20. 0:1
  21. 1:1 1
  22. 2:1 2 1
  23. 3:1 3 3 1
  24. 4:1 4 6 4 1
  25. 。。。
  26. */
  27. for (size_t i = 2; i < vv.size(); ++i) {
  28. for (size_t j = 1; j < vv[i].size() - 1; ++j) {
  29. vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
  30. }
  31. }
  32. }
  33. int main(){
  34. TestVector12();
  35. }

使用reserve、resize的探究

 
  1. /*使用reserve、resize的小技巧*/
  2. #if 1
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. using namespace std;
  6. #include <vector>
  7. #include <algorithm>
  8. #include <crtdbg.h>
  9. void TestVector13() {
  10. vector<int> v2;
  11. v2.reserve(10);
  12. v2[0] = 1;
  13. vector<int> v3;
  14. v3.resize(10);
  15. v3[0] = 1;
  16. vector<int> v1;
  17. v1[0] = 1;
  18. }
  19. int main() {
  20. TestVector13();
  21. return 0;
  22. }
  23. #endif

capacity容量,已经开辟的空间大小,length使用的空间大小。如果通过无参的构造函数创建v1lengthcapacity都是0,此时访问元素并修改会报错,因为此时v1还没有开辟空间。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/84941
推荐阅读
相关标签
  

闽ICP备14008679号