java arraydeque poll,Java ArrayDeque「建议收藏」

java arraydeque poll,Java ArrayDeque「建议收藏」Queue是什么Queue是具有队列特性的接口Queue具有先进先出的特点Queue所有新元素都插入队列的末尾,移除元素都移除队列的头部publicinterfaceQueueextendsCollection{//往队列插入元素,如果出现异常会抛出异常booleanadd(Ee);//往队列插入元素,如果出现异常则返回falsebooleanoffer(Ee);//移除队列元素…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Queue是什么

Queue是具有队列特性的接口

Queue具有先进先出的特点

Queue所有新元素都插入队列的末尾,移除元素都移除队列的头部

public interface Queue extends Collection {

//往队列插入元素,如果出现异常会抛出异常

boolean add(E e);

//往队列插入元素,如果出现异常则返回false

boolean offer(E e);

//移除队列元素,如果出现异常会抛出异常

E remove();

//移除队列元素,如果出现异常则返回null

E poll();

//获取队列头部元素,如果出现异常会抛出异常

E element();

//获取队列头部元素,如果出现异常则返回null

E peek();

}

可以将上面的方法画成以下表格

操作

抛出异常

返回特殊值

插入

add()

offer()

删除

remove()

poll()

查询

element()

peek()

Deque是什么

Deque是一个双端队列

Deque继承自Queue

Deque具有先进先出或后进先出的特点

Deque支持所有元素在头部和尾部进行插入、删除、获取

public interface Deque extends Queue {

void addFirst(E e);//插入头部,异常会报错

boolean offerFirst(E e);//插入头部,异常返回false

E getFirst();//获取头部,异常会报错

E peekFirst();//获取头部,异常不报错

E removeFirst();//移除头部,异常会报错

E pollFirst();//移除头部,异常不报错

void addLast(E e);//插入尾部,异常会报错

boolean offerLast(E e);//插入尾部,异常返回false

E getLast();//获取尾部,异常会报错

E peekLast();//获取尾部,异常不报错

E removeLast();//移除尾部,异常会报错

E pollLast();//移除尾部,异常不报错

}

可以将上面的方法画成以下表格,只不过Deque是有头部和尾部的

操作

抛出异常

返回特殊值

插入

add()

offer()

删除

remove()

poll()

查询

element()

peek()

ArrayDeque是什么

实现于Deque,拥有队列或者栈特性的接口

实现于Cloneable,拥有克隆对象的特性

实现于Serializable,拥有序列化的能力

public class ArrayDeque extends AbstractCollection

implements Deque, Cloneable, Serializable{}

ArrayDeque的成员变量

//数组存储元素

transient Object[] elements;

//头部元素索引

transient int head;

//尾部元素索引

transient int tail;

//最小容量

private static final int MIN_INITIAL_CAPACITY = 8;

ArrayDeque底层使用数组存储元素,同时还使用head和tail来表示索引,但注意tail不是尾部元素的索引,而是尾部元素的下一位,即下一个将要被加入的元素的索引

ArrayDeque的初始化

public ArrayDeque() {

elements = new Object[16];

}

public ArrayDeque(int numElements) {

allocateElements(numElements);

}

public ArrayDeque(Collection extends E> c) {

allocateElements(c.size());

addAll(c);

}

private void allocateElements(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

}

elements = new Object[initialCapacity];

}

在初始化中,数组要求的大小必须为2^n,所以有这么一个算法,如果当前的大小大于默认规定的大小时,就会去计算出新的大小,那么这个计算过程是怎么样的呢?我们举一个例子进行分析

如果initialCapacity为10的时候,那么二进制为 1010

经过initialCapacity |= (initialCapacity >>> 1)时,那么二进制为 1010 | 0101 = 1111

经过initialCapacity |= (initialCapacity >>> 2)时,那么二进制为 1111 | 0011 = 1111

后面计算的结果都是1111,可以理解为将二进制的低位数都补上1,这样出来的结果都是2^n-1

最后initialCapacity++,2^n-1+1出来的结果就是2^n

这里又有人会有疑问了,为什么initialCapacity>>>16,右移到5位就可以结束呢?那是因为用的是|=符号,从右移1位到5位累加,其实就是整体右移了15位,刚好int值是16位的数,这就刚好满足16位二进制的低位都被补上了1

ArrayDeque的插入

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) {

if (e == null)

throw new NullPointerException();

//tail中保存的是即将加入末尾的元素的索引

elements[tail] = e;

//tail向后移动一位

if ( (tail = (tail + 1) & (elements.length – 1)) == head)

//tail和head相遇,空间用尽,需要扩容

doubleCapacity();

}

在存储的过程中,这里有个有趣的算法,就是tail的计算公式(tail = (tail + 1) & (elements.length – 1)),注意这里的存储采用的是环形队列的形式,也就是当tail到达容量最后一个的时候,tail就为等于0,否则tail的值tail+1

(tail = (tail + 1) & (elements.length – 1))

证明:(elements.length – 1) = 2^n-1 即二进制的所有低位都为1,假设为 11111111

