C++ STL deque容器

等待樱花盛开

一、前言

deque 是 double-ended queue 的缩写,又称双端队列容器。deque 容器和 vecotr 容器有很多相似之处:
①deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素
②deque 容器也可以根据需要修改自身的容量和大小
与vector不同的是:deque 还擅长在序列头部添加或删除元素,所耗费的时间复杂度也为常数阶O(1)。deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中。
当需要向序列两端频繁的添加或删除元素时,应首选 deque 容器。deque 容器以模板类 deque<T>(T 为存储元素的类型)的形式在 <deque> 头文件中,并位于 std 命名空间中。因此,在使用该容器之前,代码中需要包含下面两行代码:

#include <deque>
using namespace std;

二、初始化deque容器

①std::deque<int> d;
②std::deque<int> d(10);
③std::deque<int> d(10, 5);
④std::deque<int> d2(d);
⑤//拷贝普通数组,创建deque容器
int a[] = { 1,2,3,4,5 };
std::deque<int>d(a, a + 5);
⑥//适用于所有类型的容器
std::array<int, 5>arr{ 11,12,13,14,15 };
std::deque<int>d(arr.begin()+2, arr.end());//拷贝arr容器中的{13,14,15}

①创建空的deque容器,和空 array 容器不同,空的 deque 容器在创建之后可以做添加或删除元素的操作
②创建一个具有10个元素、元素默认值为0的deque容器
③创建一个具有10个元素的deque容器,指定初始值为5的deque容器
④拷贝初始化deque容器d2,需要保证新旧容器存储的元素类型一致

1、成员函数

此处不列举迭代器、添加和删除等相关函数

函数功能
size()返回实际元素个数
max_size()返回容器所能容纳元素个数的最大值,一般是 232-1
resize()改变实际元素的个数
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false
shrink _to_fit()将内存减少到等于当前元素实际所使用的大小
at()使用经过边界检查的索引访问元素
front()返回第一个元素的引用
back()返回最后一个元素的引用
assign()用新元素替换原有内容
swap()交换两个容器的所有元素
std::swap(x , y)非成员函数,交换数据

说明:与vector相比,额外增加了实现在容器头部添加和删除元素的成员函数,同时删除了 capacity()、reserve() 和 data() 成员函数。

2、实例

1)初始化

//初始化deque
    //拷贝普通数组,创建deque容器
    int a[] = { 10,25,37,40,15 };
    std::deque<int> dequeInt(a, a + 5);

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

    //迭代器访问
    int i = 0;
    std::deque<int>::iterator dequeIter = dequeInt.begin();
    for (; dequeIter != dequeInt.end(); dequeIter++)
    {
        std::cout << "iterator dequeInt[" << i << "]=" << *dequeIter << std::endl;
    }
    std::cout << "iterator dequeInt size: " << dequeInt.size() << std::endl;


    dequeInt.push_front(190);
    dequeInt.push_back(9001);

    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "push_front and push_back dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }
    std::cout << "push_front and push_back dequeInt size: " << dequeInt.size() << std::endl;

结果如下:
image.png

三、迭代器

deque 容器迭代器的类型为随机访问迭代器。
1、deque支持的迭代器成员函数

函数功能
begin()返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器
end()返回指向容器最后一个元素之后一个位置的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin() 搭配使用
rbegin()返回指向最后一个元素的反向迭代器;如果是 const 类型容器,在该函数返回的是常量反向迭代器
rend()返回指向第一个元素之前一个位置的反向迭代器。如果是 const 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 rbegin() 搭配使用
cbegin()和 begin() 功能类似,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素
cend()和 end() 功能相同,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素
crbegin()和 rbegin() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素
crend()和 rend() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素

函数的具体功能和array、vector的类似,这里不再详细说明。stl支持全局的begin()和end()函数。

2、基本用法

1、begin()和end()

begin() 和 end() 分别用于指向「首元素」和「尾元素+1」 的位置

2、cbegin()和cend()

和 begin()/end() 唯一不同的是:cbegin()/cend() 成员函数返回的是 const 类型的正向迭代器,这样可以用来遍历容器内的元素,也可以访问元素,但是不能对所存储的元素进行修改

3、rbegin()和rend()

分别表示指向最后一个元素和第一个元素前一个位置的随机访问迭代器,又常称为反向迭代器。
crbegin()/crend() 组合和 rbegin()/crend() 组合唯一的区别在于:前者返回的迭代器为 const 类型迭代器,不能用来修改容器中的元素,除此之外在使用上和后者完全相同。

3、注意事项

