雪花飘落

C++中常见的三种序列式容器vector、list、deque

前言

  C++中标准的数组使用起来确实很方便,随机访问也很快。但是有一个致命的缺点:由于数组是一组固定的连续空间,所以不允许删除和添加元素。在实际的应用场景中,会显得有些捉襟见肘。STL中提供了很多不同的结构容器来弥补传统数组的不足,这里主要介绍常用的三种序列式容器。

vector

  向量vector是最常用的一种,对比数组,它允许元素的插入和删除操作。事实上,vector底层逻辑也是数组,它的空间是连续的。它会预留一部分的空间来供元素插入,当需要插入的元素比较多时,就会重新申请一块较大的空间,然后把整个复制过去,最后释放原空间。而当删除元素时,原来的空间也不会得到释放,仍然会作为容量的一部分。

  由于空间的连续性,因此,在执行插入操作时,越靠后需要移动的元素越少,执行插入的效率越高,删除同理。反之,在头部执行插入和删除的效率就会异常地低,如果需要大量的插入新元素,或者需要频繁的操作头部的数据,那么vector可能不是最好的选择。

  因为空间的连续性,所以vector支持随机访问(下标访问)且效率很高,同时,它的迭代器支持it+n操作。

vector声明和初始化

要使用vector需要包含头文件<vector>,基本语法为:

vector<typename> variblename(constructor);

例如:

    //声明一个存储int类型数据的向量
    vector<int> v;
    //声明一个长度为5(注意并非最大容量为5)的向量,并全部初始化为0
    vector<int> v1(5);
    //声明一个长度为5的向量,并全部初始化为2
    vector<int> v2(5,2);
    //声明一个向量,并初始化元素1,2,3
    vector<int> v3{1,2,3};

常用方法

 v.capacity();  //容器容量

 v.size();      //容器大小

 v.at(int idx); //用法和[]运算符相同

 v.push_back(); //尾部插入

 v.pop_back();  //尾部删除

 v.front();     //获取头部元素

 v.back();      //获取尾部元素

 v.begin();     //头元素的迭代器

 v.end();       //尾部元素的迭代器

 v.insert(pos,elem); //pos是vector的插入元素的位置

 v.insert(pos, n, elem) //在位置pos上插入n个元素elem

 v.insert(pos, begin, end);//在pos位置插入在[beg,end)区间的数据。

 v.erase(pos);   //移除pos位置上的元素,返回下一个数据的位置

 v.erase(begin, end); //移除[begin, end)区间的数据,返回下一个元素的位置 

 v.reverse(pos1, pos2); //将vector中的pos1~pos2的元素逆序存储

list

  list底层是一个双向链表,因此它也具有链表的特性,即高效的插入和删除操作,但是访问效率较低,且不支持随机访问,也无法使用下标[]来访问元素。它的迭代器只能进行自增或自减,无法使用it+n操作,因为无法预测节点的位置。

  list的每一个节点都有三个部分组成:前驱指针域,数据域和后继指针域。这也时双向链表的显著特征。

  前驱指针域存储前一个节点的位置,数据域保存本节点的数据,后继指针域保存后继节点的位置。每一个节点在内存中的空间并不连续,节点与节点之间完全靠指针联系,无法跨节点访问,属于逻辑意义上的线性表。

deque

   deque的全称是double-ended queue 即双端队列。它是一个双开口的分段连续的线性空间,兼具链表和数组的部分特性。它是由一段一段的连续空间连起来的,每一段空间的首地址会单独存放在一个数组中。因此,deque内部的结构分为分段数组和索引数组, 分段数组是存储数据的,索引数组是存储每段数组的首地址的。

  deque的内部是分段的动态连续空间。当需要执行插入时,会先尝试在两端的段内空间进行操作,如果不足时,就会在deque的头部或者尾部配置一段新的空间。所以向两端插入元素效率较高,而中间插入元素效率较低(因为需要对索引数组进行维护)。而deque通过索引数组这个中控器和复杂的迭代器来维持整体连续的假象,因此,在使用时,deque也表现出连续空间容器的特征:我们可以使用下标来进行随机访问,同时,迭代器也支持it+n操作。

 

  关于list和deque的使用,大致语法和vector差不多,这里就不再赘述了。另行按需查阅资料即可。

  特别的,以deque为例,一个二维结构的创建方式:

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

int main(){
    //创建一个一维deque,初始化三个元素1,2,3
    deque<int> deque1{1,2,3};
    //一个外部deque,里面初始化5个deque1,形成二维结构
    deque<deque<int>> deque2(5,deque1);
    //遍历
    for(deque<int> i:deque2){
        for(int j:i){
            cout<<j<<endl;
        }
    }
}

 

  

posted @ 2021-12-25 16:38  haruyuki  阅读(420)  评论(0编辑  收藏  举报