双端队列(Deque)原理及实现

简介: 双端队列支持在队头和队尾进行插入和删除操作,比标准队列更灵活。它可用链表或环形数组实现,头尾操作时间复杂度均为O(1)。适用于需频繁在两端操作的场景,如算法题中模拟栈或队列。

基本原理
如果你理解了前面讲解的内容,这个双端队列其实没啥可讲的了。所谓双端队列,主要是对比标准队列(FIFO 先进先出队列)多了一些操作罢了:
标准队列 只能在队尾插入元素,队头删除元素,而双端队列的队头和队尾都可以插入或删除元素。
普通队列就好比排队买票,先来的先买,后来的后买;而双端队列就好比一个过街天桥,两端都可以随意进出。当然,双端队列的元素就不再满足「先进先出」了,因为它比较灵活嘛。
在做算法题的场景中,双端队列用的不算很多。感觉只有 Python 用到的多一些,因为 Python 标准库没有提供内置的栈和队列,一般会用双端队列来模拟标准队列。
用链表实现双端队列
很简单吧,直接复用 我们之前实现的MyLinkedList 或者标准库提供的 LinkedList 就行了。因为双链表本就支持 O(1) 时间复杂度在链表的头尾增删元素:
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.LinkedList;

public class MyListDeque {
private LinkedList list = new LinkedList<>();

// 从队头插入元素,时间复杂度 O(1)
void addFirst(E e) {
    list.addFirst(e);
}

// 从队尾插入元素,时间复杂度 O(1)
void addLast(E e) {
    list.addLast(e);
}

// 从队头删除元素,时间复杂度 O(1)
E removeFirst() {
    return list.removeFirst();
}

// 从队尾删除元素,时间复杂度 O(1)
E removeLast() {
    return list.removeLast();
}

// 查看队头元素,时间复杂度 O(1)
E peekFirst() {
    return list.getFirst();
}

// 查看队尾元素,时间复杂度 O(1)
E peekLast() {
    return list.getLast();
}

public static void main(String[] args) {
    MyListDeque<Integer> deque = new MyListDeque<>();
    deque.addFirst(1);
    deque.addFirst(2);
    deque.addLast(3);
    deque.addLast(4);

    System.out.println(deque.removeFirst()); // 2
    System.out.println(deque.removeLast()); // 4
    System.out.println(deque.peekFirst()); // 1
    System.out.println(deque.peekLast()); // 3
}

}
用数组实现双端队列
也很简单吧,直接复用我们在 环形数组技巧 中实现的 CycleArray 提供的方法就行了。环形数组头尾增删元素的复杂度都是 O(1):
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MyArrayDeque {
private CycleArray arr = new CycleArray<>();

// 从队头插入元素,时间复杂度 O(1)
void addFirst(E e) {
    arr.addFirst(e);
}

// 从队尾插入元素,时间复杂度 O(1)
void addLast(E e) {
    arr.addLast(e);
}

// 从队头删除元素,时间复杂度 O(1)
E removeFirst() {
    return arr.removeFirst();
}

// 从队尾删除元素,时间复杂度 O(1)
E removeLast() {
    return arr.removeLast();
}

// 查看队头元素,时间复杂度 O(1)
E peekFirst() {
    return arr.getFirst();
}

// 查看队尾元素,时间复杂度 O(1)
E peekLast() {
    return arr.getLast();
}

}

相关文章
|
机器学习/深度学习 资源调度 数据可视化
UCB Data100:数据科学的原理和技巧:第十六章到第十八章
UCB Data100:数据科学的原理和技巧:第十六章到第十八章
407 0
|
存储 SQL JavaScript
聊一聊常见的浏览器数据存储方案(上)
聊一聊常见的浏览器数据存储方案(上)
630 0
|
Java 数据安全/隐私保护
IoTDB服务安装教程-集群版
IoTDB服务安装教程-集群版
728 0
|
5月前
|
XML Linux 数据格式
Qt对Word网页的读写功能实现
Qt对Word网页的读写功能实现
325 9
|
2月前
|
人工智能 自然语言处理 供应链
架构未来:智能体来了(西南总部)如何通过 Multi-Agent 协作定义下一代企业生产力?
智能体来了(西南总部)提出基于Multi-Agent的协作架构,通过角色分工、动态协同与工程化编排,构建企业“数字兵团”。以共享内存、DAG任务流与原子化工具调用,实现营销、制造、知识服务等场景的生产力跃迁,推动运营者向系统架构师转型,定义AI时代新生产关系。(238字)
136 2
|
10月前
|
存储 关系型数据库 MySQL
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
|
3月前
|
人工智能 Java 程序员
SpringAI+DeepSeek大模型应用开发
本教程以SpringAI为核心,讲解Java与大模型(如DeepSeek)融合开发,助力传统应用智能化升级。适合Java程序员入门AI开发,推动企业低成本拥抱AI变革。
|
3月前
|
存储 SQL 人工智能
AI时代代码开发(数据库设计)
本文介绍基于三范式与DDD的数据库设计流程,结合AI工具辅助分析页面原型,通过部门、员工及工作经历模块,演示表结构设计与优化过程,强调人工校验与调整的重要性,最终完成符合业务需求的数据库建模与测试数据构建。
|
3月前
|
人工智能 自然语言处理 Cloud Native
AI时代代码开发(DeepSeek+Cursor+Devbox)
AI时代重塑软件开发,本课程聚焦DeepSeek+Cursor+Devbox+Sealos工具链,实现自然语言到代码的零基础全栈开发。覆盖需求分析、数据库设计、编码测试至云部署全流程,助力开发者高效构建并上线项目,抢占智能开发先机。(238字)
|
3月前
|
XML 自然语言处理 机器人
SpringAI
SpringAI整合全球主流大模型,支持多种技术架构,提供统一开发接口。本文以OpenAI和Ollama为例,详解如何通过SpringAI快速构建对话机器人,涵盖项目搭建、依赖引入与配置,助力开发者高效上手大模型应用开发。