信息学奥赛第十三节 —— 双端队列deque

本文介绍了C++中的双端队列deque,它支持随机访问迭代器,允许在队首和队尾进行元素的添加与删除。deque与vector相比,插入元素时速度更快,尤其是在队首插入元素时。文章通过代码示例展示了deque的基本操作,如push_front()、push_back()、pop_front()和pop_back(),并提供了模拟双向队列操作的解题思路和AC代码。
双端队列DEQUE

deque又叫双端队列,它支持随机访问迭代器。与普通的队列不同,双端队列可以在队首增加和删除元素,也可以在对尾增加和删除元素,不必再遵循队首出队、队尾入队的原则。

双端队列与vector的区别
  • 缺点deque存储元素的速度比vector快一些。因为它们两都是可变长的,实现可变长的方法是倍增(什么是倍增思想?如:长度变为当前容器内元素个数的2倍)。但是,vector只需要在一端改变,而deque需要向两端增加长度,操作变多,因此速度稍慢一些。
  • 优点:使用vector存储元素时,当遇到在数组头部位置插入元素的时候,需要先将所有的元素后移一位,再将新元素插入首位,这样操作的话时间复杂度为O(N)。相同的情况,如果使用双端队列存储元素,可以直接在首部插入元素,时间复杂度为O(1)
函数
  • push_front() —— 在双端队列的队头加入元素
  • push_back() —— 在双端队列的队尾加入元素
  • pop_front() —— 在双端队列的队头删除元素
  • pop_back() —— 在双端队列的队尾删除元素
  • 以上函数如果不记得,可以在需要使用时前往C++ Reference中查找
deque的基本操作(插入、删除及遍历)
#include <iostream>
#include <deque>

using namespace std;

void print(deque<int> d)//输出函数
{
    for (int i = 0;i < d.size();i++) 
        cout << d[i] << " ";
    cout << endl;
}

int main()
{
    deque<int> d(5,100);//双端队列中包含5个100
    print(d);//100 100 100 100 100
    
    d.push_front(521);
    d.push_back(521);//在队首和队尾都插入元素
    print(d);//521 100 100 100 100 100 521
    
    d.pop_back();
    d.pop_front();//删除队首和队尾元素
    print(d);//100 100 100 100 100
    
    //迭代器遍历双端队列
    deque<int>::iterator it;
    for (it = d.begin();it != d.end();it++)
        cout << *it  << " ";//100 100 100 100 100
    cout << endl;
    
    for (it = d.begin();it < d.end();it += 2)
        cout << *it  << " ";//100 100 100
    cout << endl;
    
    return 0;
}
例题(原题链接)

题目描述

想想双向链表……双向队列的定义差点儿相同,也就是说一个队列的队尾同一时候也是队首。两头都能够做出队,入队的操作。
如今给你一系列的操作。请输出最后队列的状态;
命令格式:
LIN X (X表示一个整数)命令代表左边进队操作;
RIN X 表示右边进队操作;
ROUT 表示右边出队操作;
LOUT 表示从左边出队操作。

输入

第一行包括一个整数M(M<=10000),表示有M个操作;下面M行每行包括一条命令;
命令可能不合法,对于不合法的命令,请在输出中处理;

输出

输出的第一行包括队列进行了M次操作后的状态。从左往右输出,每两个之间用空格隔开。
下面若干行处理不合法的命令(假设存在);
对于不合法的命令。请输出一行X ERROR
当中X表示是第几条命令;

样例输入

8
LIN 5
RIN 6
LIN 3
LOUT
ROUT
ROUT
ROUT
LIN 3

样例输出

3
7 ERROR

解题思路:模拟过程即可
AC代码

#include <iostream>
#include <deque>

using namespace std;
const int N = 10010;
int x,cnt,acnt;//cnt用来记录命令的编号,acnt是错误命令的编号在数组中的下标
int a[N];//存储错误命令的编号
deque<int> d;

int main()
{
    deque<int>::iterator it;
    int t; cin >> t;
    string s;//表示接受的命令
    while (t --)
    {
        cin >> s;
        if (s == "LIN") 
        {
            cnt++;
            cin >> x;
            d.push_front(x);
        }
        else if (s == "RIN") 
        {
            cnt++;
            cin >> x;
            d.push_back(x);
        }
        else if (s == "LOUT")
        {
            cnt++;
            if (d.empty()) a[acnt++] = cnt;//队空
            else d.pop_front();//队列左端元素出队
        }
        else if (s == "ROUT")
        {
            cnt++;
            if (d.empty()) a[acnt++] = cnt;//队空
            else d.pop_back();//队列右端元素出队
        }
    }
    
    //遍历deque
    for (it = d.begin();it != d.end();it++) cout << *it << " ";
    cout << endl;
    //遍历数组
    for (int i = 0;i < acnt;i++)
    {
        cout << a[i] << " " << "ERROR";
        cout << endl;
    }
    return 0;
}
### 双端队列 Deque 数据结构 #### 定义 双端队列 (Deque, Double-ended Queue) 是一种可以从两端进行插入和删除操作的线性数据结构[^1]。这种特性使得它可以灵活地处理多种类型的队列需求。 #### 基本操作 双端队列支持如下基本操作: - `push_front(x)`:在前端插入元素 x。 - `pop_front()`:移除并返回前端元素。 - `push_back(x)`:在后端插入元素 x。 - `pop_back()`:移除并返回后端元素。 - `empty()`:判断双端队列是否为空。 - `size()`:获取当前存储元素的数量。 这些操作的时间复杂度通常为 O(1),这得益于内部采用的高效实现机制。 #### 实现方式 双端队列可以通过两种主要的方式实现——基于数组或者链表。每种方法都有各自的优劣之处: - **数组实现**:通过动态分配连续内存来模拟双端队列的行为,适合于已知大小范围的情况;但在频繁增删时可能会引发大量的内存复制开销。 - **链表实现**:利用点之间的指针链接形成双向循环列表,允许任意位置快速插入/删除而不必担心内存重定位问题,更适合未知规模的数据集。 对于 C++ 中的标准库容器 `std::deque` 而言,则采用了分段管理的技术方案,在保持随机访问特性的前提下优化了性能表现[^2]。 然而值得注意的是,由于 `std::deque` 的特殊设计,当涉及到大量遍历操作时,其效率相对较低,因为每次迭代都需要额外检查是否跨越了某个小块区域的边界[^3]。 #### 应用场景 尽管存在上述局限性,双端队列仍然有着广泛的应用领域: - 作为标准模板库(STL)中栈(stack)和队列(queue)的基础实现之一; - 处理需要同时维护最新与最旧记录的任务调度算法; - 缓存淘汰策略中的 LRU(Least Recently Used)缓存管理; - 图形界面应用程序的消息传递系统等[^4]。 ```cpp // 创建一个简单的 C++ std::deque 并执行一些基础操作 #include <iostream> #include <deque> int main() { std::deque<int> d; // 插入几个整数到 deque 尾部 for(int i=0; i<5; ++i){ d.push_back(i); } // 输出所有元素 while(!d.empty()){ std::cout << d.front() << ' '; d.pop_front(); } return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值