【Queue】- 从源码分析ArrayDeque及其常用方法

news2024/11/20 4:37:25

文章目录

  • 概述
  • ArrayDeque基础知识
    • ArrayDeque内部结构
    • ArrayDeque的构造方法
    • ArrayDeque的扩容操作
  • ArrayDeque常用方法
    • 将ArrayDeque作为双端队列使用时
      • public void addFirst(E e)
      • public void addLast(E e)
      • public boolean offerFirst(E e)
      • public boolean offerLast(E e)
      • public E pollFirst()
      • public E pollLast()
      • public E removeFirst()
      • public E removeLast()
      • public E getFirst()
      • public E getLast()
      • public E peekFirst()
      • public E peekLast()
    • 将ArrayDeque作为队列使用时
      • public boolean add(E e)
      • public boolean offer(E e)
      • public E remove()
      • public E poll()
      • public E element()
      • public E peek()
    • 将ArrayDeque作为栈使用时
      • public void push(E e)
      • public E pop()
    • 其他方法
      • public int size()
      • public boolean isEmpty()
      • public boolean contains(Object o)
      • public void clear()
      • public Object[] toArray()
      • public ArrayDeque<E> clone()

概述

java.util.ArrayDeque是Queue和Deque接口的基础集合。它的继承实现关系如下:
在这里插入图片描述

public class ArrayDeque<E> extends AbstractCollection<E>
        implements Deque<E>, Cloneable, Serializable

ArrayDeque继承至AbstractCollection并实现了Deque, Cloneable, Serializable接口,支持可复制以及序列化操作。

ArrayDeque集合是一个基于可循环双指针数组(可扩容)结构实现的双端队列,它既有队列、双端队列的特点,又有栈结构的特点,可用来代替Stack集合进行栈结构的操作。

ArrayDeque基础知识

ArrayDeque内部结构

ArrayDeque的内部结构主要是一个数组,该数组结构是一种可循环使用的数组结构,称为循环数组

循环数组是一个固定大小的数组,并定义了一个动态的有效数据范围(有限范围小于数组固定长度),只有在有效范围内的数据对象才能被读写,且该有效范围不受数组的头尾限制。

实现中,循环数组定义为elements,并使用名为head、tail的两个属性表示动态的有效数据:
在这里插入图片描述

  • head属性用于标识下一次进行移除操作的数据对象索引位(队列头部索引为);
  • tail属性用于标识下一次进行添加操作的数据对象索引位(队列尾部索引为)。

当tail属性指向数组的所有一个索引位并进行下一次添加操作时,数组不一定进行扩容操作,而是:tail属性重新从当前数组的0号索引位开始,循环利用有限数据范围外的数组索引位存储新的数据对象。

ArrayDeque的构造方法

1. 构造一个空的ArrayDeque,初始容量为16。

    public ArrayDeque() {
        elements = new Object[16];
    }

2. 构造一个空的ArrayDeque,初始容量为指定大小numElements。

public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }

    private void allocateElements(int numElements) {
        elements = new Object[calculateSize(numElements)];
    }

3. 构造一个包含指定集合元素的ArrayDeque

    public ArrayDeque(Collection<? extends E> c) {
        allocateElements(c.size());
        addAll(c);
    }
    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

ArrayDeque的扩容操作

ArrayDeque的扩容操作包括以下两步:

  1. 根据当前容量大小计算新的容量。
    当扩容前的容量较小时,按照扩容前容量值的1倍计算增量值;当扩容前的容量较大时(超过64),按照扩容前容量值的50%计算增量值。
  2. 按照计算得到的扩容增量值使用System.arraycopy方法进行扩容。
    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;
    }

ArrayDeque常用方法

将ArrayDeque作为双端队列使用时

public void addFirst(E e)

在此deque头部插入指定的元素。

    public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e;
        if (head == tail)
            doubleCapacity();
    }

public void addLast(E e)

