队列总结(三)ArrayDeque

ArrayDeque详解 本文主要介绍了Java集合框架中ArrayDeque的相关知识,包括ArrayDeque简介、ArrayDeque使用、Deque接口、方法剖析、扩容机制等内容。 阅读详情

ArrayDeque

关于Deque接口的介绍,记录在了另一文章里https://blog.youkuaiyun.com/java_lifeng/article/details/120650857

ArrayDeque 是 Deque 接口的一种具体实现,是依赖于可变数组来实现的。ArrayDeque 没有容量限制,可根据需求自动进行扩容。ArrayDeque不支持值为 null 的元素。

ArrayDeque 不是线程安全的; 在没有外部同步的情况下,它们不支持多线程并发访问。 此类用作Stack时可能比Stack快,用作队列时比LinkedList快。大多数ArrayDeque操作在分摊的常数时间内运行。 例外情况包括remove 、 removeFirstOccurrence 、 removeLastOccurrence 、 contains 、 iterator.remove()和批量操作,所有这些都在线性时间内运行。

源码分析

ArrayDeque是基于数组的实现,但在ArrayDeque中,数组是作为环形来使用的。

这个代码在HashMap中也很熟悉,ArrayDeque默认数组长度为16,如果手动指定为numElements,则根据此参数得到大于等于此数值的2^n形式的值,即ArrayDeque的数组长度大小必须是2的次方数。

    private static int calculateSize(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        return initialCapacity;
    }

从尾部插入的元素(addLast)从下标0开始正序插入,用tail字段表示下一个将要从尾部插入的元素的下标。(tail - 1) & (elements.length - 1)表示队列尾部实际的元素坐标。
从头部插入的元素(addFirst)从下标length-1开始倒序插入,用head表示当前队列中头部元素的下标,从头部插入时,根据head计算要插入的下标,即head = (head - 1) & (elements.length - 1)

    // 队列中头元素的下标,注意,基于数组实现,但不是数组中的下标0
    transient int head;
    public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e;
        // 说明数组空间用尽,下一次插入会产生覆盖,需要扩容
        if (head == tail)
            doubleCapacity();
    }
    
    public E getFirst() {
        @SuppressWarnings("unchecked")
        E result = (E) elements[head];
        if (result == null)
            throw new NoSuchElementException();
        return result;
    }

head初始值为0, (head - 1) & (elements.length - 1),-1与上任何数得原数,即第一次调用addFirst之后,head = elements.length - 1。此后,根据与运算的特性,每次调用addFirst,head-1,直至head == tail,触发数组扩容后head重新置为0

	 // 下一个插入队尾的元素的下标,注意,是下一个
    transient int tail;
    public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();
    }
    
    public E getLast() {
        @SuppressWarnings("unchecked")
        // 因为tail代表的是下一个,所以实际意义上的最后一个是tail-1
        E result = (E) elements[(tail - 1) & (elements.length - 1)];
        if (result == null)
            throw new NoSuchElementException();
        return result;
    }

扩容操作,懒得分析了,个人感觉整体设计十分精妙

    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;
    }

Deque接口不提供支持下标操作的api,比如List接口中的get(i),remove(i),ArrayDeque同样也不支持。对于删除,提供了删除第一次出现和删除最后一次出现的操作。

    public boolean remove(Object o) {
        return removeFirstOccurrence(o);
    }
    
    public boolean removeFirstOccurrence(Object o) {
        if (o == null)
            return false;
        int mask = elements.length - 1;
        int i = head;
        Object x;
        while ( (x = elements[i]) != null) {
            if (o.equals(x)) {
                delete(i);
                return true;
            }
            i = (i + 1) & mask;
        }
        return false;
    }
    
    public boolean removeLastOccurrence(Object o) {
        if (o == null)
            return false;
        int mask = elements.length - 1;
        int i = (tail - 1) & mask;
        Object x;
        while ( (x = elements[i]) != null) {
            if (o.equals(x)) {
                delete(i);
                return true;
            }
            i = (i - 1) & mask;
        }
        return false;
    }

