C++ STL Vector容器

等待樱花盛开

一、前言

vector和array的不同之处在于:array 实现的是静态数组(容量固定的数组),而 vector 实现的是一个动态数组。
vector 容器以类模板 vector<T>( T 表示存储元素的类型)的形式定义在 <vector> 头文件中,并位于 std 命名空间中。因此,在创建该容器之前,代码中需包含如下内容:

#include <vector>
using namespace std;

说明:std命名空间也可在使用vector容器时额外注明,如:

std::vector<double> values;

二、创建vector的方式

①std::vector<int> vecInt;
②std::vector<int> vecInt {1,5,23,45,87};
③std::vector<int> vecInt(10);
④std::vector<int> vecInt(10, 4);

①方式创建一个空的vector容器,因为容器中没有元素,所以没有分配空间,当用户添加元素时,vector会自动分配内存空间。如果创建好的vector容器的容量不足,可通过reserve()增加容器的容量。需要注意的是:

调用 reserve() 不会影响已存储的元素,也不会生成任何元素,即 vecInt 容器内此时仍然没有任何元素;
如果调用 reserve() 来增加容器容量,之前创建好的任何迭代器(例如开始迭代器和结束迭代器)都可能会失效,因为为了增加容器的容量,vector<T> **容器的元素可能已经被复制或移到了新的内存地址**。

②方式创建一个包含有5个元素的vector容器
③方式创建一个有10个元素、默认初始值为0的vector容器
④方式创建一个有10个元素、指定初始值为4的vector容器
圆括号 () 和大括号 {} 是有区别的,前者表示元素的个数,而后者则表示 vector 容器中的元素值。

三、成员函数

成员函数功能
begin()返回指向容器中第一个元素的迭代器
end()返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用
rbegin()返回指向最后一个元素的迭代器
rend()返回指向第一个元素所在位置前一个位置的迭代器
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素
size()返回实际元素个数
max_size()返回元素个数的最大值,一般是 232-1,所以我们很少会用到这个函数
resize()改变实际元素的个数
capacity()返回当前容量
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false
reserve()增加容器的容量
shrink _to_fit()将内存减少到等于当前元素实际所使用的大小
operator[ ]重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素
at()使用经过边界检查的索引访问元素
front()返回第一个元素的引用
back()返回最后一个元素的引用
data()返回指向容器中第一个元素的指针
assign()用新元素替换原有内容
push_back()在序列的尾部添加一个元素
pop_back()移出序列尾部的元素
insert()在指定的位置插入一个或多个元素
erase()移出一个元素或一段元素
clear()clear()
swap()交换两个容器的所有元素
emplace()在指定的位置直接生成一个元素
emplace_back()在序列尾部生成一个元素
std::swap(x , y)非成员函数,交换数据

四、迭代器的用法

vector的迭代器成员函数和array基本是一样的,如下:
begin()
end()
rbegin()
rend()
cbegin()
cend()
crbegin()
crend()
具体功能图示与https://segmentfault.com/a/11...

1、vector迭代器的独特之处

vector 容器可以随着存储元素的增加,自行申请更多的存储空间。因此,在创建 vector 对象时,我们可以直接创建一个空的 vector 容器,并不会影响后续使用该容器。
vector 容器在申请更多内存后,再次使用之前的迭代器,可能会导致崩溃,因为vector容器在增加容量之后,首个元素的存储地址发生了变化,这个时候再使用之前创建的迭代器显然是错误的,这个时候需要重新初始化迭代器。

五、访问vector容器元素的方式

1、下标方式[]

类似C++中数组的访问方式,vector容器的索引是从0开始的,和数组一样。需要保证下标 n 的值不会超过容器的容量,否则会发生访问越界的错误。

2、at()

当传给at()的索引值越界时,会抛出异常

3、遍历vector容器元素

根据size()获取vector容器的大小,遍历容器中的元素即可
注意:不能使用 capacity() ,因为它返回的是 vector 容器的容量而不是实际存储元素的个数

六、vector容器添加元素

向 vector 容器中添加元素的唯一方式就是使用它的成员函数

1、push_back()

在 vector 容器尾部添加一个元素

2、emplace_back()

C++11新增的,功能和push_back()相同。
既然功能相同,为什么要增加一个emplace_back()呢?

首先我们了解一下emplace_back() 和 push_back() 的区别:底层实现的机制不同。
push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程,因此emplace_back()的执行效率比push_back()高。

七、vector插入元素

1、insert()

在 vector 容器的指定位置插入一个或多个元素。该函数的语法格式有多种,如下:

格式说明
iterator insert(pos,elem)在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器
iterator insert(pos,n,elem)在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器
iterator insert(pos,first,last)在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器
iterator insert(pos,initlist)在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器

2、emplace()

C++ 11中新增的成员函数,用于在 vector 容器指定位置之前插入一个新的元素。

iterator emplace (const_iterator pos, args...);

pos 为指定插入位置的迭代器;args... 表示与新插入元素的构造函数相对应的多个参数;该函数会返回表示新插入元素位置的迭代器。
注意:
①当拷贝构造函数和移动构造函数同时存在时,insert() 会优先调用移动构造函数。
②实际中,emplace() 的运行效率比insert()高。emplace() 在插入元素时,是在容器的指定位置直接构造元素,而不是先单独生成,再将其复制(或移动)到容器中。

八、 vector删除元素的几种方式

如下:

函数功能
pop_back()删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量(capacity)不会发生改变
erase(pos)删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变
swap(beg)、pop_back()先调用 swap() 函数交换要删除的目标元素和容器最后一个元素的位置,然后使用 pop_back() 删除该目标元素
erase(beg,end)删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会发生改变
remove()删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量
clear()删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量

九、实例