在此deque尾部插入指定的元素。

    public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ((tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();
    }

public boolean offerFirst(E e)

在此deque头部插入指定的元素。

    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }

public boolean offerLast(E e)

在此deque尾部插入指定的元素。

    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

public E pollFirst()

检索并删除此deque的第一个元素,如果此deque为空,则返回 null 。

    public E pollFirst() {
        int h = head;
        @SuppressWarnings("unchecked")
        E result = (E) elements[h];
        // Element is null if deque empty
        if (result == null)
            return null;
        elements[h] = null;     // Must null out slot
        head = (h + 1) & (elements.length - 1);
        return result;
    }

public E pollLast()

检索并删除此deque的最后一个元素,如果此deque为空,则返回 null 。

    public E pollLast() {
        int t = (tail - 1) & (elements.length - 1);
        @SuppressWarnings("unchecked")
        E result = (E) elements[t];
        if (result == null)
            return null;
        elements[t] = null;
        tail = t;
        return result;
    }

public E removeFirst()

检索并删除此deque的第一个元素。 此方法与pollFirst不同之处在于,如果此deque为空,它将抛出异常。

    public E removeFirst() {
        E x = pollFirst();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

public E removeLast()

检索并删除此deque的最后一个元素。 此方法与pollLast不同之处在于,如果此deque为空,它将抛出异常。

    public E removeLast() {
        E x = pollLast();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

public E getFirst()

检索但不删除此deque的第一个元素,如果此deque为空,则抛出异常。

    public E getFirst() {
        @SuppressWarnings("unchecked")
        E result = (E) elements[head];
        if (result == null)
            throw new NoSuchElementException();
        return result;
    }

public E getLast()

检索但不删除此deque的最后一个元素,如果此deque为空,则抛出异常。

    public E getLast() {
        @SuppressWarnings("unchecked")
        E result = (E) elements[(tail - 1) & (elements.length - 1)];
        if (result == null)
            throw new NoSuchElementException();
        return result;
    }

public E peekFirst()

检索但不删除此deque的第一个元素,如果此deque为空,则返回 null 。

    public E peekFirst() {
        // elements[head] is null if deque empty
        return (E) elements[head];
    }

public E peekLast()

检索但不删除此deque的最后一个元素,如果此deque为空,则返回 null 。

    public E peekLast() {
        return (E) elements[(tail - 1) & (elements.length - 1)];
    }

将ArrayDeque作为队列使用时

public boolean add(E e)

在此deque的末尾插入指定的元素。

    public boolean add(E e) {
        addLast(e);
        return true;
    }

public boolean offer(E e)

在此deque的末尾插入指定的元素。

    public boolean offer(E e) {
        return offerLast(e);
    }

public E remove()

检索并删除由此deque的头部元素。 如果此deque为空,它将抛出异常。

    public E remove() {
        return removeFirst();
    }

public E poll()

检索并删除由此deque的头部元素。 如果此deque为空,返回null。

    public E poll() {
        return pollFirst();
    }

public E element()

检索但不删除由此deque的头部元素。 如果此deque为空,它将抛出异常。

    public E element() {
        return getFirst();
    }

public E peek()

检索但不删除由此deque的头部元素。 如果此deque为空,返回null。

    public E peek() {
        return peekFirst();
    }

将ArrayDeque作为栈使用时

public void push(E e)

入栈

    public void push(E e) {
        addFirst(e);
    }

public E pop()

出栈

    public E pop() {
        return removeFirst();
    }

其他方法

public int size()

返回此deque中的元素数。

    public int size() {
        return (tail - head) & (elements.length - 1);
    }

public boolean isEmpty()

判断此deque是否为空。

    public boolean isEmpty() {
        return head == tail;
    }

public boolean contains(Object o)

如果此deque包含指定的元素,则返回true 。

    public boolean contains(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))
                return true;
            i = (i + 1) & mask;
        }
        return false;
    }

public void clear()

