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栈与队列

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 太厉害了,终于有人能把TCP/IP 协议讲的明明白白了「建议收藏」

    一图看完本文一、计算机网络体系结构分层计算机网络体系结构分层计算机网络体系结构分层不难看出,TCP/IP与OSI在分层模块上稍有区别。OSI参考模型注重“通信协议必要的功能是什么”,而TCP/IP则更强调“在计算机上实现协议应该开发哪种程序”。二、TCP/IP基础1.TCP/IP的具体含义从字面意义上讲,有人可能会认为…

    2022年4月12日
    44
  • python进阶(5)异常模块

    python进阶(5)异常模块异常模块下面介绍python常用的异常模块AttributeError异常AttributeError试图访问一个类中不存在的成员(包括:成员变量、属性和成员方法)而引发的异常Attribut

    2022年7月31日
    5
  • 华为转移到ios传输中断_社保不转移 重新开户

    华为转移到ios传输中断_社保不转移 重新开户iPhone备份麻烦,大家都知道!到底有多麻烦呢?以小编的经验,大概是折腾一晚上都不一定能顺利完成吧。。。iPhone自带的备份工具iCloud,在有WiFi的情况下可以自动备份,但其不大的免费空间对于大家来说显然不够,需要花高价扩容。另外,如果备份的数据比较多,就会拉慢备份速度,严重影响手机的正常使用。而且,iCloud不够稳定,所以使用过程中很有可能造成数据的丢失!简直不能再糟糕!有…

    2022年9月17日
    2
  • 查看win11激活状态[通俗易懂]

    查看win11激活状态[通俗易懂](一)命令行查看:slmgr.vbs-dlv如上图所示,windows11已激活。(二)右键计算机属性查看(1)单击系统:(2)单击激活:可以看到已经处于激活状态。

    2022年5月7日
    64
  • hdu 4861 Couple doubi(数论)

    hdu 4861 Couple doubi(数论)

    2021年12月7日
    40
  • 浅谈 js 字符串 search 方法

    浅谈 js 字符串 search 方法这是一个很久以前的事情了,好像是安心兄弟在学习js的时候做的练习。具体记不清了,今天就来简单分析下search究竟是什么用的。从字面意思理解,一个是搜索字符串吧。varstr="1

    2022年7月2日
    24

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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