上面的逻辑很简单,主要看delete方法,有点绕,烦死了,没劲看了


 /**
  * 移除元素数组中指定位置的元素,并根据需要调整头部和尾部。
  * 这可能导致数组中元素的移动。
  */
  private boolean delete(int i) {
        checkInvariants();
        final Object[] elements = this.elements;
        final int mask = elements.length - 1;
        final int h = head;
        final int t = tail;
        final int front = (i - h) & mask;
        final int back  = (t - i) & mask;

        // Invariant: head <= i < tail mod circularity
        if (front >= ((t - h) & mask))
            throw new ConcurrentModificationException();

        // Optimize for least element motion
        if (front < back) {
            if (h <= i) {
                System.arraycopy(elements, h, elements, h + 1, front);
            } else { // Wrap around
                System.arraycopy(elements, 0, elements, 1, i);
                elements[0] = elements[mask];
                System.arraycopy(elements, h, elements, h + 1, mask - h);
            }
            elements[h] = null;
            head = (h + 1) & mask;
            return false;
        } else {
            if (i < t) { // Copy the null tail as well
                System.arraycopy(elements, i + 1, elements, i, back);
                tail = t - 1;
            } else { // Wrap around
                System.arraycopy(elements, i + 1, elements, i, mask - i);
                elements[mask] = elements[0];
                System.arraycopy(elements, 1, elements, 0, t);
                tail = (t - 1) & mask;
            }
            return true;
        }
    }
    
    private void checkInvariants() {
        assert elements[tail] == null;
        assert head == tail ? elements[head] == null :
            (elements[head] != null &&
             elements[(tail - 1) & (elements.length - 1)] != null);
        assert elements[(head - 1) & (elements.length - 1)] == null;
    }
ArrayDeque双端队列完全解析 ArrayDeque双端队列完全解析 重点: 底层通过循环数组实现 俩个重要属性 head tail 不能添加null值,不然会报空指针 每次扩容都是2的n次方 可以实现普通队列先进先出排序,也可以实现栈先进后出的排序 特别留意,它里面通过二进制方式判断数组是否已满 (tail = (tail + 1) &amp;amp;amp;amp;amp;amp;amp;amp;amp; (elements.length - 1)) == head 注意操作插入... 阅读详情

相关推荐

Java 集合框架:Java 中的双端队列 ArrayDeque 的实现

Deque 接口表示一个双端队列(Double Ended Queue),允许在队列的首尾两端操作,所以既能实现队列行为,也能实现栈行为。Deque 常用的两种实现 ArrayDeque 和 LinkedList。ArrayDeque 是 Java 集合中双端队列的数组实现,可以从两端进行插入或删除操作,当需要使用栈时,Java 已不推荐使用 Stack,而是推荐使用更高效的ArrayDeque,当需要使用队列时也可以使用 ArrayDeque。

栗筝i的博客 4194

java ArrayQueue数据队列的使用

