源码 | Queue、Deque、ArrayDeque源码分析

本文深入探讨Java集合框架中ArrayDeque的实现原理,分析其作为队列时为何比LinkedList更高效,包括其基于数组的实现方式、头尾指针操作、扩容机制及与ArrayList的对比。

ArrayDeque,Collection框架中不起眼的一个类有删改

继承关系

8923455-6d815404deb0ef23.png

继承关系

 

类名中的 Array姓氏,它是基于数组实现的。

类注释中,有句话引起了我的注意:

/**
 * This class is likely to be faster than
 * {@link Stack} when used as a stack, and faster than {@link LinkedList}
 * when used as a queue.
 */

(Stack先不管)注释中后半句说,ArrayDeque作为队列时比LinkedList快,看看它是怎么办到的!

属性:

transient Object[] elements;    //基于数组实现
transient int head;    //头指针
transient int tail;    //尾巴指针

构造器

private static final int MIN_INITIAL_CAPACITY = 8; // 默认大小

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;
}
// The main insertion and extraction methods are addFirst,
// addLast, pollFirst, pollLast. The other methods are defined in
// terms of these.

方法

以上注释有云,核心方法就4个,我们从add方法入手。

插入

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

head = (head - 1) & (elements.length - 1),玄机就在这里。如果你对1.8的HashMap足够了解,就会知道hashmap的数组大小同样始终是2的次幂。其中很重要的一个原因就是:当lengh是2的次幂的时候,某数字 x 的操作 x & (length - 1) 等价于 x % length,而对二进制的计算机来说 & 操作要比 % 操作效率更好
而且head = (head - 1) & (elements.length - 1),(head初始值0)第一次就将head指针定位到数组末尾了。

画图分析下:

 

8923455-ff7361ac7c6ca16b.png

队列首添加元素

可见,head指针从后向前移动。

addLast

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

8923455-fa73cbf8438c0420.png

队列尾部添加元素

addLast和addFirst原理相同,只是addLast控制tail指针,从前向后移动!

上图中再做一次add操作,指针将会重合。比如,再一次addFirst之后:

 

8923455-96a786e3bed593a4.png

扩容操作

if (head == tail)
        doubleCapacity();    //扩容触发

扩容

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;    //左移,等价乘2,依然保持2的次幂
    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;
}

8923455-af13b2b1011657db.png

扩容实现

通过数组拷贝和重新调整指针,完成了扩容。

至于pollFirst、pollLast是addFirst、addLast的相反操作,原理相似,不多做分析。

作为队列时,ArrayDeque效率为什么会比LinkedList更好?

我认为:因为只操作首尾元素,不会像ArrayList那样插入或删除中间元素,不会设计到大量的复制移动操作,并且基于数组。所以效率更高。

【轴承故障诊断】基于融合鱼鹰和柯西变异的麻雀优化算法OCSSA-VMD-CNN-BILSTM轴承诊断研究【西储大学数据】(Matlab代码实现)内容概要:本文提出了一种基于融合鱼鹰和柯西变异的麻雀优化算法(OCSSA)优化变分模态分解(VMD)参数,并结合卷积神经网络(CNN)与双向长短期记忆网络(BiLSTM)的轴承故障诊断模型。该方法利用西储大学公开的轴承数据集进行验证,通过OCSSA算法优化VMD的分解层数K和惩罚因子α,有效提升信号分解精度,抑制模态混叠;随后利用CNN提取故障特征的空间信息,BiLSTM捕捉时间序列的动态特征,最终实现高精度的轴承故障分类。整个诊断流程充分结合了信号预处理、智能优化与深度学习的优势,显著提升了复杂工况下轴承故障诊断的准确性与鲁棒性。; 适合人群:具备一定信号处理、机器学习及MATLAB编程基础的研究生、科研人员及从事工业设备故障诊断的工程技术人员。; 使用场景及目标:①应用于旋转机械设备的智能运维与故障预警系统;②为轴承等关键部件的早期故障识别提供高精度诊断方案;③推动智能优化算法与深度学习在工业信号处理领域的融合研究。; 阅读建议:建议读者结合MATLAB代码实现,深入理解OCSSA优化机制、VMD参数选择策略以及CNN-BiLSTM网络结构的设计逻辑,通过复现实验掌握完整诊断流程,并可进一步尝试迁移至其他设备的故障诊断任务中进行验证与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值