zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    xml 创建 和 处理 及其修改
    shutil模块(高级的文件copy)
    shelve模块使用说明
    random内置模块
    time 时间内置模块3种形态的转化
    python模块说明
    Java控制并发线程数的Semaphore
    Java并发测试
    JAVA 模拟瞬间高并发
    java并发--流量控制demo
  • 原文地址:https://www.cnblogs.com/mmmmmmmmm/p/14034145.html
Copyright © 2011-2022 走看看