目录

  • ArrayDeque
    • 循环数组
    • 属性
    • 构造函数
      • 详解
    • 方法定义
      • allocateElements(int numElements)详解
      • add(E e)、addFirst(E e)、addLast(E e)、push(E e)详解
      • clear()详解
      • clone()详解
      • contains(Object o)详解
      • descendingIterator()详解
      • element()、getFirst()、getLast()详解
      • isEmpty()详解
      • iterator()详解
      • offer(E e)、offerFirst(E e)、offerLast(E e)详解
      • peek()、peekFirst()、peekLast()详解
      • poll()、pollFirst()、pollLast()详解
      • remove()、remove(Object o)、removeFirst()、removeFirstOccurrence(Object o)、removeLast()、removeLastOccurrence(Object o)详解
      • pop()详解
      • size()详解
      • toArray()、toArray(T[] a)详解

ArrayDeque

  • Deque接口的可调整大小的数组双端队列实现,没有容量限制;根据需要增长以支持使用
  • 不是线程安全的;在没有外部同步的情况下,不支持多线程并发访问,禁止空元素
  • 该类在用作Stack时比Stack更快,当用作队列时比LinkedList更快;大多数ArrayDeque操作在分摊的常数时间内运行。例外情况包括removeremoveFirstOccurrenceremoveLastOccurrencecontainsiterator.remove()和批量操作,所有这些都在线性时间内运行
  • 该类的iterator方法返回的iterator是快速失败的:如果在迭代器创建后的任何时间修改双端队列,除了通过迭代器自己的remove方法外,迭代器通常会抛出ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是冒着在未来不确定的时间出现任意、非确定性行为的风险

循环数组

  • 如上图 head 指向队头,入队加元素时,tail队尾向后移动,出队时从 head 处取出元素并移除,这样就利用了线性数组实现先进先出的队列数据结构,当 head 等于 tail 时,则表示队列为空。但是这样存在问题:当不断出队时,head 向后移动,前面空出来的空间就被浪费,导致不断入队时,需要数组扩容,出队时造成大量空间无法使用,空间利用率低下
  • 假设,如果能将前面空出来的空间也利用起来进行存储末尾的元素,那么空间使用率将提高,就需要有个循环的思维,把这种线性弯曲成一个圆环,这样就可以反复使用空出来的空间,入队时使用出队空余出来的空间解决以上的问题
  • 当 head 等于 tail 时,则表示循环队列为空。head 和 tail 也是循环的,像钟表中的时针,具有周期性。这里 head 和tail 需要对长度 length 取模,这样 head 和 tail 将一直在长度范围内,可以作为数组的下标

属性

 // 存储双端队列元素的数组transient Object[] elements;// 队列头部元素的索引;如果双端队列为空,则为等于 tail 的任意数字transient int head;// 将下一个元素添加到双端队列尾部的索引transient int tail;// 用于新创建的双端队列的最小容量。必须是 2 的次幂private static final int MIN_INITIAL_CAPACITY = 8;

构造函数

方法 作用
ArrayDeque() 构造一个空数组,初始容量足以容纳16个元素
ArrayDeque(Collection<? extends E> c) 构造一个包含指定集合元素的双端队列,按照它们由集合的迭代器返回的顺序
ArrayDeque(int numElements) 构造一个空数组队列,初始容量足以容纳指定数量的元素

详解

    /*** 构造一个容量为16的空的双端队列*/public ArrayDeque() {elements = new Object[16];}/*** 构造一个容量为numElements的空的双端队列*/public ArrayDeque(int numElements) {allocateElements(numElements);}/*** 构造一个包含指定集合的​​元素的双端队列,按照集合迭代器返回的顺序* (集合的迭代器返回的第一个元素成为第一个元素,或双端队列的前面)*/public ArrayDeque(Collection<? extends E> c) {allocateElements(c.size());addAll(c);}

方法定义

