java arraydeque_java基础容器学习之双端队列ArrayDeque

ArrayDeque是Java中高效实现栈和队列功能的双端队列,其容量为2的指数,默认为8。插入操作通过循环数组防止越界,扩容时将原有元素复制到新的两倍容量数组中。ArrayDeque适用于需要快速在两端插入和删除的场景。

引言:

ArrayDeque,被称为“双端队列”,可以从两端进行插入或删除操作,当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque,当需要使用队列时也可以使用ArrayDeque。

ArrayDeque类简介:

Deque的含义是“double ended queue”,即双端队列。它可以实现栈和队列的功能,存在以下这些方法的关系:

队列方法 双端队列方法

add(e) addLast(e)

offer(e) offerLast(e)

remove() removeFirst()

poll() pollFirst()

element() getFirst()

peek() peekFirst()

栈方法 双端队列方法

push(e) addFirst(e)

pop() removeFirst()

peek() peekFirst()

很明显的,ArrayDeque类就是一个实现了两头插入删除的队列。

ArrayDeque类属性:

主要属性如下所示,为存放元素的数组elements,头的索引位置head,尾的索引位置tail。

transient Object[] elements;

transient int head;

transient int tail;

ArrayDeque类的具体结构如下图所示:

715d8ddb2c9a385ce68f2b0f6a4ee24b.png

ArrayDeque结构

ArrayDeque的数组是循环数组,就是可以head在后,tail在前。

ArrayDeque类的数组容量:

如下源码所示,ArrayDeque的数组容量由构造函数中调用allocateElements获取,而allocateElements方法的逻辑如下:

-1. 如果传入的容量参数numElements小于8,则使用8作为默认的容量。

-2.如果numElements>=8(且numElements<2的30次方),则取numElements的下一个2的指数的值作为容量。

-3.如果numElements>=2的30次,则取2的30次作为容量。

举个栗子:

numElements=9,

二进制为00000000 00000000 00000000 00001001

语句1后,结果为

00000000 00000000 00000000 00001101

语句2后,结果为

00000000 00000000 00000000 00001111

语句3,4,5执行后结果还是这个,就是15,再++就是16。

而numElements>=2的30次,则得到的结果为initialCapacity为-1,就是10000000 00000000 00000000 00000000,则右移一位,就是结果:01000000 00000000 00000000 00000000,2的30次。

private static final int MIN_INITIAL_CAPACITY = 8;

private void allocateElements(int numElements) {

int initialCapacity = MIN_INITIAL_CAPACITY;

if (numElements >= initialCapacity) {

initialCapacity = numElements;

initialCapacity |= (initialCapacity >>> 1);//1

initialCapacity |= (initialCapacity >>> 2);//2

initialCapacity |= (initialCapacity >>> 4);//3

initialCapacity |= (initialCapacity >>> 8);//4

initialCapacity |= (initialCapacity >>> 16);//5

initialCapacity++;

if (initialCapacity < 0)

initialCapacity >>>= 1;

}

elements = new Object[initialCapacity];

}

总结:ArrayDeque的容量总为2的指数,默认是8,构造函数时不必刻意传入2的指数,会自动计算。

如果传入的值>=2的30次,则使用最大容量2的30次。

ArrayDeque类的元素插入操作:

如下代码所示,为插入元素的操作,主要注意的是下标不能为越界。

这里使用(head - 1) & (elements.length - 1) 这样的方式来防止越界,elements.length - 1为低位全为1的二进制,与head-1做与运算,得到结果即可。

尾部插入操作也类似,都比较简单。

如下图所示:

f38fe9cc3e7f2de228ac0f9022a6d36d.png

addFirst操作

public void addFirst(E e) {

if (e == null)

throw new NullPointerException();

elements[head = (head - 1) & (elements.length - 1)] = e;

if (head == tail)

doubleCapacity();

}

ArrayDeque类的扩容操作:

如下代码所示,扩容操作主要分两部分,容量申请为原来的两倍,将head右边的数据复制,将head左边的数据复制。

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类已基本介绍完毕,后续还有许多java容器的类,下次介绍。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值