循环队列是表示内部是循环的,但操作依然是只能往队尾添加元素,但各项操作优化到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();
}
这里只介绍几个重要的方法。
入队:
首先需要判断数组是否需要扩容
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;
}
然后计算在数组中入队的索引
预期入队索引
=第0个元素索引
+当前队列元素个数
。- 如果
预期入队索引
大于等于数组长度
,实际入队索引
=预期入队索引
-数组长度
。 - 如果
预期入队索引
小于数组长度
,实际入队索引
=预期入队索引
。
private int index(int index) {
index += front;
return index - (index >= elements.length ? elements.length : 0);
}
所以入队的方法为
public void enQueue(E element) {
// 数组扩容判断,要加新元素,需要的容量就是当前容量加一
ensureCapacity(size + 1);
// 索引计算,并赋值
elements[index(size)] = element;
// size加一
size++;
}
出队,就移动front指针
public E deQueue() {
// 获取出队元素
E frontElement = elements[front];
// 将索引位置致空
elements[front] = null;
// 更新font,这里参数为1
front = index(1);
// size减一
size--;
// 返回出队元素
return frontElement;
}
至此,循环队列的方法就介绍完了。值得探讨的是index这个方法,很精妙。
这篇文章参考了小码哥的笔记,附上链接
参考博文
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。