方法 作用
添加 boolean add(E e) 在此队列的末尾插入指定的元素
void addFirst(E e) 在此队列前面插入指定的元素
void addLast(E e) 在此队列的末尾插入指定的元素
boolean offer(E e) 在此队列的末尾插入指定的元素
boolean offerFirst(E e) 在此队列的头部插入指定的元素
boolean offerLast(E e) 在此队列的末尾插入指定的元素
void push(E e) 将元素推送到此堆栈上
删除 void clear() 将这个队列中所有的元素删除
E poll() 检索并删除此队列的第一个元素,如果此队列为空,则返回 null
E pollFirst() 检索并删除队列的第一个元素,如果此队列为空,则返回 null
E pollLast() 检索并删除此队列的最后一个元素,如果此队列为空,则返回 null
E pop() 从堆栈中弹出一个元素
E remove() 检索并删除由此队列的头部
boolean remove(Object o) 从此队列中删除指定元素
E removeFirst() 检索并删除此队列的第一个元素
boolean removeFirstOccurrence(Object o) 删除此队列中指定元素的第一个出现
E removeLast() 检索并删除此队列的最后一个元素
boolean removeLastOccurrence(Object o) 删除此队列中指定元素的最后一次
查询 E element() 检索但不删除该队列的头
E getFirst() 检索但不删除该队列的第一个元素
E getLast() 检索但不删除该队列的最后一个元素
boolean isEmpty() 如果此队列不包含元素,则返回 true
boolean contains(Object o) 如果此队列包含指定的元素,则返回 true
E peek() 检索但不删除此队列的头部,如果此队列为空,则返回 null
E peekFirst() 检索但不删除此队列的第一个元素,如果此队列为空,则返回 null
E peekLast() 检索但不删除此队列的最后一个元素,如果此队列为空,则返回 null
int size() 返回此队列中的元素数
克隆 ArrayDeque clone() 返回此队列的副本
迭代器 Iterator iterator() 返回此队列中元素的迭代器
Spliterator spliterator() 在这个队列的元素上创建一个late-binding和快速失败的迭代器
Iterator descendingIterator() 以相反的顺序返回此队列中元素的迭代器
转数组 Object[] toArray() 以适当的顺序返回一个包含此队列中所有元素的数组
T[] toArray(T[] a) 以正确的顺序返回一个包含此队列中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型

