简介

dequeue指的是双向队列,可以分别从队列的头部插入和获取数据,也可以从队列的尾部插入和获取数据。

本文将会介绍一下怎么创建dequeue和dequeue的一些基本操作。

双向队列的实现

和普通队列项目,双向队列可以分别在头部和尾部进行插入和删除工作,所以一个dequeue需要实现这4个方法:

  • insertFront(): 从dequeue头部插入数据
  • insertLast(): 从dequeue尾部插入数据
  • deleteFront(): 从dequeue头部删除数据
  • deleteLast(): 从dequeue尾部删除数据

同样的我们也需要一个head和一个rear来指向队列的头部和尾部节点。

也就是说实现了这四个方法的队列就是双向队列。我们不管它内部是怎么实现的。

接下来我们来直观的感受一下dequeue的插入和删除操作:

  1. 在头部插入

  1. 在尾部插入

  1. 在头部删除

  1. 在尾部删除

双向队列也可以有很多种实现方式,比如循环数组和链表。

双向队列的数组实现

因为数组本身已经有前后关系,也就是说知道head可以拿到它后面一个数据,知道rear也可以拿到它前面一个数据。

所以数组的实现中,存储head和rear的index值已经够了。

我们只需要添加向头部插入数据和向尾部删除数据的方法即可:


//从头部入队列
public void insertFront(int data){
if(isFull()){
System.out.println("Queue is full");
}else{
//从头部插入ArrayDeque
head = (head + capacity - 1) % capacity;
array[head]= data;
//如果插入之前队列为空,将real指向head
if(rear == -1 ){
rear = head;
}
}
} //从尾部取数据
public int deleteLast(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data= array[rear];
//如果只有一个元素,则重置head和real
if(head == rear){
head= -1;
rear = -1;
}else{
rear = (rear + capacity - 1)%capacity;
}
return data;
}
}

双向队列的动态数组实现

动态数组可以动态改变数组大小,这里我们使用倍增的方式来扩展数组。

看下扩展方法怎么实现:

    //因为是循环数组,这里不能做简单的数组拷贝
private void extendQueue(){
int newCapacity= capacity*2;
int[] newArray= new int[newCapacity];
//先全部拷贝
System.arraycopy(array,0,newArray,0,array.length);
//如果rear<head,表示已经进行循环了,需要将0-head之间的数据置空,并将数据拷贝到新数组的相应位置
if(rear < head){
for(int i=0; i< head; i++){
//重置0-head的数据
newArray[i]= -1;
//拷贝到新的位置
newArray[i+capacity]=array[i];
}
//重置rear的位置
rear = rear +capacity;
//重置capacity和array
capacity=newCapacity;
array=newArray;
}
}

因为是循环数组,这里不能做简单的数组拷贝,我们需要判断rear和head的位置来判断是否进入到了循环结构。

如果进入到了循环结构,我们需要重置相应的字段数据,并拷贝到新数组中。

向头部插入数据和向尾部删除数据的方法和基本队列的实现是一致的,这里就不列出来了。

双向队列的链表实现

如果使用链表来实现双向队列会有什么问题呢?

在头部插入和在尾部插入都可以快速定位到目标节点。但是我们考虑一下尾部删除的问题。

尾部删除我们需要找到尾部节点的前一个节点,将这个节点置位rear节点。这就需要我们能够通过rear节点找到它的前一个节点。

所以基本的链表已经满足不了我们的需求了。 这里我们需要使用双向链表。

public class LinkedListDeQueue {
//head节点
private Node headNode;
//rear节点
private Node rearNode; class Node {
int data;
Node next;
Node prev;
//Node的构造函数
Node(int d) {
data = d;
}
} public boolean isEmpty(){
return headNode==null;
} //从队尾插入
public void insertLast(int data){
Node newNode= new Node(data);
//将rearNode的next指向新插入的节点
if(rearNode !=null){
rearNode.next=newNode;
newNode.prev=rearNode;
}
rearNode=newNode;
if(headNode == null){
headNode=newNode;
}
} //从队首插入
public void insertFront(int data){
if(headNode == null){
headNode= new Node(data);
}else{
Node newNode= new Node(data);
newNode.next= headNode;
headNode.prev= newNode;
headNode= newNode;
}
} //从队首删除
public int deleteFront(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data=headNode.data;
headNode=headNode.next;
headNode.prev=null;
}
return data;
} //从队尾删除
public int deleteLast(){
int data;
if(isEmpty()){
System.out.println("Queue is empty");
return -1;
}else{
data=rearNode.data;
rearNode=rearNode.prev;
rearNode.next=null;
}
return data;
} }

双向链表中的每一个节点都有next和prev两个指针。通过这两个指针,我们可以快速定位到他们的后一个节点和前一个节点。

双向链表的时间复杂度

上面的3种实现的enQueue和deQueue方法,基本上都可以立马定位到要入队列或者出队列的位置,所以他们的时间复杂度是O(1)。

本文的代码地址:

learn-algorithm

本文已收录于 http://www.flydean.com/13-algorithm-dequeue/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

