std::vector

参考C++ vector使用详解

中文标准库:std::vector

Vector、Array、数组的区别与联系

一、vector简介

C++ 的 vector本质上是一个动态数组,它的元素是连续存储的,这意味着不仅可以通过迭代器访问元素,还可以使用指向元素的常规指针来对其进行访问。还可以将指向 vector 元素的指针传递给任何需要指向数组元素的指针的函数。

vector 的存储是自动处理的,可以根据需要进行扩展和收缩。vector通常比静态数组占用更多的空间,因为分配了更多的内存来处理将来的增长。这样,vector 不必在每次插入元素时都重新分配,而仅在附加内存耗尽时才需要重新分配。可以使用 capacity() 函数查询已分配的内存总量。可以通过调用 shrink_to_fit() 将额外的内存返回给系统。

就性能而言,重新分配空间通常是费时的操作。如果元素的数目是预先已知的,调用 reserve() 函数可以消除重新分配。

二、vector优缺点

  • 优点:
    1. 可以不用指定vector的大小
    2. 随机访问方便(因为内存是连续的),即支持[]操作符和vector.at()
    3. 节省空间(vector在开始就创建适合的容量,防止自动扩充大小,节省内存,当插入的个数大于容量时,则容量自动扩充一倍)
  • 缺点:
    1. 插入和删除效率低,复杂度高O(n)
    2. 当元素超出容量时,重新分配内存空间,扩充一倍。元素拷贝到新空间,释放原来的内存,原来的迭代器失效。

三、构造vector

    std::vector<int> v0(3, 100);        //3个100,即相当于v0 {100,100,100}
    std::vector<int> v1 = { 1,2,3,4 };  //有无 = 都正确

四、增加元素

1. push_back:添加一个元素到容器尾部

    void push_back (const value_type& val);
    void push_back (value_type&& val);

2. insert:将一个或多个元素添加到一个指定位置

    iterator insert(const_iterator position, const value_type & val);
    iterator insert(const_iterator position, size_type n, const value_type & val);
    template <class InputIterator>
    iterator insert(const_iterator position, InputIterator first, InputIterator last);
    iterator insert(const_iterator position, value_type && val);
    iterator insert(const_iterator position, initializer_list<value_type> il);

3. emplace_back:和push_back对应

template <class... Args>
    void emplace_back (Args&&... args);

4. emplace:和insert对应

template <class... Args>
    iterator emplace (const_iterator position, Args&&... args);

5. emplace_back 和 push_back 的区别

push_back的过程

  1. 构造一个临时对象

  2. 调用移动构造函数把临时对象的副本拷贝到容器末尾增加的元素中

  3. 调用析构释放临时对象

emplace_back 的过程

  1. 调用构造函数在容器末尾增加一个元素

优缺点

emplace_back比push_back的效率更高,但是使用emplace_back的代码健壮性不如push_back,例如

点击查看代码
    std::vector<int> vec1;
    vec1.push_back(3);
    vec1.emplace_back(5);
    std::vector<std::vector<int>> vec2;
    //vec2.push_back(3);// 报错
    vec2.emplace_back(5); // vec2 = { {0,0,0,0,0} }

示例代码:

点击查看代码
    std::vector<int> vec{ 1,2,3 };
    std::vector<int>::iterator it;

    vec.push_back(4);  //1,2,3,4
    vec.emplace_back(5);  //1,2,3,4,5
    it = vec.begin() + 1;
    auto r1 = vec.emplace(it,6);  //1,6,2,3,4,5  在vec的第一个位置加1(即第二个元素)之前添加一个元素
    auto r2 = vec.insert(r1, 7);  //1,7,6,2,,3,4,5  //注意此处不能再用it,因为it迭代器对应的vector已经发生了变化
    std::vector<int> vec2{ 9,8,7 };
    auto r3 = vec.insert(r2, vec2.begin(), vec2.end()-1); //1,9,8,7,6,2,3,4,5共9个元素,将vec2的9和8添加到vec的r2位置之前
    auto r4 = vec.insert(r3, 3, 4);  //1,4,4,4,9,8,7,6,2,3,4,5在vec的r3位置之前加入3个4

五、删除元素

1. erase:

    iterator erase (const_iterator position);  //删除指定的一个元素
    iterator erase (const_iterator first, const_iterator last);  //删除区间所有元素

删除一个值为value的元素需要用到std::find先查找到位置的迭代器然后再删除(如果vector中存在多个相同的值,std::find只会查找到第一个)。
vec.erase(std::find(vec.begin(),vec.end(),value));

2.erase_if (C++20):