package com.coship.mes.stbsdk.apis; /**  * 数组队列,该队列在创建时可以不指定队列最大容量,如果没有指定队列最大容量,则会采用默认的最大容量(500)  *  */ class ArrayQueue {  private static final int MAX_SIZE = 500;  private Object[] queue; //

mikesno1的专栏 1914

离散数学期末复习笔记【精华版】

文章目录前言一、????理逻辑1. 命题逻辑2. 等值演算3. 主合取范式、主析取范式4. 【题】推理证明5. 辖域、自由变元、约束变元二、????合1. 环和、环积,幂集,笛卡尔乘积三、 ????????关系1. 自反、对称、传递2&3. 合成运算,逆关系、闭包4. 哈斯图、上下界、偏序5. 等价关系、划分四、????1. 幺元(么元、单位元)、零元、逆元,半群、群、阿尔贝群、独异点、循环独异点2. 【题】由表判断3. 【题】证明五、????论1. 简单图、平凡图、多重图、子图、补图、出度、入度、

林大夕可的博客 17万+

java 集合-ArrayDeque

基本概念及实例ArrayDeque类实现Queue接口。对于数组实现的Deque来说,数据结构上比较简单,只需要一个存储数据的数组以及头尾两个索引即可。由于数组是固定长度的,所以很容易就得到数组的头和尾,那么对于数组的操作只需要移动头和尾的索引即可。 ArrayDeque并不是一个固定大小的队列 , 每次队列满了以后就将队列容量扩大一倍(doubleCapacity()),因此加入一个元素总是能成功

liuyufeihu的专栏 797

【VAX 小番茄安装详细步骤】

本文详细介绍了在VS2022环境下安装Visual Assist X(番茄助手)的步骤及常见问题解决方案。主要内容包括:安装前的兼容性设置(需修改为Windows7兼容模式)、安装流程(卸载旧版本、勾选对应VS版本、替换关键dll文件)以及常见问题处理(如安装失败、工具栏图标缺失等)。文章提供了完整的下载链接和操作截图,特别强调了安装失败后的清理方法(注册表、安装目录和残余文件删除)。最后给出了安装成功后的测试运行指引。

qq_23962581的博客 1718

手把手教你解锁TI MSPM0G3507开发板(2025新版,附XDS110接线图)

本文详细解析了2025版TI MSPM0G3507开发板的解锁方法,针对新版硬件中BSL引脚的电路设计变化提供了精准接线方案和UniFlash软件配置步骤。通过实测数据和专业指导,帮助开发者解决芯片锁定问题,确保调试接口正常响应。

weixin_42696271的博客 810

一文详解 ArrayDeque 双端队列使用及实现原理

deque(double-ended queue)双端队列,是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。

bjxiaxueliang的CODING小栈 1677

1553B通信项目开发笔记(一)协议概述

最近接了个项目,需要用1553B协议通信,仅作为RT端口进行通信,控制器采用ARM 使用芯片为国产的BU61580芯片,功能和引脚和DDC的61580完全一致。

u010396127的博客 2万+

ArrayDeque类常用方法

ArrayDeque类常用方法(用作:栈和队列)

twi_twi的博客 807

QGIS-空间分析-核密度分析

本文在QGIS软件中使用核密度估计法分析全球历年的地震数据,旨在分析出地震频发且严重的区域,为地震防控提供参考依据。全球历年地震数据来源于网络,仅用于技术学习探索。通过核密度分析,可以观察到南美、美国西部海岸线和太平洋北部区域在全球地震分布状态中是最为集中和强烈的。

imxiezy的博客 2467

黑猫带你学UFS协议第8篇:UFS电气特性详解(Power、CLK、Reset等)

UFS强制支持secure mode。UFS设备可能会存储个人或者公司的信息,UFS提供把数据永久从设备上移除的功能,并且保证对存储介质进行逆向恢复数据也恢复不回来原有数据。安全模式是以逻辑单元为单位进行应用的,不同的逻辑单元可以有不同的安全模式。由于UFS设备的存储介质不同,所以把数据安全从存储介质上移除方式会有不同,spec提供了三种通用的移除方法,UFS设备至少支持其中一种。● 对存储的位置进行一次擦除操作。● 对存储的位置使用单一字符(比如0xAA)覆盖写,然后进行擦除。.........

黑猫奥利奥的博客 4077

Java中ArrayDeque的实现

ArrayDeque采用循环数组的形式实现。 ArrayDeque提供了三个构造函数。 1. 无参构造器:申请大小为16的数组 2. 提供需要空间大小的有参构造器:利用allocateElements申请空间 3. 利用现有集合的有参构造器:同样利用allocateElements申请空间,再将现有集合中的元素拷贝到数组中 allocateElements(int numEl...

ddou_pan的博客 676

2025华为od机试真题B卷【停车场费用统计】Python实现

2025华为od机试真题B卷【停车场费用统计】Python实现

MISAYAONE的博客 539

Java 队列全面详解:从入门到面试实战

队列(Queue)是一种操作受限的线性数据结构,遵循先进先出(FIFO, First In First Out)原则。它只允许在一端(队尾)进行插入操作,在另一端(队头)进行删除操作。队列就像日常生活中的排队,先进入队列的元素会先被处理。本文从 Java 队列的接口体系出发,详细介绍了普通队列、优先队列、双端队列以及阻塞队列的实现原理和使用场景。队列的 FIFO 特性及其典型应用。Queue、Deque、BlockingQueue 三大接口及其核心方法。

2501_91525818的博客 317

代谢组数据分析(十九):随机森林构建代谢组预后模型

建立胃癌(GC)预后模型时,从队列3中的181名患者中,使用右删失结果数据进行了随机分层抽样,分为训练数据集(n = 121)和测试数据集(n = 60)。训练了一个包含1000棵树的随机生存森林(RSF)模型,根据它们基于排列的特征重要性来选择突出的特征。通过再次训练随机生存模型,并选取28种代谢物,建立了显示出色预测能力(AUROC = 0.832,95% CI:0.697-0.951)的最佳模型,用于预测测试数据集中GC患者的生存结果。

专注生信领域 1713

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【Java从入门到精通】第15篇:数组与集合框架的选择地图——List、Set、Queue各自的战场

数组是Java最基础的数据容器,但固定容量与单一操作语义使其在复杂场景中捉襟见肘。Java集合框架以统一的接口体系将数据结构与算法分离,为数据管理提供了完整的工具箱。本文构建数组与集合的选择地图,系统拆解List、Set、Queue三大接口的语义边界,深入ArrayList基于动态数组的随机访问优势与LinkedList基于双向链表的插入删除优势,并剖析两者在头部插入、中间删除等特定场景下的性能拐点——理解底层数据结构如何影响集合的操作复杂度。

2301_80672009的博客 183

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java Collection 完整知识体系(面试完整版)

文章摘要: 本文系统梳理Java集合框架,分为单列集合(Collection)和双列集合(Map)两大体系。Collection包含List(有序可重复)、Set(唯一无序)、Queue(FIFO队列)三大子接口,核心实现类如ArrayList(动态数组)、LinkedList(双向链表)、HashSet(哈希去重)、PriorityQueue(优先级队列)等,详解其底层结构、时间复杂度及适用场景。Map体系未展开,但强调与Collection的独立性。 核心要点: List:ArrayList查询快但中间

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 415

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java数据结构之双端队列ArrayDeque

java 自带双端队列ArrayDeque的源码解析

冰血ANG的博客 3500

Java双端队列ArrayDeque

双端队列ArrayDeque是Java集合框架中的一种数据结构,它实现了Deque接口,因此支持在两端进行添加和移除元素。通过名称也能看出,ArrayDeque是基于数组实现的,ArrayDeque内部使用一个可动态调整大小的环形数组来存储元素。当ArrayDeque中的元素数量超过当前数组容量时,会自动进行扩容,以确保有足够的空间存放新元素,但Java没有实现自动缩容。

qq_38875964的博客 820

ArrayDeque双端队列--底层原理可视化

ArrayDeque是基于循环数组的双端队列实现,既可用作队列(FIFO)也可用作栈(LIFO)。通过两个索引headtail和位运算自动在固定大小(2 的幂)的底层数组中“回绕”操作,当空间用尽时再将数组容量翻倍并平铺原有元素,所有入、删、取操作均为摊销 O(1),不支持存放null且非线程安全,但因无额外节点指针、缓存友好,通常比链表结构性能更优。通过这篇文章,从栈功能使用到底层原理基本掌握,对ArrayDeque队列操作功能感兴趣的可以自行学习,底层和栈功能是共用的,相信你很快便可掌握双端队列。

qq_35485206的博客 981

Java集合(四三): ArrayDeque

ArrayDeque是 Deque接口的一个实现,使用了可变数组,所以没有容量上的限制。同时, ArrayDeque是线程不安全的,在没有外部同步的情况下,不能再多线程环境下使用。 ArrayDeque是 Deque的实现类,可以作为栈来使用,效率高于 Stack; 也可以作为队列来使用,效率高于 LinkedList。 需要注意的是, ArrayDeque不支持 null值。 一、常用方法 1.添加元素 addFirst(E e)在数组前面添加元素 addLa...

mingyuli的博客 1万+

双端队列ArrayDeque、LinkedList

双端队列ArrayDeque、LinkedList 一、前言 Stack栈:先进后出 Queue队列:先进先出 在Java里有一个Stack类,但是这个类已经不推荐使用了,而Queue是一个接口,当我们需要使用栈和队列时,推荐使用更加高效的ArrayDeque该类实现Deque接口,次选使用LinkedList。 二、总体介绍 要讲栈和队列,首先要讲Deque接口。Deque的含义是"double ended queue",即双端队列,既可以当栈使用,也可以当队列使用。 下表列出Deque和Queue相对应

qq_34222160的博客 1013

Java 栈(Stack)和队列(Queue)的首选 - ArrayDeque

阅读 Java 版本为 1.8.0.25。 栈(Stack) 和 队列(Queue) 应该是大家非常熟悉的数据结构了。 Java 中有 栈(Stack) 的具体类, 队列(Queue) 只定义了接口,当然所有实现了这个接口的类都可以当作一个队列使用。

路的尽头在哪 5642

java双队列_Java双端队列-ArrayDeque的使用

1、概览本篇,我们将介绍ArrayDeque的使用方法-ArrayDeque是Deque的一个实现。ArrayDeque俗称数组双端队列,是一种允许我们从俩端进行存取操作的可扩容数组。ArrayDeque既可以作为Stack使用(Last-In-First-Out) 又可以作为Queue使用(First-In-First-Out)。2、API针对于每个操作,我们基本上都有俩个可选择的API,第一组...

weixin_36331764的博客 1799

Java集合 - ArrayDeque

Java集合 - ArrayDeque

qq_43350524的博客 1125
上一篇: 队列总结(二)PriorityQueue
下一篇: 队列总结(四)ArrayBlockingQueue
MrMoving
博客等级 码龄10年 54粉丝 145原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值