1)、迭代器的功能是遍历容器,在遍历的同时可以访问(甚至修改)容器中的元素,但迭代器不能用来初始化空的 deque 容器
2)、对于空的 deque 容器来说,可以通过 push_back()、push_front() 或者 resize() 成员函数实现向(空)deque 容器中添加元素。
3)、当向 deque 容器添加元素时,deque 容器会申请更多的内存空间,同时其包含的所有元素可能会被复制或移动到新的内存地址(原来占用的内存会释放),这会导致之前创建的迭代器失效。和vector类似。

4、示例

 //全局begin和end
    i = 0;
    for (dequeIter = begin(dequeInt); dequeIter < end(dequeInt); dequeIter++)
    {
        std::cout << "global begin and end dequeInt[" << i << "]=" << *dequeIter << std::endl;
    }

    //cbegin/cend
    i = 0;
    std::deque<int>::const_iterator dequeIterC = dequeInt.cbegin();
    for (; dequeIterC != dequeInt.cend(); dequeIterC++)
    {
        std::cout << "cbegin and cend dequeInt[" << i << "]=" << *dequeIterC << std::endl;
    }

    //rbegin/rend
    i = 0;
    std::deque<int>::reverse_iterator dequeIterR = dequeInt.rbegin();
    for (; dequeIterR != dequeInt.rend(); dequeIterR++)
    {
        std::cout << "rbegin and rend dequeInt[" << i << "]=" << *dequeIterR << std::endl;
    }

    //crbegin/crend
    i = 0;
    std::deque<int>::const_reverse_iterator dequeIterCR = dequeInt.crbegin();
    for (; dequeIterCR != dequeInt.rend(); dequeIterCR++)
    {
        std::cout << "crbegin and crend dequeInt[" << i << "]=" << *dequeIterCR << std::endl;
    }

结果如下:
image.png

四、添加和删除元素

deque 容器中,无论是添加元素还是删除元素,都只能借助 deque 模板类提供的成员函数。

1、涉及的相关函数

函数功能
push_back()在容器现有元素的尾部添加一个元素
pop_back()移除容器尾部的一个元素
push_front()在容器现有元素的头部添加一个元素
pop_front()移除容器尾部的一个元素
emplace_back()在容器尾部生成一个元素,效率比push_back()高
emplace_front()在容器头部生成一个元素,效率比push_front()高
insert()在指定的位置直接生成一个元素
emplace()在指定的位置直接生成一个元素,效率比insert高
erase()移除一个元素或某一区域内的多个元素
clear()删除容器中所有的元素

insert的用法

格式功能
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、示例

添加、删除

std::deque<int> dequeInt;

    dequeInt.push_back(319);
    std::cout << "push_back dequeInt size: " << dequeInt.size() << std::endl;
    dequeInt.pop_back();
    std::cout << "pop_back dequeInt size: " << dequeInt.size() << std::endl;

    dequeInt.push_front(31);
    dequeInt.push_front(571);
    dequeInt.push_front(910);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "push_front dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }

    dequeInt.pop_front();
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "pop_front dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }

    dequeInt.emplace_front(1099);
    dequeInt.emplace_back(7100);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "emplace_front and emplace_back dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }

    dequeInt.emplace(dequeInt.begin() + 2, 4301);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "emplace dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }

    dequeInt.erase(dequeInt.begin() + 2);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "erase appoint dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }

结果如下:
image.png

insert用法

 std::deque<int> dequeInt{4301,2591,671};
    std::cout << "dequeInt size: " << dequeInt.size() << std::endl;

    dequeInt.insert(dequeInt.begin() + 2, 798);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "insert1 dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }
    std::cout << "dequeInt size: " << dequeInt.size() << std::endl;

    dequeInt.insert(dequeInt.begin() + 3, 3, 9);
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "insert2 dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }
    std::cout << "insert2 dequeInt size: " << dequeInt.size() << std::endl;

    std::array<int, 3> arrayInt{ 901,756,34 };
    dequeInt.insert(dequeInt.begin() + 5, arrayInt.begin(), arrayInt.end());
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "insert3 dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }
    std::cout << "insert3 dequeInt size: " << dequeInt.size() << std::endl;

    dequeInt.insert(dequeInt.begin() + 1, { 88,92,34 });
    for (int i = 0; i < dequeInt.size(); i++)
    {
        std::cout << "insert4 dequeInt[" << i << "]=" << dequeInt[i] << std::endl;
    }
    std::cout << "insert4 dequeInt size: " << dequeInt.size() << std::endl;

结果如下:
image.png

阅读 349

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

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

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

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