template< class T, class Alloc, class Pred >
constexpr typename std::vector<T, Alloc>::size_type 
erase_if(std::vector<T, Alloc>& c, Pred pred);

3. pop_back:

void pop_back(); //删除最后一个元素

4. clear:

void clear() noexcept; //清空所有元素

5.示例代码:

点击查看代码
    std::vector<int> vec3 = { 1,2,3,4,5,6,7,8,9 };
    vec3.erase(vec3.end()-2);  //12345679  删除倒数第二个元素
    vec3.erase(vec3.end()-3, vec3.end()); //12345  删除从倒数第三个元素开始,到最后一个元素之间的所有元素
    vec3.pop_back();  //1234  删除最后一个元素
    vec3.clear();  //相当于vec3.erase(vec3.begin(),vec3.end())

六、修改元素

1. swap:

void swap (vector& x); //交换两个容器的元素

2. assign:

    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);
    void assign(size_type n, const value_type& val);
    void assign(initializer_list<value_type> il);

3. 利用operator[]、at()以及find()修改元素

4. 示例代码:

点击查看代码
    std::vector<std::string> vec4(3, "abc");  //abc,abc,abc
    vec4[1] = "xyz"; //abc,xyz,abc
    std::string str1("ooo");
    vec4.at(0) = str1;  //ooo,xyz,abc
    vec4.front() = "front";  //front,xyz,abc
    vec4.back() = "back";    //front,xyz,back

    std::vector<int> vec5(5, 6); //666666
    vec5.assign(3, 4);  //444  以3个4替换vec5原来的所有元素
    vec5.assign(v1.begin() + 1, v1.end());  //234  用v1第二个元素到最后一个元素替换vec5原来的所有元素
    vec5.assign({ 9,9,9 }); //999  用3个9替换vec5原来的所有元素

    std::vector<int> vecInt{ 1,2,3,4,5 };
    auto it1 = find(vecInt.begin(), vecInt.end(), 3);
    if(it1!=vecInt.end())
        *it1 = 9;  //vecInt = 1,2,9,4,5

七、查找元素

1. at:访问第n个元素(从0开始)

注意:访问越界会出现异常,所以谨慎使用

    reference at (size_type n); //返回引用,可以利用此修改元素
    const_reference at (size_type n) const;

2. [i]:访问第i个元素(从0开始)

注意:访问越界会出现异常

auto r6 = vec6[1]; //2

3. front:返回容器首元素的引用

    reference front();
    const_reference front() const;

4. back:返回容器末尾元素的引用

    reference back();
    const_reference back() const;

5. data:返回指向内存中数组第一个元素的指针(容器为空返回nullptr,不可以对该指针解引用)

    value_type* data() noexcept;
    const value_type* data() const noexcept;

6. find:返回指向首个满足条件的迭代器,或若找不到这种元素则为end()

std::find需要包含头文件<algorithm>

    template <class InputIterator, class T>
       InputIterator find (InputIterator first, InputIterator last, const T& val);

find、find_if、find_if_not

7. 示例代码:

点击查看代码
    std::vector<int> vec6{ 1,2,3,4,5,6,5 };
    auto r5 = vec6.at(0);  //1
    auto r6 = vec6[1];     //2
    auto r7 = vec6.front();//1
    auto r8 = vec6.back(); //5

    std::vector<int> vec7;
    auto r9 = vec7.data();
    //auto r10 = *r9;   //会出现异常
    auto r11 = find(vec6.begin(), vec6.end(), 5);  //返回指向5的迭代器,返回的是查找到的第一个迭代器
    auto r12 = *(r11-1);   //4

八、比较

非成员函数==,两个vector所有元素都相等则返回true,不相等返回false,使用==的前提是,两个vector的模板初始化参数一致。

九、大小和容量

1. 获取大小或容量

  • capacity():返回容量,即可以存放的元素个数。如果没有使用reserver()设置容量,就返回vector的元素个数

  • size():返回大小,即实际元素的个数

  • max_size():返回可容纳的最大元素个数,vs为:4611686018427387903

2. 设置大小或容量

  • resize():设置容器的大小,如果设置之前的容量大于该大小,则容量不会变化,否则容量也变化为该大小。会修改size()和capacity()