看动画学算法之:双向队列dequeue的更多相关文章

  1. 看动画学算法之:队列queue

    目录 简介 队列的实现 队列的数组实现 队列的动态数组实现 队列的链表实现 队列的时间复杂度 简介 队列Queue是一个非常常见的数据结构,所谓队列就是先进先出的序列结构. 想象一下我们日常的排队买票 ...

  2. 看动画学算法之:排序-count排序

    目录 简介 count排序的例子 count排序的java实现 count排序的第二种方法 count排序的时间复杂度 简介 今天我们介绍一种不需要作比较就能排序的算法:count排序. count排 ...

  3. 看动画学算法之:linkedList

    目录 简介 linkedList的构建 linkedList的操作 头部插入 尾部插入 中间插入 删除节点 简介 linkedList应该是一种非常非常简单的数据结构了.节点一个一个的连接起来,就成了 ...

  4. 看动画学算法之:栈stack

    目录 简介 栈的构成 栈的实现 使用数组来实现栈 使用动态数组来实现栈 使用链表来实现 简介 栈应该是一种非常简单并且非常有用的数据结构了.栈的特点就是先进后出FILO或者后进先出LIFO. 实际上很 ...

  5. 看动画学算法之:平衡二叉搜索树AVL Tree

    目录 简介 AVL的特性 AVL的构建 AVL的搜索 AVL的插入 AVL的删除 简介 平衡二叉搜索树是一种特殊的二叉搜索树.为什么会有平衡二叉搜索树呢? 考虑一下二叉搜索树的特殊情况,如果一个二叉搜 ...

  6. 看动画学算法之:hashtable

    目录 简介 散列表的关键概念 数组和散列表 数组的问题 hash的问题 线性探测 二次探测 双倍散列 分离链接 rehash 简介 java中和hash相关并且常用的有两个类hashTable和has ...

  7. 看动画学算法之:二叉搜索树BST

    目录 简介 BST的基本性质 BST的构建 BST的搜索 BST的插入 BST的删除 简介 树是类似于链表的数据结构,和链表的线性结构不同的是,树是具有层次结构的非线性的数据结构. 树是由很多个节点组 ...

  8. 看动画学算法之:doublyLinkedList

    目录 简介 doublyLinkedList的构建 doublyLinkedList的操作 头部插入 尾部插入 插入给定的位置 删除指定位置的节点 简介 今天我们来学习一下复杂一点的LinkedLis ...

  9. STL之双向队列(dequeue)

    //双向队列 deque #include <deque> #include <cstdio> #include <algorithm> using namespa ...

随机推荐

  1. go build 与go install

    相同点都能生成可执行文件 不同点go build 不能生成包文件, go install 可以生成包文件go build 生成可执行文件在当前目录下, go install 生成可执行文件在bin目录 ...

  2. 聊一聊开闭原则(OCP).

    目录 简述 最早提出(梅耶开闭原则) 重新定义(多态开闭原则) 深入探讨 OCP的两个特点 对外扩展开放(Open for extension) 对内修改关闭 抽象 关闭修改.对外扩展? 简述 在面向 ...

  3. python win32com 处理excle 写一个公共的类

    利用win32com处理excle,这样可以不管文件是老的xls还是新的xlsx格式,非常方便. 类的源码如下: import win32com.client as win32 class easyE ...

  4. Linux没有/var/log/messages日志文件

    1.新安装的CentOS8没有/var/log/messages日志文件: 安装rsyslog: dnf  install   -y  rsyslog 或 yum  install  -y  rsys ...

  5. Mysql将其他表中的数据更新到指定表中

    update tb  set tb.字段= (select 字段 from tb1 where tb.字段1 = tb1.字段1); update role set uid = (select ID ...

  6. 低代码+RPA+AI,能否让ERP焕发下一春?

    从2004年开始,国内ERP项目的实施便在各大企业热火朝天地展开,2014年,国内大中型企业已经基本完成了ERP系统的普及.ERP已经在大中型企业中成为不可或缺的关键信息系统.企业核心业务的流转与管控 ...

  7. Python爬虫之PySpider框架

    概述 pyspider 是一个支持任务监控.项目管理.多种数据库,具有 WebUI 的爬虫框架,它采用 Python 语言编写,分布式架构.详细特性如下: 拥有 Web 脚本编辑界面,任务监控器,项目 ...

  8. [转载]linux环境变量设置方法总结(PATH/LD_LIBRARY_PATH)

    http://blog.chinaunix.net/uid-354915-id-3568853.html PATH:  可执行程序的查找路径查看当前环境变量:echo $PATH设置: 方法一:exp ...

  9. c++ 的学习 第二集函数的重载2 namemangling

    1. 本质 采用了name mangling或者叫name decoration ✓ C++编译器默认会对符号名(比如函数名)进行改编.修饰,有些地方翻译为"命名倾轧"✓ 重载时 ...

  10. Python3入门系列之-----json与字典转换

    json JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写 JSON 函数 使用 JSON 函数需要导入 json 库:import js ...