• Cpp浅析系列-STL之vector


    前言

    能够在运行时高效地存放各种类型的动态数组vector

    CPP

    Vector定义

    1. #include <Vector> 
    2. using namespace std;
    3. void init() {
    4.     //空对象
    5.     vector<int> v1;
    6.     //元素个数为5,每个int元素都为0
    7.     vector<int> v2(5);
    8.     //元素个数为5,每个int元素都为3
    9.     vector<int> v3(53);
    10.     //手动赋初值,共五个元素,元素值为指定的内容
    11.     vector<int> v4{12345};
    12. }

    Vector常规操作

    C++中文在线手册:https://zh.cppreference.com/

    访问Vector中的任意元素或从末尾添加元素的时间复杂度是O(1),而查找特定值的元素所处的位置或是在Vector中插入元素则是线性时间复杂度,即O(n)

    增加元素

    下标插入

    Vector动态数组,是支持随机访问的,也就是直接用下标取值。

    但是如果是直接用下标赋值,当下标超出了容器的超出了容量,会无法插入,而且此时是不会报错。

    1. /*
    2.  * 声明了一个对象,初始是两个元素,容量为2
    3.  * 当直接修改下标没有超过容量,会直接修改元素
    4.  * 当直接修改下标查过了容量,会没有变化,因为容器内不存在超过容量的元素,被认为是无效操作。
    5.  * */
    6. void add1(){
    7.     vector<int> demo{12};
    8.     demo[1]=3;//{1,3}
    9.     demo[10]=3;//{1,3}
    10. }

    所以建议使用自带的插入函数。

    insert插入

    允许多个元素的插入,使用迭代器指定位置。

    注意:是在迭代器 pos 位置之前插入

    注意:因为需要调用类的构造函数和移动构造函数,所以较慢,但是适用性很棒!

    1. void add2(){
    2.     vector<int> demo{12};
    3.     //在第一个元素后面插入3
    4.     demo.insert(demo.begin() + 13);//{1,3,2}
    5.     //在末尾插入25
    6.     demo.insert(demo.end(), 25);//{1,3,2,5,5}
    7.     //插入其他容器的部分序列
    8.     set<int> setTemp{789};
    9.     demo.insert(demo.end(), ++setTemp.begin(), --setTemp.end()); //{1,3,2,5,5,8}
    10.     //插入初始化列表
    11.     demo.insert(demo.end(), {1011}); //{1,3,2,5,5,7,8,9,10,11}
    12.     for (int i = 0; i < demo.size(); i++) {
    13.         cout << demo[i] << " ";
    14.     }
    15. }

    emplace插入

    注意是每次只能插入一个,而且是只有构造函数,效率高!

    1. void add3() {
    2.     vector<int> demo{12};
    3.     demo.emplace(demo.begin(), 3);//{3,1,2}
    4.     for (int i = 0; i < demo.size(); i++) {
    5.         cout << demo[i] << " ";
    6.     }
    7. }

    push_back插入

    vector底层是用数组实现的,每次执行push_back操作,在底层实现时,是会判断当前元素的个数是否等于容量大小,如果没有就直接插入,否则就要扩容了。

    1. void add4() {
    2.     vector<int> demo{12};
    3.     demo.push_back(3);//{3,1,2}
    4.     for (int i = 0; i < demo.size(); i++) {
    5.         cout << demo[i] << " ";
    6.     }
    7. }

    换句话说,扩容时是要重新分配大小的,先free掉原来的存储空间,后重新malloc。非常耗费时间!

    1. void
    2. vector<_Tp, _Allocator>::push_back(const_reference __x)
    3. {
    4.     if (this->__end_ != this->__end_cap())
    5.     {
    6.         __construct_one_at_end(__x);
    7.     }
    8.     else
    9.         __push_back_slow_path(__x);
    10. }

    遍历元素

    下标遍历1

    1. /*
    2.  * 直接for循环,用下标取元素即可
    3.  * */
    4. void search1() {
    5.     vector<int> demo{12};
    6.     for (int i = 0; i < demo.size(); i++) {
    7.         cout << demo[i] << " ";
    8.     }
    9. }

    下标遍历2

    1. /*
    2.  * 直接用下标取值,超过容量会报错
    3.  * */
    4. void search3() {
    5.     vector<int> demo{12};
    6.     cout <<demo.at(1);
    7.     // cout <<demo.at(1);// 会报错
    8.     cout << endl;
    9. }

    迭代器遍历

    1. /*
    2.  * 直接用迭代器,注意const_iterator还是iterator
    3.  * */
    4. void search2() {
    5.     vector<int> demo{12};
    6.     // 如果参数为const vector<int> 需要用const_iterator
    7.     // vector<int>::const_iterator iter=v.begin();
    8.     for (vector<int>::iterator it = demo.begin(); it != demo.end(); ++it) {
    9.         cout << (*it) << " ";
    10.     }
    11.     cout << endl;
    12. }

    删除元素

    1. /*
    2.  * 删除有两种方式,
    3.  * clear一个是直接清空
    4.  * erase是删除指定迭代器范围内的数字
    5.  * pop_back是删除最后一个
    6.  * */
    7. void del() {
    8.     vector<int> demo{12345};
    9.     //清空
    10.     demo.clear();//{}
    11.     if (demo.empty()) {//判断Vector为空则返回true
    12.         demo.insert(demo.end(), {67891011});//67891011 }
    13.         //删除第一个元素
    14.         demo.erase(demo.begin());//{7891011 }
    15.         //删除前三个
    16.         demo.erase(demo.begin(), demo.begin() + 3); //1011 }
    17.         //删除最后一个
    18.         demo.pop_back();//{10}
    19.     }
    20.     for (int i = 0; i < demo.size(); i++) {
    21.         cout << demo[i] << " ";
    22.     }
    23. }

    原理

    内存扩展方式

    当调用插入函数,却发现空间不够的时候,会进行扩容:

    1. 寻找原来的capacity的两倍空间;

    2. 将原数据复制过去;

    3. 释放原空间三部曲。

    每次配置新空间时都有留下一些数据空间,可以保证常数的时间复杂度

    三大特性

    • 严格的线性顺序排序。

    • 支持动态内存分配

    • 支持随机访问元素,并操供了在尾部添加和删除操作

    size和capacity的区别

    size则代表了对象内元素的个数

    capacity代表了能够存放多少个元素的阀值。

    一旦超过阀值capacity,容器会花费大量时间重新配置内部的存储器,并导致vector元素相关的所有referencepointersiterator都会失效。

    感谢

    示例文件

    gitee:https://gitee.com/JunKuangKuang/KeenCPPTest-all/blob/ac9971df11109470fbaf708ba2977ca593d92292/STL/vector/vector_test.cpp

    github.com:https://github.com/JunKuangKuang/KeenCPPTest-all/blob/main/STL/vector/vector_test.cpp

    感谢

    感谢现在的好奇,为了能成为更好的自己。

    离线下载链接

    vector 类中的 push_back( ) 函数

    C++ STL vector插入元素

  • 相关阅读:
    深度强化学习技术概述
    【毕业设计】31-基于单片机的农业蔬菜大棚温度自动控制系统设计(原理图工程+源码工程+仿真工程+答辩论文+答辩PPT)
    [学习笔记]CS224W
    uview的input框,clear没反应的问题
    HWS-2022 夏令营线上赛 WP
    Table of Laplace Transforms
    Vue中的插槽--组件复用,内容自定义
    七、矩阵的初等变换
    《柳叶刀》发文,孩子睡觉时间一定要睡够9小时!认知能力很重要
    16. Java字符串拼接的低层原理
  • 原文地址:https://blog.csdn.net/qq_41461536/article/details/126571882