void resize( size_type count, T value = T() ); //设置大小为count,且用count个value填充

  • reserver():设置容器预留空间,(会涉及到内存的释放与申请,因为vector在一段连续的内存空间存储,如果容量大于原容量,且当前内存空间不足,就会重新申请内存空间并将原来的元素复制过去(拷贝构造),且释放掉原来的内存空间。不会修改容器的大小。只会修改capacity,不会修改size()
点击查看代码
 vector<int> v1;
    vector<int> v2;
    vector<int> v3;

    auto _capacity1 = v1.capacity();  //0
    auto _size1 =     v1.size();      //0
    auto _max_size1 = v1.max_size();  //4611686018427387903

    v1.resize(10);                    
    auto _capacity2 = v1.capacity();  //10
    auto _size2 = v1.size();          //10
    auto _max_size2 = v1.max_size();  //4611686018427387903

    v2.reserve(20);                   
    auto _capacity21 = v2.capacity(); //20
    auto _size21 = v2.size();         //0
    auto _max_size21 = v2.max_size(); //4611686018427387903

    v3.reserve(2);                    
    v3.insert(v3.begin(), 3,5);       
    auto _capacity31 = v3.capacity(); //3
    auto _size31 = v3.size();         //3
    auto _max_size31 = v3.max_size(); //4611686018427387903

十、 vector转指针

例如:vector<int>转int*,注意:该指针离开当前作用域后将会失效
int* p = vec.data();

十一、自己实现一个vector

待添加

十二、获取vector的最大值最小值

  • std::max_element

  • std::min_element

完整示例代码:

点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    //构造
    std::vector<int> v0(3, 100);        //3个100,即相当于v0 {100,100,100}
    std::vector<int> v1 = { 1,2,3,4 };  //有无 = 都正确

    //增加
    std::vector<int> vec1{ 1,2,3 };
    std::vector<int>::iterator it;
    vec1.push_back(4);  //1,2,3,4
    vec1.emplace_back(5);  //1,2,3,4,5
    it = vec1.begin() + 1;
    auto r1 = vec1.emplace(it, 6);  //1,6,2,3,4,5  在vec1的第一个位置加1(即第二个元素)之前添加一个元素
    auto r2 = vec1.insert(r1, 7);  //1,7,6,2,,3,4,5  //注意此处不能再用it,因为it迭代器对应的vector已经发生了变化
    std::vector<int> vec2{ 9,8,7 };
    auto r3 = vec1.insert(r2, vec2.begin(), vec2.end() - 1); //1,9,8,7,6,2,3,4,5共9个元素,将vec2的9和8添加到vec1的r2位置之前
    auto r4 = vec1.insert(r3, 3, 4);  //1,4,4,4,9,8,7,6,2,3,4,5在vec1的r3位置之前加入3个4

    //删除
    std::vector<int> vec3 = { 1,2,3,4,5,6,7,8,9 };
    vec3.erase(vec3.end() - 2);  //12345679  删除倒数第二个元素
    vec3.erase(vec3.end() - 3, vec3.end()); //12345  删除从倒数第三个元素开始,到最后一个元素之间的所有元素
    vec3.pop_back();  //1234  删除最后一个元素
    vec3.clear();  //相当于vec3.erase(vec3.begin(),vec3.end())

    //修改
    std::vector<std::string> vec4(3, "abc");  //abc,abc,abc
    vec4[1] = "xyz"; //abc,xyz,abc
    std::string str1("ooo");
    vec4.at(0) = str1;  //ooo,xyz,abc
    vec4.front() = "front";  //front,xyz,abc
    vec4.back() = "back";    //front,xyz,back

    std::vector<int> vec5(5, 6); //666666
    vec5.assign(3, 4);  //444  以3个4替换vec5原来的所有元素
    vec5.assign(v1.begin() + 1, v1.end());  //234  用v1第二个元素到最后一个元素替换vec5原来的所有元素
    vec5.assign({ 9,9,9 }); //999  用3个9替换vec5原来的所有元素

    std::vector<int> vecInt{ 1,2,3,4,5 };
    auto it1 = find(vecInt.begin(), vecInt.end(), 3);
    if(it1!=vecInt.end())
        *it1 = 9;  //vecInt = 1,2,9,4,5

    //查找
    std::vector<int> vec6{ 1,2,3,4,5,6,5 };
    auto r5 = vec6.at(0);  //1
    auto r6 = vec6[1];     //2
    auto r7 = vec6.front();//1
    auto r8 = vec6.back(); //5

    std::vector<int> vec7;
    auto r9 = vec7.data();
    //auto r10 = *r9;   //会出现异常
    auto r11 = find(vec6.begin(), vec6.end(), 5);  //返回指向5的迭代器,返回的是查找到的第一个迭代器
    auto r12 = *(r11 - 1);   //4

    return 0;
}

原文链接: https://www.cnblogs.com/mmmmmmmmm/p/14034145.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    std::vector

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404247

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月24日 下午6:46
下一篇 2023年4月24日 下午6:46

相关推荐