1、访问vector容器中的元素

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //初始化vector
    std::vector<int> vecInt;
    std::vector<int> vecInt2{ 3,8,9,6,7,10 };
    std::vector<int> vecInt3(10);
    std::vector<int> vecInt4(20, 4);
   
    for (size_t i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "vecInt size: " << vecInt.size() << " capacity: " << vecInt.capacity() << std::endl;

    for (size_t i = 0; i < vecInt2.size(); i++)
    {
        std::cout << "vecInt2[" << i << "]=" << vecInt2[i] << std::endl;
    }
    std::cout << "vecInt2 size: " << vecInt2.size() << " capacity: " << vecInt2.capacity() << std::endl;

    for (size_t i = 0; i < vecInt3.size(); i++)
    {
        std::cout << "vecInt3[" << i << "]=" << vecInt3[i] << std::endl;
    }
    std::cout << "vecInt3 size: " << vecInt3.size() << " capacity: " << vecInt3.capacity() << std::endl;

    for (size_t i = 0; i < vecInt4.size(); i++)
    {
        std::cout << "vecInt4[" << i << "]=" << vecInt4[i] << std::endl;
    }
    std::cout << "vecInt4 size: " << vecInt4.size() << " capacity: " << vecInt4.capacity() << std::endl;

    system("pause");
    return 0;
}

结果如下:
image.png

2、vector容器迭代器的使用

 //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //begin、end
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter != vecInt.end(); vecIter++)
    {
        std::cout << "begin and end test: vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }


    //rbegin、rend
    i = 0;
    std::vector<int>::reverse_iterator vecIterR = vecInt.rbegin();
    for (; vecIterR != vecInt.rend(); vecIterR++)
    {
        std::cout << "rbegin and rend test: vecInt[" << i++ << "]=" << *vecIterR << std::endl;
    }

    //cbegin、cend 
    i = 0;
    std::vector<int>::const_iterator vecIterC = vecInt.cbegin();
    for (; vecIterC != vecInt.cend(); vecIterC++)
    {
        std::cout << "cbegin and cend test: vecInt[" << i++ << "]=" << *vecIterC << std::endl;
    }

    //crbegin、crend
    i = 0;
    std::vector<int>::const_reverse_iterator vecIterCR = vecInt.crbegin();
    for (; vecIterCR != vecInt.crend(); vecIterCR++)
    {
        std::cout << "crbegin and crend test: vecInt[" << i++ << "]=" << *vecIterCR << std::endl;
    }

结果如下:
image.png

3、访问vector容器元素

 //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //下标方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //at()方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "vecInt[" << i << "]=" << vecInt.at(i) << std::endl;
    }

    //迭代器方式
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter < vecInt.end(); vecIter++)
    {
        std::cout << " iterator vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }

结果如下:
image.png

4、往vector中插入元素

//初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301 };

    //添加元素
    vecInt.push_back(4301);
    vecInt.emplace_back(910);

    //下标方式
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "push_back and emplace_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }


    //insert
    vecInt.insert(vecInt.begin(), 72);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert begin vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), 189);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert end vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    std::array<int, 2> arrayInt{ 13,15 };
    vecInt.insert(vecInt.end(), arrayInt.begin(), arrayInt.end());
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert array vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), { 73,98,49 });
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "insert array2 vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

结果如下:
image.png

5、删除vector容器中的元素

  //初始化vector
    std::vector<int> vecInt{ 3,8,9,6,7,10,34,57,981,301,201,701,623,82,201,2909 };

    vecInt.pop_back();

    //
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "pop_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "pop_back vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //erase
    vecInt.erase(vecInt.begin() + 3);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "erase vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "erase vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //swap
    swap(*(std::begin(vecInt) + 1), *(std::end(vecInt) - 1));
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after swap vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "after swap vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
    vecInt.pop_back();
    
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after swap rest vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //erase指定范围
    vecInt.erase(vecInt.begin() + 2, vecInt.end() - 5);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "erase appoint vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //remove
    std::remove(vecInt.begin(), vecInt.end(), 3);
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "after remove vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "remove vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //clear
    vecInt.clear();
    for (int i = 0; i < vecInt.size(); i++)
    {
        std::cout << "clear vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "clear vecInt size: " << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

结果如下:
image.png
image.png
说明:
pop_back:执行后删除了最后一个元素,容器大小-1,容量不变;
erase:执行后,会返回一个指向删除元素所在位置下一个位置的迭代器,erase在删除元素时,会将删除位置后续的元素陆续前移,并将容器的大小减-1;erase也可以删除指定区域的元素,会返回指向此区域之后一个位置的迭代器;
remove:删除容器中和指定元素值相同的所有元素,在对容器执行完 remove() 函数之后,由于该函数并没有改变容器原来的大小和容量,因此借助 remove() 返回的迭代器完成正确的遍历
remove()的实现原理是:在遍历容器中的元素时,一旦遇到目标元素,就做上标记,然后继续遍历,直到找到一个非目标元素,即用此元素将最先做标记的位置覆盖掉,同时将此非目标元素所在的位置也做上标记,等待找到新的非目标元素将其覆盖。通过 remove() 函数删除掉 demo 容器中的多个指定元素,该容器的大小和容量都没有改变,其剩余位置还保留了之前存储的元素,此时可以使用erase清理无用的数据:

vecInt.erase(iter, vecInt.end());

建议:remove()用于删除容器中指定元素后,可使用 erase() 成员函数清理无用数据。
clear:清理容器中所有的元素

阅读 973

小菜鸟一枚,望各位大佬不吝指教,用于记录学习

1 声望
0 粉丝
0 条评论
你知道吗?

小菜鸟一枚,望各位大佬不吝指教,用于记录学习

1 声望
0 粉丝
文章目录
宣传栏