构算法度·deque容器

一、deque容器的定义

1.什么是deque容器

deque容器时 是 “double-ended queue” 的缩写,翻译为“双端队列”。它是一种可以在容器头部和尾部快速进行插入和删除操作的顺序容器

2.deque容器与vector容器的联系

deque容器和上一篇学习的vector容器有很多相似点,如:

  • deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。
  • deque 容器也可以根据需要修改自身的容量和大小。

当然,和 vector 不同的是,deque 还擅长在序列头部添加或删除元素,所耗费的时间复杂度也为常数阶O(1)。并且更重要的一点是,deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中。

给出deque容器和vector容器的对比表方便大家直白理解:

特性deque容器vector容器
内存结构分段连续(块+映射表)完全连续
头部插入/删除O(1)O(n)(需要移动所有元素)
尾部插入/删除O(1)O(1)(均摊)
中间插入/删除O(n)O(n)
随机访问性能O(1),(先找到块,再在块内偏移)稍慢于vectorO(1),最优
内存稳定性高:元素地址稳定低:扩容时所有元素都会移动地址
迭代器失效头尾操作:通常不失效
中间操作:局部失效
控制块重分配:全部失效
扩容时:全部失效
尾部操作:end()失效
中间操作:之后的所有失效

因此,

  • deque容器适合高频头尾操作(如任务队列、滑动窗口)。
  • vector容器适合尾部操作+随机访问(如动态数组、数据缓存)。

二、deque容器的使用

1.deque容器的创建

  • 创建一个没有任何元素的空 deque 容器:
deque<int> d;  //最常见的构造,空的 deque 容器在创建之后可以做添加或删除元素的操作
  • 创建一个具有 n 个元素的 deque 容器,其中每个元素都采用对应类型的默认值:
deque<int> d(10);  //此行代码创建一个具有 10 个元素(默认都为 0)的 deque 容器。
  • 创建一个具有 n 个元素的 deque 容器,并为每个元素都指定初始值,例如:
deque<int> d(10, 5);  //如此就创建了一个包含 10 个元素(值都为 5)的 deque 容器。
  • 在已有 deque 容器的情况下,可以通过拷贝该容器创建一个新的 deque 容器,例如:
deque<int> d1(5);
deque<int> d2(d1);  //采用此方式,必须保证新旧容器存储的元素类型一致。
  • 通过拷贝其他类型容器中指定区域内的元素(也可以是普通数组),可以创建一个新容器,例如:
//拷贝普通数组,创建deque容器
int a[] = { 1,2,3,4,5 };
std::deque<int>d(begin(a), end(a));
//适用于所有类型的容器
vector<int> v { 11,12,13,14,15 };
deque<int> d (v.begin()+2, v.end());//拷贝vector容器中的{13,14,15}

2.deque容器内置函数方法

2.1 Iterators(迭代器)

函数名描述示例
begin返回指向第一个元素的迭代器auto it = d.begin();
end返回指向最后一个元素之后位置的迭代器auto end = d.end();
cbegin返回指向第一个元素的const迭代器auto it = d.cbegin();
cend返回指向末尾之后位置的const迭代器auto end = d.cend();
rbegin返回指向最后一个元素的反向迭代器auto rit = d.rbegin();
rend返回指向第一个元素之前位置的反向迭代器auto rend = d.rend();
crbegin返回const反向迭代器auto rit = d.crbegin();
crend返回const反向迭代器末尾auto crend = d.crend();

2.2 Capacity(容量)

函数名描述时间复杂度示例
empty检查容器是否为空O(1)if(d.empty())
size返回容器中元素的个数O(1)int n = d.size();
max_size返回容器可容纳的最大元素数O(1)size_t max = d.max_size();
resize调整容器大小O(N)d.resize(10);
shrink_to_fit请求移除未使用的容量(非强制)O(N)d.shrink_to_fit();

2.3 Element access(元素访问)

函数名描述时间复杂度示例
operator[]下标访问(不检查边界)O(1)int val = d[2];
at带边界检查的元素访问O(1)int val = d.at(2);
front访问第一个元素O(1)int first = d.front();
back访问最后一个元素O(1)int last = d.back();

2.4 Modifiers(修改器)

函数名描述时间复杂度示例
push_back尾部插入一个元素O(1)d.push_back(10);
push_front头部插入一个元素O(1)d.push_front(10);
pop_back删除尾部元素O(1)d.pop_back();
pop_front删除头部元素O(1)d.pop_front();
emplace_back尾部原位构造元素O(1)d.emplace_back(10, 20);
emplace_front头部原位构造元素O(1)d.emplace_front(10, 20);
insert在指定位置插入元素/范围O(N)d.insert(it, 99);
emplace在指定位置原位构造O(N)d.emplace(it, 99);
erase删除指定位置/范围的元素O(N)d.erase(it);
clear清空所有元素O(N)d.clear();
assign替换容器内容O(N)d.assign({1,2,3});
swap交换两个容器的内容O(1)d1.swap(d2);