allocateElements(int numElements)详解

    /*** 分配空数组以保存给定数量的元素*/private void allocateElements(int numElements) {// 创建数组,数组长度为大于当前参数的最小的2次幂整数elements = new Object[calculateSize(numElements)];}/*** 找到大于需要长度的最小的2次幂整数*/private static int calculateSize(int numElements) {// 默认为8int initialCapacity = MIN_INITIAL_CAPACITY;// 大于参数if (numElements >= initialCapacity) {initialCapacity = numElements;// 进行5次右移及位或操作initialCapacity |= (initialCapacity >>>  1);initialCapacity |= (initialCapacity >>>  2);initialCapacity |= (initialCapacity >>>  4);initialCapacity |= (initialCapacity >>>  8);initialCapacity |= (initialCapacity >>> 16);// +1initialCapacity++;// 小于0if (initialCapacity < 0)// 设置初始容量为2的30次方initialCapacity >>>= 1;}return initialCapacity;}
  • 对于一个小于2^30的值,经过五次右移和位或操作后,可以得到一个2^k - 1的值。最后再将这个值+1,得到2^k。通过这个方法,可以将一个任意的初始值转化为2^n的值,如果本身传进来的值就是2^n的值,那么经过转化会变成2^(n+1),所以不用刻意去传入2^n的值。如果传入的值大于等于2^30,那么经过转化会变成负值,即< 0,此时会把初始值设置为2^30,即最大的容量只有2^30

add(E e)、addFirst(E e)、addLast(E e)、push(E e)详解

    /*** 在此队列的末尾插入指定的元素,相当于addLast(E e)*/public boolean add(E e) {// 调用addLast方法addLast(e);return true;}/*** 在此队列前面插入指定的元素*/public void addFirst(E e) {// 如果元素为空,抛出NullPointerExceptionif (e == null)throw new NullPointerException();// 头部索引-1 与 length-1做与操作,elements[head = (head - 1) & (elements.length - 1)] = e;// 头部索引等于尾部索引时扩容if (head == tail)doubleCapacity();}/*** 在此队列的末尾插入指定的元素*/public void addLast(E e) {if (e == null)throw new NullPointerException();// 数组下标为tail的元素赋值e    elements[tail] = e;// 尾部索引+1 和 length - 1进行与操作等于头部索引时扩容if ( (tail = (tail + 1) & (elements.length - 1)) == head)doubleCapacity();}/*** 将元素推送到此堆栈上,相当于addFirst(e)*/public void push(E e) {addFirst(e);}/*** 将此双端队列的容量加倍。仅在当头部和尾部缠绕变得相等时调用*/private void doubleCapacity() {// 明确头部索引等于队列尾部下一个元素索引assert head == tail;int p = head;int n = elements.length;// p索引右边的元素数int r = n - p;// 新容量为旧容量左移一位即乘以2int newCapacity = n << 1;// 如果新容量小于0,抛出IllegalStateExceptionif (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;}

clear()详解

    /*** 将这个队列中所有的元素删除*/public void clear() {// 记录头部、尾部索引int h = head;int t = tail;// 不为空if (h != t) {// 重置首尾索引head = tail = 0;int i = h;int mask = elements.length - 1;do {// 清除元素elements[i] = null;i = (i + 1) & mask;} while (i != t);}}

clone()详解

    /*** 返回此队列的副本*/public ArrayDeque<E> clone() {try {@SuppressWarnings("unchecked")// 克隆ArrayDeque<E> result = (ArrayDeque<E>) super.clone();// 存储双端队列元素的数组赋值result.elements = Arrays.copyOf(elements, elements.length);return result;} catch (CloneNotSupportedException e) {throw new AssertionError();}}

contains(Object o)详解

    /*** 如果此队列包含指定的元素,则返回 true*/public boolean contains(Object o) {// 为空返回falseif (o == null)return false;int mask = elements.length - 1;int i = head;Object x;// 循环比较while ( (x = elements[i]) != null) {// 存在if (o.equals(x))return true;i = (i + 1) & mask;}// 不存在返回falsereturn false;}

descendingIterator()详解

    /*** 以相反的顺序返回此队列中元素的迭代器*/public Iterator<E> descendingIterator() {return new DescendingIterator();}private class DescendingIterator implements Iterator<E> {private int cursor = tail;// 游标开始索引为tailprivate int fence = head;// 游标的结束索引为headprivate int lastRet = -1;public boolean hasNext() {// 不相等说明有元素return cursor != fence;}public E next() {// 相等不存在元素if (cursor == fence)throw new NoSuchElementException();// tail是下个添加元素的位置,所以要减1才是尾节点的索引cursor = (cursor - 1) & (elements.length - 1);@SuppressWarnings("unchecked")E result = (E) elements[cursor];if (head != fence || result == null)throw new ConcurrentModificationException();lastRet = cursor;return result;}public void remove() {if (lastRet < 0)throw new IllegalStateException();if (!delete(lastRet)) {// 如果从左往右移,需要将游标加1cursor = (cursor + 1) & (elements.length - 1);fence = head;}lastRet = -1;}}

element()、getFirst()、getLast()详解

    /*** 检索但不删除该队列的头,相当于getFirst()*/public E element() {return getFirst();}/*** 检索但不删除该队列的第一个元素*/public E getFirst() {@SuppressWarnings("unchecked")// 获取头部元素E result = (E) elements[head];if (result == null)throw new NoSuchElementException();return result;}/*** 检索但不删除该队列的最后一个元素*/public E getLast() {@SuppressWarnings("unchecked")// 获取尾部元素E result = (E) elements[(tail - 1) & (elements.length - 1)];if (result == null)throw new NoSuchElementException();return result;}

isEmpty()详解

    /*** 如果此队列不包含元素,则返回 true*/public boolean isEmpty() {// 返回头部索引是否等于尾部索引return head == tail;}

iterator()详解

    public Iterator<E> iterator() {return new DeqIterator();}private class DeqIterator implements Iterator<E> {// 后续调用 next 返回的元素索引,即游标private int cursor = head;// 记录尾部索引(也在移除时记录),以停止迭代器并检查协同修改private int fence = tail;// 最近调用 next 返回的元素索引,如果调用 remove 删除元素,则重置为 -1private int lastRet = -1;public boolean hasNext() {return cursor != fence;}public E next() {if (cursor == fence)throw new NoSuchElementException();@SuppressWarnings("unchecked")// 获取元素E result = (E) elements[cursor];if (tail != fence || result == null)throw new ConcurrentModificationException();lastRet = cursor;cursor = (cursor + 1) & (elements.length - 1);return result;}public void remove() {if (lastRet < 0)throw new IllegalStateException();if (delete(lastRet)) { // 如果左移,则在 next() 中撤消增量cursor = (cursor - 1) & (elements.length - 1);// 游标位置回退1fence = tail;}lastRet = -1;}public void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);Object[] a = elements;int m = a.length - 1, f = fence, i = cursor;cursor = f;while (i != f) {@SuppressWarnings("unchecked") E e = (E)a[i];i = (i + 1) & m;if (e == null)throw new ConcurrentModificationException();action.accept(e);}}}

offer(E e)、offerFirst(E e)、offerLast(E e)详解

    /*** 在此队列的末尾插入指定的元素,相当于offerLast(E e)*/public boolean offer(E e) {return offerLast(e);}/*** 在此队列的头部插入指定的元素,相当于addFirst(e)*/public boolean offerFirst(E e) {addFirst(e);return true;}/*** 在此队列的末尾插入指定的元素,相当于addLast(e)*/public boolean offerLast(E e) {addLast(e);return true;}

peek()、peekFirst()、peekLast()详解

    /*** 检索但不删除此队列的头部,如果此队列为空,则返回 null,相当于peekFirst()*/public E peek() {return peekFirst();}/*** 检索但不删除此队列的第一个元素,如果此队列为空,则返回 null*/public E peekFirst() {// 获取队列头元素return (E) elements[head];}/*** 检索但不删除此队列的最后一个元素,如果此队列为空,则返回 null*/public E peekLast() {// 获取队列尾部元素return (E) elements[(tail - 1) & (elements.length - 1)];}

poll()、pollFirst()、pollLast()详解

    /*** 检索并删除此队列的第一个元素,如果此队列为空,则返回 null,相当于pollFirst()*/public E poll() {return pollFirst();}/*** 检索并删除队列的第一个元素,如果此队列为空,则返回 null*/public E pollFirst() {int h = head;@SuppressWarnings("unchecked")E result = (E) elements[h];// 如果为空返回nullif (result == null)return null;// 表明head位置已为空elements[h] = null;// 重新赋值头部索引head = (h + 1) & (elements.length - 1);return result;}/*** 检索并删除此队列的最后一个元素,如果此队列为空,则返回 null*/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;}

remove()、remove(Object o)、removeFirst()、removeFirstOccurrence(Object o)、removeLast()、removeLastOccurrence(Object o)详解

    /*** 检索并删除此队列的头部,相当于removeFirst()*/public E remove() {return removeFirst();}/*** 从此队列中删除指定元素,相当于removeFirstOccurrence(o)*/public boolean remove(Object o) {return removeFirstOccurrence(o);}/*** 检索并删除此队列的第一个元素,相当于pollFirst()*/public E removeFirst() {E x = pollFirst();if (x == null)throw new NoSuchElementException();return x;}/*** 删除此队列中指定元素的第一个出现*/public boolean removeFirstOccurrence(Object o) {// 为空返回falseif (o == null)return false;int mask = elements.length - 1;int i = head;Object x;// 循环元素while ( (x = elements[i]) != null) {// 删除第一个出现if (o.equals(x)) {delete(i);return true;}// 增加游标i = (i + 1) & mask;}return false;}/*** 检索并删除此队列的最后一个元素,相当于pollLast()*/public E removeLast() {E x = pollLast();if (x == null)throw new NoSuchElementException();return x;}/*** 删除此队列中指定元素的最后一次*/public boolean removeLastOccurrence(Object o) {// 为空返回falseif (o == null)return false;int mask = elements.length - 1;int i = (tail - 1) & mask;Object x;while ( (x = elements[i]) != null) {// 删除最后一次出现if (o.equals(x)) {delete(i);return true;}i = (i - 1) & mask;}return false;}

pop()详解

    /*** 从堆栈中弹出一个元素,相当于removeFirst()*/public E pop() {return removeFirst();}

size()详解

    /*** 返回此队列中的元素数*/public int size() {// 尾部元素下标减头部元素下标与数组长度-1做与运算return (tail - head) & (elements.length - 1);}

toArray()、toArray(T[] a)详解

    /*** 以适当的顺序返回一个包含此队列中所有元素的数组,其实是调用了copyElements(T[] a)*/public Object[] toArray() {// 复制数组return copyElements(new Object[size()]);}/*** 按顺序将元素数组elements复制到指定的数组中*/private <T> T[] copyElements(T[] a) {if (head < tail) {System.arraycopy(elements, head, a, 0, size());} else if (head > tail) {int headPortionLen = elements.length - head;System.arraycopy(elements, head, a, 0, headPortionLen);System.arraycopy(elements, 0, a, headPortionLen, tail);}return a;}/*** 以正确的顺序返回一个包含此队列中所有元素的数组; * 返回的数组的运行时类型是指定数组的运行时类型*/public <T> T[] toArray(T[] a) {int size = size();// 如果指定数组小于元素数,创建新数组if (a.length < size)a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);// 复制数组copyElements(a);if (a.length > size)a[size] = null;return a;}

集合之ArrayDeque相关推荐

  1. 死磕 java集合之ArrayDeque源码分析

    问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...

  2. java arraydeque_死磕 java集合之ArrayDeque源码分析

    问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...

  3. 深度剖析Java集合之ArrayDeque

    ArrayDeque ArrayDeque是Deque接口的一个实现,使用了可变数组,所以没有容量上的限制.同时,ArrayDeque是线程不安全的,在没有外部同步的情况下,不能再多线程环境下使用. ...

  4. 集合框架之ArrayDeque类详解

    Java集合框架分析(Deque)---ArrayDeque类详解 目录 一.数据结构 二.类标题 三.字段 四.构造函数 五.方法分析 类型 方法 作用 添加元素 public void addFi ...

  5. 死磕 java集合之终结篇

    概览 我们先来看一看java中所有集合的类关系图. 这里面的类太多了,请放大看,如果放大还看不清,请再放大看,如果还是看不清,请放弃. 我们下面主要分成五个部分来逐个击破. List List中的元素 ...

  6. Java SE第8章 Java集合

    Java SE第8章 Java集合 1. 集合的概念和作用 2. 使用Lambad表达式遍历集合 3.Collection集合的常规用法 4. 使用Predicate操作集合 5.使用Iterator ...

  7. java queue源码_java源码解读--queue

    queue接口特点:可以模拟队列行为,即"先进先出". 接口结构 queue接口继承了Collection接口,并增加了一些新方法 1 2 3 4 5 6 7 8 9 10 11 ...

  8. 深读源码-java集合类总结篇

    概览 我们先来看一看java中所有集合的类关系图. 这里面的类太多了,请放大看,如果放大还看不清,请再放大看,如果还是看不清,请放弃. 我们下面主要分成五个部分来逐个击破. List List中的元素 ...

  9. 栈与队列及其应用 - 1.算术表达式求值

    使用到了ArrayDeque集合:使用ArrayDeque表示Queue比LinkedList.表示Stack效率更高 ArrayDeque使用详解 package com.kiger.Demo;im ...

最新文章

  1. linux make makefile 内置变量 默认变量
  2. 【js笔记】数组那些事[0]
  3. Android Low Battery 低电量处理流程
  4. C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\文件不断增长,如何处理?...
  5. 配置Django实现数据库读写分离
  6. Python Tricks —— 计算 1+1/2+1/4+...=2
  7. java 汉字 char_char 类型如何存储一个汉字的?
  8. presentation编程软件_编程难学?web相关知识,跟着淼哥学php全栈之路6
  9. 帆软超级链接使用(根据内容跳转不同页面、超级链接使用js并传参、超级链接参数传递)
  10. c2c网站开店的流程图_C2C电子商务网站的交易流程
  11. Jib快速打包Docker镜像
  12. 《数学建模算法与应用第二版》——chapter13.数字图像处理
  13. JSON Viewer有个大bug导致不得不放弃掉
  14. STM32单片机基于HAL库开发HC-SR04 超声波测距模块(终极版)
  15. ROS学习笔记(八)—— moveit!概述
  16. 【无标题】阳光厨房管理系统需求分析
  17. Java/eclipse新建项目TR_52,编写程序,完成以下功能
  18. 乔布斯在斯坦福大学的演讲稿【中英】
  19. 北京地铁21号线_北京迎来地铁大动脉,设有21站,全为地下线,沿线市民幸运了...
  20. android 仿qq好友列表分组效果及联系人分组效果

热门文章

  1. Nodejs卸载、安装及环境配置
  2. Scala中List的步长by
  3. phpstudy提示80端口被system占用
  4. nginx1.18.0 安装vts
  5. python 在 win cmd 环境中形如 '\xhh' 输出的转化
  6. 计算机十进制转为八位二进制,Java将十进制转换为8位二进制(Java convert from decimal to 8-bit binary)...
  7. 学习JBPM 工作流引擎 API方法(二)
  8. Muli3D 4 Calculate vertex tangent
  9. studio 3T连接不上mongoDB
  10. Cesium是什么,简介