ArrayDeque——循环数组之找下一个元素的正确位置

本文深入探讨了ArrayDeque数据结构的内部实现,包括其使用的循环数组、头尾指针及容量扩展策略。详细介绍了如何通过与操作高效地找到下一个元素的正确位置,以及在不同情况下数组长度的计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayDeque——循环数组之找下一个元素的正确位置

内部的实例变量:

private transient E[] elements; // 用于存储元素的数组
privata transient int head; // 头
privata transient int tail; // 尾

如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。

构造方法(其一)

public ArrayDeque(Collection<? extends E> c){

	allocateElements(c.size); // 该方法用于计算该分配的数组的长度

	addAll(c);


allocateElements(int numElements)

该方法计算逻辑:

  1. 如果numElements小于8,就是8

  2. 如果numElements大于等于8,分配的实际长度是严格大于numElements并且为2的整数次幂的最小数。比如:numElements为10,则实际分配16,如果numElements为32则为64。

    是2的幂次数,是为了更有效率的获取数组中下一个元素的正确位置。严格大于numElements,是因为循环数组必须时刻至少留一个空位,tail指向下一个空位,为了容纳numElements个元素,至少需要numElements+1个位置

addAll(E e)

addAll只是循环调用了add方法;

add:

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

addLast(E e)

public void addLast(E e){
    if(e == null)
    	throw new NullPointerException();
    elements[tail] = e; // 将元素添加到tail处
    if((tail = (tail +1 ) & (element.length-1)) == head)
    	doubleCapacity
}

  1. tail = (tail +1 ) & (element.length-1)—— 将tail指向下一个位置(tail的下一个位置是 (tail +1 ) & (element.length-1))
  2. (tail = (tail +1 ) & (element.length-1)) == head 时说明队列满了

神奇的操作:

进行与操作保证了索引在正确范围,与(element.length-1)相与就可以得到下一个正确位置,是因为elements.length时2的幂次方,(element.length-1)的后几位全是1,无论是证书还是附属,与(element.length-1)相与都能得到期望的下一个正确位置;

这种操作是循环数组中的常见操作,效率很高。

ps:与操作:将数转换为二进制,都为1时为1,其他情况都为0,得到值后再转为10进制

如:elements.length = 8,则(element.length-1) = 7,二进制为0111,对于8,与7相与,结果为0.

JDK8源码详解-util篇-ArrayDeque(双端队列),请详细解析相关概念和描述,联网解析,中文解析,源码详细解析每一步):删除指定元素 delete(int i) 参数:i —— 要删除的元素的索引 注意: 1. 本方法会改变结构导致元素移动 2. 队列已满且未扩容的情况下不能删除指定元素 3. 对于调用本方法的removeFirstOccurrence(Object o)和removeLastOccurrence(Object o),本方法中返回的并未使用,上述两个方法没有进行返回的判断处理 4. 本方法的返回不能作为是否删除成功的标识,其只标识移动的是头索引(返回false)还是尾索引(返回true) 备注: 1. 本详解中的正常顺序包括整个数组就是正常顺序和数组循环数组但是指定下标与头索引/尾索引之间的关系是正常顺序两种情况 2. 本详解中的循环顺序仅表示指定下标与头索引/尾索引之间的关系是非正常(循环)顺序 // 源码 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; // 此处计算了尾索引到头索引的距离,与指定索引到头索引的距离进行比较,以下两种情况会抛异常 // 情况1:不变性检测后,增加元素后队列满了这种情况(距离为0) // 情况2:不变性检测后,移除元素导致指定索引到头索引的距离小于尾索引到头索引的距离(指定元素可能已被删除) if (front >= ((t - h) & mask)) throw new ConcurrentModificationException(); // 判断索引元素距头索引远还是距尾索引远,选择元素较少的方向移动元素和头尾索引 // 距头索引较近,变更头索引,移除成功返回false if (front < back) { // 头索引小于等于指定索引(正常的数组顺序,从前往后) if (h <= i) { // 复制指定索引前面的元素全部后移一位(复制到后面) System.arraycopy(elements, h, elements, h + 1, front); } else { // 头索引大于指定索引(非正常的数组顺序,循环数组循环部分) // 将索引[0~指定索引元素前]的元素后移一位(复制到后面) System.arraycopy(elements, 0, elements, 1, i); // 将数组最大索引复制至索引0 elements[0] = elements[mask]; // 将头索引后的元素全部后移一位(正常顺序) System.arraycopy(elements, h, elements, h + 1, mask - h); } // 原头索引设置为null,此索引已不再是头索引了 elements[h] = null; // 重新计算头索引并赋(原头索引后一位) head = (h + 1) & mask; return false; } else { // 距尾索引较近,变更尾索引,移除成功返回true // 指定索引小于尾索引(正常的数组顺序,从前到后) if (i < t) { // 直接将指定索引后尾索引之前的元素前移一位(复制到前面) System.arraycopy(elements, i +
04-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值