Java之ArrayDeque

本文介绍了Java中的ArrayDeque数据结构,它基于数组实现,可用作队列和栈。文章详细讲解了ArrayDeque的底层数据结构,提供了方法思维导图,并重点解析了add、remove和size()这三个方法的源代码实现。

一、底层数据结构

// 构造方法
public ArrayDeque() {
        elements = (E[]) new Object[16];
    }

该队列是基于数组实现的.

二、方法思维导图

在这里插入图片描述
从方法来看, ArrayDeque既可以用作队列(元素添加至尾部)、也可以作为(元素添加至头部).

三、 部分方法的源代码
1. add
public boolean add(E e) {
        addLast(e);
        return true;
    }
public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head) // 判断下一个索引是否超出数组范围
            doubleCapacity(); // 扩容
    }

为什么(tail = (tail + 1) & (elements.length - 1)) == head能够判断索引是否超出范围?

Firstly, 首先记住 2 n 2^n 2n & ( 2 n 2^n 2n-1) == 0 . 比如4&3==0, 16&15==0.And 若转为二进制则分别为100&011、10000&01111

Secondly, 构造方法保证了无论如何内部数组的长度总是 2 n 2^n 2n, 且长度必定>=8

Lastly, 举个栗子. 例如, 长度为16的数组, 最后一个元素的索引为(length - 1)即tail=15, 套用上面的代码16 = (15 + 1) & 16 -1, 即16 & 15.Get it?

// 构造方法一
public ArrayDeque() {
       elements = (E[]) new Object[16]; // 长度为2^4
    }
// 其它构造方法调用
private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY; // 8
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {  // 长度必定大于等于8
            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   // Integer.MAX_VALUE + 1
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = (E[]) new Object[initialCapacity];
    }
2. remove

虽然ArrayDeque与ArrayList都是基于数组实现的, 但是ArrayDeque并不提供根据索引访问数据, 也就是说不能像ArrayList一样根据索引访问数据例如:get(i), 因为ArrayDeque没有实现RandomAccess接口.

// 关键代码
public E pollFirst() {
        int h = head;
        E result = 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;
    }

它虽然基于数组实现, 却使用2个变量来记录队列的头部和尾部的索引, 头部索引并非一定为0.
private transient int head // 记录首个元素所在索引
private transient int tail //记录下一个元素添加时的索引

还有一点,分清数组长度(elements.length)集合大小(size())的区别.

3. size()
public int size() {
   return (tail - head) & (elements.length - 1);
 }
<think>嗯,用户问的是JavaArrayDeque是什么。首先,我需要回忆一下ArrayDeque的基本信息。ArrayDequeJava集合框架中的一个类,它实现了Deque接口,也就是双端队列。那Deque允许在两端进行插入和删除操作,对吧? 接下来,ArrayDeque的底层数据结构应该是一个动态数组,可能是一个循环数组。因为动态数组可以自动扩容,所以适合频繁的增删操作。不过,循环数组的实现可能有点复杂,比如头尾指针的管理,可能涉及到模运算。 然后,ArrayDeque的特点有哪些呢?比如线程不安全,但性能较好,适合单线程环境使用。而如果是多线程的话,可能需要使用ConcurrentLinkedDeque之类的线程安全类。另外,ArrayDeque不允许存储null元素,否则会抛出异常,这点需要注意。 ArrayDeque的常见用法包括作为队列或者双端队列使用。比如,作为时,push和pop方法是从头部添加和移除元素;作为队列时,offer和poll方法是从尾部添加,头部移除。而双端队列的话,可以同时操作两端的方法,比如addFirst、removeLast等。 还要比较一下ArrayDeque和其他类似的类,比如LinkedList。虽然LinkedList也实现了Deque接口,但它的底层是链表结构,所以对于频繁的插入删除操作,ArrayDeque可能效率更高,因为数组的内存连续,缓存命中率更好。不过,当数据量大时,扩容可能会有性能损耗,但总体来说还是比链表快。 另外,需要注意ArrayDeque的初始容量,默认初始容量是16,当元素超过容量时会自动扩容,通常是增长到原来的两倍。这一点在处理大量数据时可能需要考虑初始容量的设置以避免频繁扩容。 可能用户在使用的时候会遇到一些问题,比如如何正确初始化,或者在使用过程中出现的异常情况,比如添加null元素导致的NullPointerException。所以在编写代码时要确保元素不为null。 总结一下,ArrayDeque是一个基于动态数组实现的双端队列,适用于高效的操作两端的场景,线程不安全,性能较好,但不支持null元素。常见用途包括作为队列、双端队列使用,以及算法中的实现,比如BFS或者DFS等需要高效数据结构的场景。 现在需要将这些信息整理成一个结构清晰的回答,包括定义、底层结构、特点、使用场景、与LinkedList的比较,以及相关示例代码。同时,在回答末尾生成相关问题,比如ArrayDeque和LinkedList的区别,如何扩容,线程安全问题,使用场景举例等。</think>ArrayDequeJava集合框架中的双端队列(Deque)实现,基于动态数组结构。其特点如下: 1. **底层结构**:使用可变长的循环数组实现,通过头尾指针管理元素。 2. **线程安全**:非线程安全,适合单线程环境。 3. **性能优势**:相比LinkedList(链表结构),数组连续内存访问效率更高。 4. **不允许null元素**:添加null会抛出`NullPointerException`。 5. **常见用途**:作为队列、双端队列使用,常用于算法实现(如BFS/DFS)。 示例代码: ```java ArrayDeque<Integer> deque = new ArrayDeque<>(); deque.addFirst(1); // 添加到头部 deque.addLast(2); // 添加到尾部 System.out.println(deque.pollFirst()); // 移除头部元素(输出1) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值