06-java实现队列
06-java实现队列
一丶队列
- 队列是特殊的线性结构,只能在头尾两端操作
- 队尾入队,队头出队,
- FIFO
- 队列可以用动态数组和双向链表实现
- 优先使用双向链表,主要在头尾进行操作
二丶队列的接口设计(和之前的线性结构类似)
public class Queue<E> {
// 使用双向链表实现队列
private List<E> list = new LinkedList<>();
// 元素的数量
public int size();
// 是否为空
public boolean isEmpty();
// 入队
public void enQueue(E element);
// 出队
public E deQueue();
// 获取队列的头元素
public E front();
}
三丶队列的实现
public class Queue<E> {
private List<E> list = new LinkedList<>();
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public void enQueue(E element) {
list.add(element);
}
public E deQueue() {
return list.remove(0);
}
public E front() {
return list.get(0);
}
}
四丶双端队列
- 双端队列,头可以入队出队,尾可以入队出队
五、双端队列的接口设计&实现
public class Deque<E> {
private List<E> list = new LinkedList<>();
// 元素的数量
public int size() {
return list.size();
}
// 是否为空
public boolean isEmpty() {
return list.isEmpty();
}
// 从队头出队
public E deQueueFront() {
return list.remove(0);
}
// 从队头入队
public void enQueueFront(E element) {
list.add(0, element);
}
// 从队尾入队
public void enQueueRear(E element) {
list.add(element);
}
// 从队尾出队
public E deQueueRear() {
return list.remove(list.size() - 1);
}
// 获取队列的头元素
public E front() {
return list.get(0);
}
// 获取队列的尾元素
public E rear() {
return list.get(list.size() - 1);
}
}
六丶循环队列
- 队列内部实现也可以用动态数组实现,并且将各项接口优化到O(1)的时间复杂度, 这个用数组实现并优化之后的队列就叫做: 循环队列。
七、循环队列的接口设计
public class CircleQueue<E> {
// 记录第0个元素的索引
private int front;
// 当前队列存储的元素个数
private int size;
// 用来存储元素的数组
private E[] elements;
// 当前队列存储的元素数量
public int size();
// 当前队列是否为空
public boolean isEmpty();
// 入队
public void enQueue(E element);
// 出队
public E deQueue();
// 查看索引为0的元素
public E front();
}
八丶循环队列的实现
3.1 构造方法
public class ArrayList<E> {
private E[] elements;
// 设置elements数组默认的初始化空间
private static final int DEFAULT_CAPACITY = 10;
public CircleQueue() {
elements = (E[]) new Object[DEFAULT_CAPACITY];
}
}
3.2 入队
- 入队前需要考虑两个问题:队列是否需要扩容和计算入队实际索引。
3.2.1 动态扩容
动态数组的扩容方法拿来直接用即可
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity) return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1); //位运算
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[index(i)];
}
elements = newElements;
// 重置front
front = 0;
}
3.2.2 索引计算
- 获取实际索引公式 (front+index)%elements.length;
private int index(int index) {
return (front +index)%elements.length;
}
入队代码
public void enQueue(E element) {
// 数组扩容判断
ensureCapacity(size + 1);
// 索引计算,并赋值
elements[index(size)] = element;
// size加一
size++;
}
3.3 出队
- 一定要更新front指针,一定不要忘
public E deQueue() {
// 获取出队元素
E frontElement = elements[front];
// 将索引位置致空
elements[front] = null;
// 更新font
front = index(1);
// size减一
size--;
// 返回出队元素
return frontElement;
}