版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/www851903307/article/details/82828457
一、基本概念
1、特点:
- 在队列头部进行删除,在队列的尾部进行插入操作
2、主要实现:
- 使用循环数组
- 使用链表
3、关系图:
二、Queue
public interface Queue<E> extends Collection<E> {
//添加
boolean add(E var1);
//添加
boolean offer(E var1);
//移除
E remove();
//移除
E poll();
//获取元素
E element();
//获取
E peek();
}
一般peek、poll、offer方法跟其他类似方法的区别在于为空会返回null
三、Deque
1、特点:
- 双端队列:Deque是一种具有队列和栈的性质的数据结构,插入和删除操作可以在表的两端进行。
LinkedList实现了Deque接口,可以在两端进行插入和删除操作。
2、接口源码:
public interface Deque<E> extends Queue<E> {
//将元素插入队列
boolean add(E e);
//将元素插入队列,与add相比,在容量受限时应该使用这个
boolean offer(E e);
//将队首的元素删除,队列为空则抛出异常
E remove();
//将队首的元素删除,队列为空则返回null
E poll();
//获取队首元素,但不移除,队列为空则抛出异常
E element();
//获取队首元素,但不移除,队列为空则返回null
E peek();
...
}
提供了在两端移除、添加的相关方法
四、ArrayDeque
双端队列
- ArrayDeque通过循环数组的方式实现循环队列,容量为2的次幂。
- 作为Stack,因为其非线程安全所以效率高于java.util.Stack,而作为队列,因为其不需要结点支持所以更快。
1、变量:
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable {
//元素存储为数组
transient Object[] elements;
//头部元素索引
transient int head;
//队部元素索引
transient int tail;
//最小容量
private static final int MIN_INITIAL_CAPACITY = 8;
...
}
2、构造:
/**
* 无参构造,默认大小为16
*/
public ArrayDeque() {
elements = new Object[16];
}
/**
* @param numElements 初始容量
*/
public ArrayDeque(int numElements) {
allocateElements(numElements);
}
/**
* 传入一个集合
* @param c
*/
public ArrayDeque(Collection<? extends E> c) {
//获取初始容量,并创建数组
allocateElements(c.size());
//添加元素
addAll(c);
}
获取初始容量,并创建数组
private void allocateElements(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
//如果传入的容量>=MIN_INITIAL_CAPACITY
if (numElements >= initialCapacity) {
//通过右移和位或运算得到大于numElements的2^n个容量
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];
}
3、添加元素
添加元素都是从队列的尾部添加,如果调用addFirst,就是将索引为0作为队首,需要从length-1的位置(队尾)开始添加。如果addLast,则索引为0作为队尾。
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
//如果elements.length为8,最终head的索引为7,然后赋值
elements[head = (head - 1) & (elements.length - 1)] = e;
//进行扩容
if (head == tail)
doubleCapacity();
}
//如果将1-8的元素依次通过addFirst添加到队列中,此时head是从7到0,最终的顺序为[8,7,6,5,4,3,2,1]。
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
//队尾赋值,首次添加元素时tail为0
elements[tail] = e;
//将tail后移一位
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
//如果将1-8的元素依次通过addLast添加到队列中,此时tail从1到8,最终的顺序为[1,2,3,4,5,6,7,8]
//将容量扩大到2倍,然后元素复制到新数组
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;
}
4、删除元素:
删除元素时在队首删除,removeFirst时队首在前(索引为head)开始删,removeLast时队首在后(索引为tail)处开始删。
public E removeFirst() {
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E removeLast() {
E x = pollLast();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E pollFirst() {
final Object[] elements = this.elements;
final int h = head;
@SuppressWarnings("unchecked")
//获取head元素
E result = (E) elements[h];
// Element is null if deque empty
if (result != null) {
//head的元素置空,将head向后移动一位
elements[h] = null; // Must null out slot
head = (h + 1) & (elements.length - 1);
}
return result;
}
public E pollLast() {
final Object[] elements = this.elements;
//通过&运算获取队首元素索引(如果tail为2,队首索引t为1)
final int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
if (result != null) {
//删除最后一个元素,将tail向前移动一位
elements[t] = null;
tail = t;
}
return result;
}
5、获取元素:
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;
}