Java双向队列Deque栈与队列

Java双向队列Deque栈与队列Java中实际上提供了java.util.Stack来实现栈结构,但官方目前已不推荐使用,而是使用java.util.Deque双端队列来实现队列与栈的各种需求.如下图所示java.util.Deque的实现子类有java.util.LinkedList和java.util.ArrayDeque.顾名思义前者是基于链表,后者基于数据实现的双端队列.总体介绍要讲栈和队列,首先要讲Dequ…

大家好,又见面了,我是你们的朋友全栈君。

Java中实际上提供了java.util.Stack来实现栈结构,但官方目前已不推荐使用,而是使用java.util.Deque双端队列来实现队列与栈的各种需求.如下图所示java.util.Deque的实现子类有java.util.LinkedListjava.util.ArrayDeque.顾名思义前者是基于链表,后者基于数据实现的双端队列.

Java双向队列Deque栈与队列

总体介绍

要讲栈和队列,首先要讲Deque接口。Deque的含义是“double ended queue”,即双端队列,它既可以当作栈使用,也可以当作队列使用。下表列出了Deque与Queue相对应的接口:

Java双向队列Deque栈与队列

下表列出了Deque与Stack对应的接口:

Java双向队列Deque栈与队列

上面两个表共定义了Deque的12个接口。添加,删除,取值都有两套接口,它们功能相同,区别是对失败情况的处理不同。一套接口遇到失败就会抛出异常另一套遇到失败会返回特殊值(false或null)。除非某种实现对容量有限制,大多数情况下,添加操作是不会失败的。虽然Deque的接口有12个之多,但无非就是对容器的两端进行操作,或添加,或删除,或查看。明白了这一点讲解起来就会非常简单。

ArrayDeque

从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也就是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素

Java双向队列Deque栈与队列

上图中我们看到,head指向首端第一个有效元素tail指向尾端第一个可以插入元素的空位。因为是循环数组,所以head不一定总等于0,tail也不一定总是比head大。

addFirst()

针对首端插入实际需要考虑:1.空间是否够用,以及2.下标是否越界的问题。上图中,如果head为0之后接着调用addFirst(),虽然空余空间还够用,但head为-1,下标越界了。下列代码很好的解决了这两个问题。

  public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    //下标越界问题解决方案
    elements[head = (head - 1) & (elements.length - 1)] = e;
    //容量问题解决方案
    if (head == tail)
        doubleCapacity();
}

上述代码我们看到,空间问题是在插入之后解决的,因为tail总是指向下一个可插入的空位,也就意味着elements数组至少有一个空位,所以插入元素的时候不用考虑空间问题。

下标越界的处理解决起来非常简单,head = (head – 1) & (elements.length – 1)就可以了,这段代码相当于取余,同时解决了head为负值的情况。因为elements.length必需是2的指数倍(构造函数初始化逻辑保证),elements – 1就是二进制低位全1,跟head – 1相与之后就起到了取模的作用,如果head – 1为负数(其实只可能是-1),则相当于对其取相对于elements.length的补码。

下面再说说扩容函数doubleCapacity(),其逻辑是申请一个更大的数组(原数组的两倍),然后将原数组复制过去。过程如下图所示:

Java双向队列Deque栈与队列

 

图中我们看到,复制分两次进行,第一次复制head右边的元素,第二次复制head左边的元素。

private void doubleCapacity() {
    assert head == tail;
    int p = head;
    int n = elements.length;
    int r = n - p; // number of elements to the right of p
    int newCapacity = n << 1;
    if (newCapacity < 0)
        throw new IllegalStateException("Sorry, deque too big");
    Object[] a = new Object[newCapacity];
    System.arraycopy(elements, p, a, 0, r);
    System.arraycopy(elements, 0, a, r, p);
    elements = a;
    head = 0;
    tail = n;
}

addLast()

addLast(E e)的作用是在Deque的尾端插入元素,也就是在tail的位置插入元素,由于tail总是指向下一个可以插入的空位,因此只需要elements[tail] = e;即可。插入完成后再检查空间,如果空间已经用光,则调用doubleCapacity()进行扩容。与first比较类似就不多分析了.

Java双向队列Deque栈与队列

其他操作也是差不多的方式,唯一麻烦的head与tail位置转换也用取余巧妙的化解了.

LinkedList

LinkedList实现了Deque接口,因此其具备双端队列的特性,由于其是链表结构,因此不像ArrayDeque要考虑越界问题,容量问题,那么对应操作就很简单了,另外当需要使用栈和队列是官方推荐的是ArrayDeque,因此这里不做多的分析.

Java双向队列Deque栈与队列

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160486.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 2021年10月TIOBE排行 榜首 Python yyds[通俗易懂]

    2021年10月TIOBE排行 榜首 Python yyds[通俗易懂]2021年10月TIOBE排行榜首Pythonyydspython这次不负众望,登上了榜首,大势所趋罢了,意料之中的事情。简介Python(英国发音:/ˈpaɪθən/美国发音:/ˈpaɪθɑːn/),是一种面向对象的解释型计算机程序设计语言,由荷兰人GuidovanRossum于1989年发明,第一个公开发行版发行于1991年。Python是纯粹的自由软件,源代码和解释器CPython遵循GPL协议。2017年7月20日,IEEE发布2017年编程语言排行榜:Python高居首位。未

  • oracle数据库建表语句大全_sql server建表语句

    oracle数据库建表语句大全_sql server建表语句Oracle数据库建表语句#1.建表语句createtableCUST_INFO(CUST_IDVARCHAR(36)notnull,CUST_TYPEVARCHAR(50),CUST_NAMEVARCHAR(200),ID_NO…

  • 详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了

    详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了目录STN的作用1.1灵感来源1.2什么是STN?STN的基本架构Localisationnet是如何实现参数的选取的?3.1实现平移3.2实现缩放3.3实现旋转3.4实现剪切3.5小结Gridgenerator实现像素点坐标的对应关系4.1为什么会有坐标的问题?4.2仿射变换关系Sampler实现坐标求解的可微性5.1小数

    2022年10月19日
  • 通俗理解LDA主题模型

    通俗理解LDA主题模型0前言印象中,最开始听说“LDA”这个名词,是缘于rickjin在2013年3月写的一个LDA科普系列,叫LDA数学八卦,我当时一直想看来着,记得还打印过一次,但不知是因为这篇文档的前序铺垫太长(现在才意识到这些“铺垫”都是深刻理解LDA的基础,但如果没有人帮助初学者提纲挈领、把握主次、理清思路,则很容易陷入…

  • fedora14安装教程_Linux下zip安装使用方法

    fedora14安装教程_Linux下zip安装使用方法LinuxFedora12下,安装SAMBA ,使用以下命令:yuminstallsambayuminstallsamba

  • java怎么使用random函数,java中的random函数

    java怎么使用random函数,java中的random函数RandomAccessFile(“C:/MyFile1/Test.java”,”wr”)30、当使用FileInputStream类中的read()方法时,如果没有读入一个字节数据时,返回值为()DA、0……3.Coding:ImplementthesolutioninJava.4.Testing:Makesurethatthenumbersap…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号