2.5 核心部分总结

必须掌握

函数类别说明
push_back()修改器尾部插入元素
push_front()修改器头部插入元素
pop_back()修改器尾部删除元素
pop_front()修改器头部删除元素
operator[]元素访问随机访问元素
front()元素访问获取第一个元素
back()元素访问获取最后一个元素
empty()容量判断是否为空
size()容量获取元素数量
begin()/end()迭代器遍历容器

建议掌握

函数类别说明
insert()修改器中间插入元素
erase()修改器删除元素
clear()修改器清空容器
at()元素访问带边界检查的访问
resize()容量调整大小
assign()修改器重新赋值

了解

函数类别说明
emplace_back()修改器原位构造(避免拷贝)
emplace_front()修改器头部原位构造
emplace()修改器中间原位构造
rbegin()/rend()迭代器反向遍历
shrink_to_fit()容量请求压缩内存
max_size()容量最大可能大小

3. 样例代码及分析

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

int main() {
    /******************** 1. 基本创建和初始化 ********************/
    // 创建空deque
    deque<int> d1;
    
    // 创建并初始化
    deque<int> d2 = {1, 2, 3, 4, 5};
    
    // 创建指定大小
    deque<int> d3(3);        // 3个0
    deque<int> d4(3, 100);   // 3个100
    
    /******************** 2. 两端操作(核心优势) ********************/
    deque<int> d;
    
    // 尾部插入
    d.push_back(10);     // [10]
    d.push_back(20);     // [10, 20]
    d.push_back(30);     // [10, 20, 30]
    
    // 头部插入(vector做不到高效!)
    d.push_front(0);     // [0, 10, 20, 30]
    d.push_front(-10);   // [-10, 0, 10, 20, 30]
    
    // 头部删除
    d.pop_front();       // [0, 10, 20, 30]
    
    // 尾部删除
    d.pop_back();        // [0, 10, 20]
    
    /******************** 3. 元素访问 ********************/
    // 随机访问
    cout << "第一个元素: " << d.front() << endl;   // 0
    cout << "最后一个元素: " << d.back() << endl;  // 20
    cout << "第二个元素: " << d[1] << endl;        // 10
    cout << "第二个元素(安全): " << d.at(1) << endl; // 10
    
    /******************** 4. 容量查询 ********************/
    cout << "大小: " << d.size() << endl;       // 3
    cout << "是否为空: " << (d.empty() ? "是" : "否") << endl; // 否
    
    /******************** 5. 遍历方法 ********************/
    cout << "遍历结果: ";
    
    // 方法1:范围for循环(最常用)
    for (int num : d) {
        cout << num << " ";  // 0 10 20
    }
    cout << endl;
    
    // 方法2:使用迭代器
    for (auto it = d.begin(); it != d.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // 方法3:使用下标
    for (int i = 0; i < d.size(); i++) {
        cout << d[i] << " ";
    }
    cout << endl;
    
    /******************** 6. 中间操作 ********************/
    // 在指定位置插入
    d.insert(d.begin() + 1, 99);  // [0, 99, 10, 20]
    
    // 删除指定位置
    d.erase(d.begin() + 2);       // [0, 99, 20]
    
    /******************** 7. 清空容器 ********************/
    d.clear();
    cout << "清空后大小: " << d.size() << endl;  // 0
    
    /******************** 8. 实用场景示例 ********************/
    
    // 场景1:deque作为队列(FIFO)
    cout << "\n作为队列使用:" << endl;
    deque<int> queue;
    queue.push_back(1);  // 入队
    queue.push_back(2);
    queue.push_back(3);
    
    while (!queue.empty()) {
        cout << queue.front() << " ";  // 出队顺序:1 2 3
        queue.pop_front();
    }
    cout << endl;
    
    // 场景2:deque作为栈(LIFO)
    cout << "\n作为栈使用:" << endl;
    deque<int> stack;
    stack.push_back(10);  // 压栈
    stack.push_back(20);
    stack.push_back(30);
    
    while (!stack.empty()) {
        cout << stack.back() << " ";  // 弹栈顺序:30 20 10
        stack.pop_back();
    }
    cout << endl;
    
    // 场景3:与算法结合
    cout << "\n与算法结合:" << endl;
    deque<int> nums = {5, 3, 8, 1, 9, 2};
    
    // 排序
    sort(nums.begin(), nums.end());
    cout << "排序后: ";
    for (int n : nums) cout << n << " ";
    cout << endl;
    
    // 查找
    auto it = find(nums.begin(), nums.end(), 8);
    if (it != nums.end()) {
        cout << "找到8,位置索引: " << distance(nums.begin(), it) << endl;
    }
    
    return 0;
}

下一篇我考虑给大家总结出竞赛中常用的一些stl算法函数,本篇还请大家一定要掌握,打好基础。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