假设:tail为最后一个元素,则(tail + 1)为 (11111111 + 1) = 100000000

结果:(tail + 1) & (elements.length – 1) = 000000000,tail下一个要添加的索引为0

其插入过程中,如果刚好是最后一个元素时,示例如下图

9855e1c4d672

ArrayDeque的扩容

private void doubleCapacity() {

assert head == tail; //扩容时头部索引和尾部索引肯定相等

int p = head;

int n = elements.length;

//头部索引到数组末端(length-1处)共有多少元素

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;

}

其扩容的过程如下图

9855e1c4d672

ArrayDeque的删除

ArrayDeque支持从头尾两端移除元素,remove方法是通过poll来实现的。因为是基于数组的,在了解了环的原理后这段代码就比较容易理解了

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() {

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;

}

ArrayDeque的查询

@SuppressWarnings(“unchecked”)

public E peekFirst() {

// elements[head] is null if deque empty

return (E) elements[head];

}

@SuppressWarnings(“unchecked”)

public E peekLast() {

return (E) elements[(tail – 1) & (elements.length – 1)];

}

总结

ArrayDeque是Deque 接口的一种具体实现,是依赖于可变数组来实现的。ArrayDeque 没有容量限制,可根据需求自动进行扩容。ArrayDeque 可以作为栈来使用,效率要高于Stack;ArrayDeque 也可以作为队列来使用,效率相较于基于双向链表的LinkedList也要更好一些

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191355.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Cloudsim_java源码大全

    Cloudsim_java源码大全CloudSim介绍和使用1.CloudSim简介:2.CloudSim提供了以下新的特点:(1)支持大型云计算的基础设施的建模与仿真;(2)一个自足的支持数据中心、服务代理人、调度和分配策略的平台。(3)CloudSim独特功能有:3.CloudSim源代码介绍几个核心类:4.CloudSim下载,CloudSim在IDEA中配置5.CloudSim环境配置6.CloudSim的扩展7.使用CloudSim仿真的一般步骤1.CloudSim简介:2009年4月8日,澳大利亚墨尔本

    2022年10月13日
    0
  • MODBUS协议规范-中文版(免费下载)

    MODBUS协议规范-中文版(免费下载)1.Modbus数据帧构成:地址域+功能码+数据+差错校验下面逐一解释各部分的具体含义:(1)地址域:即主站要访问的从站地址,其范围0~247(2)功能码:即主站想要从站执行什么动作。从大的方面看分为读(主站读取从站数据),写(主站向从站读取数据)(3)数据:如果主站的请求是读数据,那么该“数据”要包含的信息有:从哪里开始读数据+读多少数据。如果主站的请求是向从站写…

    2022年7月15日
    18
  • 网游盗号木马关闭杀软窗口盗号「建议收藏」

    网游盗号木马关闭杀软窗口盗号「建议收藏」病毒进入系统后,在系统盘的%WINDOWS%目录下生成病毒文件NAVMon32.exE和NAVMon32.dll,并修改注册表启动项相关数据,使自己能在每次系统启动时跟着自动运行起来。  紧接着,它创建线程,循环查找杀毒软件卡巴斯基的报警和提示窗口,只要找到,便模拟用户的鼠标点击,抢先关闭该窗口,使用户无法获得卡巴发出的系统异常警告。这样,病毒就能尽可能久地呆在用户系统中。  病毒顺利运行

    2022年7月25日
    12
  • struts2的拦截器AbstractInterceptor「建议收藏」

    struts2的拦截器AbstractInterceptor「建议收藏」publicclassAuthorizationInterceptorextendsAbstractInterceptor{@Override   publicStringintercept(ActionInvocationai)throwsException{      Map&lt;?,?&gt;session=ai.getInvocationConte…

    2022年5月14日
    37
  • c++迭代器iterator遍历map_iterator迭代器原理

    c++迭代器iterator遍历map_iterator迭代器原理什么是迭代器迭代器是一种可以遍历容器元素的数据类型。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。C++更趋向于使用迭代器而不是数组下标操作,因为标准库为每一种标准容器(如vector、map和list等)定义了一种迭代器类型,而只有少数容器(如vector)支持数组下标操作访问容器元素。可以通过迭代器指向你想访问容器的元素地址,通过*x打印出元素值。这和我们所熟知的指针极其类似。C语言有指针,指针用起来十分灵活高效。C++语言有迭代器,迭代器相对于指针而言功能更为丰富。vector,是数

    2025年7月1日
    1
  • SpringApplication初始化阶段[通俗易懂]

    SpringApplication初始化阶段[通俗易懂]在SpringFramework时代,Spring应用上下文通常由容器启动,如ContextLoaderListener或WebApplicationInitializer的实现类由Servlet容器装载并驱动。到了SpringBoot时代,Spring应用上下文的启动则通过调用SpringApplication.run(Object,String…)或SpringApplicationBuilder.run(String…)方法并配合@SpringBootApplication或@EnableAu

    2022年9月9日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号