C++ STL--vector容器

1、vector容器简介

Vector 是C++标准程序库中的一个类,可视为会自动扩展容量的数组,以顺序(Sequential)的方式维护变量集合。vector的特色有支持随机存取,在集合尾端增删元素很快,但是在集合中间增删元素比较费时。vector是C++标准程序库中的众多容器(container)之一。 vector以模板(泛型)方式实现,可以保存任意类型的变量,包括用户自定义的资料类型,例如:它可以是放置整数(int)类型的 vector、也可以是放置字符串(string)类型的 vector、或者放置用户自定类别(user-defined class)的 vector。vector 常被称为向量容器,因为该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为O(1);而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶O(n)。

2、vector容器原理

STL 众多容器中,vector 是最常用的容器之一,其底层所采用的数据结构非常简单,就只是一段连续的线性内存空间。

(1)vector 存储方式

vector使用 3 个迭代器(可以理解成指针)来表示的:

//_Alloc 表示内存分配器,此参数几乎不需要我们关心
template <class _Ty, class _Alloc = allocator<_Ty>>
class vector{
    ...
protected:
    pointer _Myfirst;
    pointer _Mylast;
    pointer _Myend;
};

其中,_Myfirst 指向的是 vector 容器对象的起始字节位置;_Mylast 指向当前最后一个元素的末尾字节;_myend 指向整个 vector 容器所占用内存空间的末尾字节。具体如下图所示:
C++ STL--vector容器_第1张图片
如上图所示,通过这 3 个迭代器,就可以表示出一个已容纳 2 个元素,容量为 5 的 vector 容器。
在此基础上,将 3 个迭代器两两结合,还可以表达不同的含义,例如:

  • _Myfirst 和 _Mylast 可以用来表示 vector 容器中目前已被使用的内存空间;
  • _Mylast 和 _Myend 可以用来表示 vector 容器目前空闲的内存空间;
  • _Myfirst 和 _Myend 可以用表示 vector 容器的容量。
  • 对于空的 vector 容器,由于没有任何元素的空间分配,因此 _Myfirst、_Mylast 和 _Myend 均为 null。

通过灵活运用这 3 个迭代器,vector 容器可以轻松的实现诸如首尾标识、大小、容器、空容器判断等几乎所有的功能,比如:

template <class _Ty, class _Alloc = allocator<_Ty>>
class vector{
public:
    iterator begin() {return _Myfirst;}
    iterator end() {return _Mylast;}
    size_type size() const {return size_type(end() - begin());}
    size_type capacity() const {return size_type(_Myend - begin());}
    bool empty() const {return begin() == end();}
    reference operator[] (size_type n) {return *(begin() + n);}
    reference front() { return *begin();}
    reference back() {return *(end()-1);}
    ...
};

(2)vector扩容原理

当 vector 的大小和容量相等(size==capacity)也就是满载时,如果再向其添加元素,那么 vector 就需要扩容。vector 容器扩容的过程需要经历以下 3 步:

  • 完全弃用现有的内存空间,重新申请更大的内存空间;
  • 将旧内存空间中的数据,按原有顺序移动到新的内存空间中;
  • 最后将旧的内存空间释放。

扩容之后注意点:

  • vector 容器在进行扩容后(内存重新分配),与其相关的指针、引用以及迭代器可能会失效的原因。
  • vector扩容比较耗时,由于需要重新分配内存并且需要复制数据。
  • vector每次扩容,所扩展的大小可能会比当前使用的大小大;

3、vector容器函数接口

(1)访问元素的方法

  • vec[i] - 访问索引值为 i 的元素引用。 (索引值从零起算,故第一个元素是vec[0]。)
  • vec.at(i) - 访问索引值为 i 的元素的引用,以 at() 访问会做数组边界检查,如果访问越界将会抛出一个例外,这是与operator[]的唯一差异。
  • vec.front() - 回传 vector 第一个元素的引用。
  • vec.back() - 回传 vector 最尾端元素的引用。

(2)新增或移除元素的方法

  • vec.push_back() - 新增元素至 vector 的尾端,必要时会进行存储器配置。
  • vec.pop_back() - 删除 vector 最尾端的元素。
  • vec.insert() - 插入一个或多个元素至 vector 内的任意位置。
  • vec.erase() - 删除 vector 中一个或多个元素。
  • vec.clear() - 清空所有元素。

(3)获取长度/容量

  • vec.size() - 获取 vector 目前持有的元素个数。
  • vec.empty() - 如果 vector 内部为空,则传回 true 值。
  • vec.capacity() - 获取 vector 目前可容纳的最大元素个数。这个方法与存储器的配置有关,它通常只会增加,不会因为元素被删减而随之减少。

(4)重新配置/重置长度

  • vec.reserve() - 如有必要,可改变 vector 的容量大小(配置更多的存储器)。在众多的 STL 实例,容量只能增加,不可以减少。
  • vec.resize() - 改变 vector 目前持有的元素个数。

(5)迭代 (Iterator)

  • vec.begin() - 回传一个Iterator,它指向 vector 第一个元素。
  • vec.end() - 回传一个Iterator,它指向 vector 最尾端元素的下一个位置(请注意:它不是最末元素)。
  • vec.rbegin() - 回传一个反向Iterator,它指向 vector 最尾端元素的。
  • vec.rend() - 回传一个Iterator,它指向 vector 的第一个元素的前一个位置。

4、 使用实例

  • push、insert和迭代操作
#include 
#include 
using namespace std;
int main()
{
    //初始化一个空vector容量
    vector<char>value;
    //向value容器中的尾部依次添加 S、T、L 字符
    value.push_back('S');
    value.push_back('T');
    value.push_back('L');
    //调用 size() 成员函数容器中的元素个数
    printf("元素个数为:%d\n", value.size());
    //使用迭代器遍历容器
    for (auto i = value.begin(); i < value.end(); i++) {
        cout << *i << " ";
    }
    cout << endl;
    //向容器开头插入字符
    value.insert(value.begin(), 'C');
    cout << "首个元素为:" << value.at(0) << endl;
    return 0;
}

输出结果:

元素个数为:3
S T L
首个元素为:C

参考资料:
《https://zh.wikipedia.org/wiki/Vector_(STL)》
《http://c.biancheng.net/view/6749.html》

你可能感兴趣的:(计算机语言,c++,开发语言)