3.1 序列式容器-vector

本文详细介绍了STL中的几种常见容器,包括序列式容器(如vector、list、deque)及其特点,以及关联式容器(如set、map等)的使用。重点讲解了vector的动态增长机制,涉及insert、pop_back和erase操作。
摘要由CSDN通过智能技术生成

STL中一些常见的容器:

  1. 序列式容器(Sequence Containers)

    • vector(动态数组): 动态数组,支持随机访问和在尾部快速插入/删除。
    • list(链表): 双向链表,支持在任意位置快速插入/删除。
    • deque(双端队列): 双端队列,支持在两端快速插入/删除。

    容器适配器(Container Adapters):

    • stack(栈): 后进先出(LIFO)的数据结构。
    • queue(队列): 先进先出(FIFO)的数据结构。
    • priority_queue(优先队列): 具有优先级的队列。

  2. 关联式容器(Associative Containers)

    • set(集合): 有序集合,不允许重复元素。
    • multiset(多重集合): 有序集合,允许重复元素。
    • map(映射): 键-值对的集合,按键有序存储,不允许重复键。
    • multimap(多重映射): 键-值对的集合,按键有序存储,允许重复键。

    无序关联容器(Unordered Associative Containers):

    • unordered_set: 无序集合,不允许重复元素。
    • unordered_multiset: 无序集合,允许重复元素。
    • unordered_map: 无序映射,按键无序存储,不允许重复键。
    • unordered_multimap: 无序映射,按键无序存储,允许重复键。

序列式容器

1.vector

1.1定义

C++本身提供了一个序列容器array数组,STL中新增了一个vector,被称为动态数组。

它与array的区别是它提供了动态空间大小。

例如:

std::array<int, 5> myArray = {1, 2, 3, 4, 5};
std::vector<int> myVector = {1, 2, 3, 4, 5};

1.2迭代器

vector的迭代器所需功能,普通指针就能满足,所以在vector容器中,迭代器就是普通指针,并且其类型属于随机访问迭代器,支持跳跃式的访问。支持++,—,+=,-=等操作运算。

所以vector容器元素的访问的时间复杂度是O(1).

1.2数据结构

vector的数据结构是一块连续的线性空间。其中以两个迭代器start和finish分别指向配置得来的连续空间中已被使用的范围,以迭代器end_of_storage指向整块连续空间的尾端:

template <class T,class Alloc=alloc>
class vector
{
    ...
protected:
    
    iterator start;//目前使用的空间的头部
    
    iterator finish;//目前使用的空间的尾部
    
    iterator end_of_storage; //目前可用空间的尾部 
...
}

为了减少空间动态配置时的成本,vector实际配置的大小(capacity)可能比需求更大一些,以备将来可能的扩充。vector这里就有一个容量capacity的概念。和vector大小size的概念对应。vector的容量永远大于或等于其大小。一旦容量等于大小,便是满载,下次再有新增元素,整个vector就要进行转移。
在这里插入图片描述
在这里插入图片描述

1.3vector的push_back(如何动态增长)

在这里插入图片描述
其中核心点在于insert_aux函数

template <class T,class Alloc>
void vector<T,Alloc>::insert_aux(iterator position,const T& x)
{   
    //检查是否还有备用空间
    if(finish!=end_of_storage){
        //在备用空间起始处构造一个元素,并以vector最后一个元素为其初始值
        construct(finish,*(finish-1));
        //移动finish指针
        ++finish;
        //拷贝内容
        T x_copy=x;
        //执行拷贝
        copy_backward(position,finish-2,finish-1);
        *position=x_copy;
    }else {
        //进入这里表示已经不存在可用空间
        const size_type old_size=size();
        //决定分配空间的大小
        const size_type len=old_size!=0?2*old_size:1;
        //实际分配
        iterator new_start=data_allocator::allocate(len);
        iterator new_finish=new_start;
        try{
            //拷贝元素
            new_finish=uninitialized_copy(start,position,new_start);
            //为新元素设定初值x
            construct(new_finish,x);
            //调整指针位置
            ++new_finish;
        }catch(...){
            destroy(new_start,new_finish);
            data_allocator::deallocate(new_start,len);
            throw;
        }
        //释放原来的内存
        destroy(begin(),end());
        deallocate();
        //调整迭代器,指向新vector
        start=new_start;
        finish=new_finish;
        end_of_storage=new_start+len;
    }
}

可以看出来vector所谓的动态增加大小,并不是在原有空间之后接新的空间(因为无法保证原空间之后还有连续的可配置空间),而是以原大小的两倍来另外配置一块较大的空间,然后再将原有内容拷贝过来,并释放原空间。因此需要注意的是vector一旦引起了的空间重新配置,指向原vector的所有迭代器都失效了。

1.4vector的pop_back、erase、insert

pop_back和erase比较简单,如下所示:
在这里插入图片描述

  • insert存在三种情况。

例如插入代码insert(iter, 2, 1),表示从位置iter开始插入,插入2个为1的数。

  1. 插入n个数后,没有引发动态配置空间。且插入的数量大于插入点之后的现有元素个数;
  2. 插入n个数后,没有引发动态配置空间。且插入的数量小于等于插入点之后的现有元素个数;
  3. 插入n个数后,引发了动态配置空间。

3种情况的源码和示意图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于是在原有的空间上来构造插入数据,没有生成多余的临时变量(尽可能地压榨性能),所以会有以上两种情况。
在这里插入图片描述
三种情况插入都会引发迭代器失效问题,前两种会导致position之后的所有迭代器均失效,最后一种情况会导致所有迭代器失效。

  • 40
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aries_Ro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值