清空

    public void clear() {
        int h = head;
        int t = tail;
        if (h != t) { // clear all cells
            head = tail = 0;
            int i = h;
            int mask = elements.length - 1;
            do {
                elements[i] = null;
                i = (i + 1) & mask;
            } while (i != t);
        }
    }

public Object[] toArray()

返回一个包含此deque中所有元素的数组(从第一个到最后一个元素)。

    public Object[] toArray() {
        return copyElements(new Object[size()]);
    }

public ArrayDeque clone()

返回此deque的副本。

    public ArrayDeque<E> clone() {
        try {
            @SuppressWarnings("unchecked")
            ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
            result.elements = Arrays.copyOf(elements, elements.length);
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态SLAM论文归纳

持续更新&#xff0c;持续更新 2022 Multi-modal Semantic SLAM for Complex Dynamic Environments 作者&#xff1a;Han Wang, Jing Ying Ko and Lihua Xie, Fellowcode&#xff1a;https://github.com/wh200720041/MMS_SLAM视频&#xff1a;https://www.youtube.com/watch…

web自动化测试——入门篇01

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

并发编程中的原子性,可见性,有序性问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章是关于并发编程中出现的原子性&#xff0c;可见性&#xff0c;有序性问题。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&am…

PyTorch(三)TensorBoard 与 Transforms

文章目录Log一、TensorBoard1. TensorBoard 的安装2. SummaryWriter 的使用① add_scalar() 的使用a. 参数说明b. 函数使用c. 使用 Tensorboard② add_image() 的使用a. 参数说明b. 使用 numpy.array() 对 PIL 图片进行转换c. 使用函数d. 改变 global_step二、Transforms1. Tra…

数据结构 | 时间复杂度与空间复杂度

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;数据结构 | C语言 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;文章目录&#x1f333;前言&#x1f333;正…

【C++初阶】类和对象(二)

大家好我是沐曦希&#x1f495; 类和对象1.类的6个默认成员函数2.构造函数2.1 概念2.2 特性3.析构函数3.1 概念3.2 特性4.拷贝构造函数4.1 概念4.2 特征1.类的6个默认成员函数 空类&#xff1a;类中一个成员都没有 可是空类真的什么都没有吗&#xff1f; 并不是&#xff0c;任…

STM32关于UART的接收方式

STM32的 UART 一般分为定长接收和不定长接收 定长接收&#xff1a; HAL_UART_Receive():只能接收固定长度的数据&#xff0c;如果超过固定长度的数据只能接收对应长度&#xff0c;如果小于固定长度则不会接收 HAL_UART_Receive_IT():中断方式接收&#xff0c;每接收一个字节…

CSS 2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】

CSS 文章目录CSS2 CSS 选择器 - 52.8 伪选择器2.8.1 伪类选择器【根据特定状态选取元素】2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】 【什么是伪类】 伪类用于定义元素的特殊状态。 例如&#xff0c;它可以用于&#xff1a; 设置鼠标悬停在…

如何删除ZIP压缩包的密码?

ZIP是比较常用的压缩文件格式&#xff0c;有时候因为工作需要很多人还会给压缩包设置打开密码。那如果后续不需要密码保护了要如何删除密码呢&#xff1f;密码忘记了还能删除吗&#xff1f; 首先来说说第一种情况&#xff0c;也就是知道密码但后续不需要密码保护&#xff0c;只…

1. 初识Python

1. Pythond 简介 Python 语言由荷兰的 Guido Van Rossum (吉多范罗苏姆, 江湖人称龟叔) 在1989年圣诞节期间为了打发圣诞节的无趣而开发的一个脚本解释语言.Python 源代码遵循 GPL(GNU General Public License)开源协议, 也就是说你可以免费使用和传播它, 而不用担心版权的问…

libusb系列-005-部分API简介

libusb系列-005-部分API简介 文章目录libusb系列-005-部分API简介摘要libusb_initlibusb_open_device_with_vid_pidlibusb_kernel_driver_activelibusb_detach_kernel_driverlibusb_claim_interfacelibusb_release_interfacelibusb_attach_kernel_driverlibusb_closelibusb_exi…

【论文翻译】分布式并发控制中时间戳排序算法与本地计数器同步的改进方法

An Advanced Approach of Local Counter Synchronization to Timestamp Ordering Algorithm in Distributed Concurrency Control DOI目录1 介绍2 时间戳排序算法3 本地计数器同步的一种高级方法3.1 改进更新本地计数器的广播消息方式3.2 减少广播消息中的数据传输费用4 结论参…

时间复杂度与空间复杂度

文章目录1.什么是数据结构2.什么是算法3.如何学好数据结构呢3.1写代码3.2 多去动手画图4.算法效率4.1如何评判一个算法的好与坏呢4.2算法的复杂度5.时间复杂度5.1 概念5.2大O渐进法6常见的时间复杂度6.1常数阶6.2线性阶6.3 对数阶6.4平方阶6.5函数调用6.5.1普通调用6.5.2递归调…

1024程序节|Android框架之一 BRVAH【BaseRecyclerViewAdapterHelper】使用demo

文章目录&#x1f353;&#x1f353;BRVAH 上部&#x1f344;&#x1f353;动态图结果展示&#x1f344;&#x1f344;myAdapter.java【第一个布局适配器】&#x1f344;&#x1f344;youAdapter.java【第二个布局适配器】&#x1f344;&#x1f344;MainActivity.java【主活动…

【Android】自制静音App,解决他人手机外放问题

契源 看到一个粉丝留言&#xff0c;吐槽舍友深夜手机外放&#xff0c;打扰别人休息&#xff0c;想设计一款软件阻止舍友行径。于是我就来简单设计一下。 需求实现分析 实际上&#xff0c;我之前有篇博文提到过一个类似的Android APP&#xff0c;主要功能是将手机声音强制开到…

内存函数 memcpy、memmove 的简单模拟实现

一、memcpy 函数 数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。注意是以字节为单位进行拷贝。函数声明如下&#xff1a; 1、参数返回值解析 第二个参数 src&#xff1a;源地址&#xff0c;即你要从哪开始拷贝。 第三个参数 count&#xff1a…

Qt 物联网系统界面开发 “ 2022湖南省大学生物联网应用创新设计竞赛技能赛 ——应用物联网的共享电动自行车 ”

文章目录前言一、实现效果二、程序设计1. 界面背景图设计2. 信号槽设计3. 定时器设计4. 动态曲/折线图的设计5. 摄像头扫码6. 注册设计7. 登录设计8. 巡检人员设计三、综合分析前言 本篇源于 “ 2022 湖南省大学生物联网应用创新设计竞赛技能赛参考样题 ” ——应用物联网的共享…

【git】git ssh 公钥私钥 在 windows和mac 双系统分别如何生成 以及对接各个平台说明

win和mac 双系统分别如何生成 git ssh 一、windows 生成 ssh 公钥私钥 windows版本需要下载git bash&#xff1a;https://gitforwindows.org/ 在 git bash 中输入如下指令&#xff1a; # 创建全局名称&#xff08;将会在你的git提交作者中显示&#xff09;git config --glo…

【allegro 17.4软件操作保姆级教程三】布局操作基础二

4精准定位与坐标定位 在设计中经常会有一些器件或结构孔要摆放在指定位置&#xff0c;如果用move命令用鼠标去移则很难定位完全&#xff0c;这时候就需要精准定位。 操作步骤为&#xff1a; 1、点击move命令&#xff0c;在option面板选择器件原点&#xff0c;这时器件就会悬停在…

策略分析中缺失值的处理方法

在日常的策略分析中&#xff0c;经常会碰到分析的变量出现缺失值的情况&#xff0c;如果对这些缺失值视而不见&#xff0c;则会对策略分析的结果造成一定的影响。那么我们如何处理缺失值呢&#xff1f;关注“金科应用研院”&#xff0c;回复“CSDN”领取“风控资料合集” 首先…