如果对队列还有些疑问的可以线看一看我上一个博客:用Java描述数据结构之栈和队列,以及栈和队列的常用方法
当我们只有一段固定大小空间去存一个队列时像这样:
Front是队首,Rear是队尾,很明显这个空间已经满了,现在依次删除队首元素:
可以发现随着队列内元素越来越少,没有用到的空间越来越大,且总空间大小不变,所以说到最后这段空间就算是废了。
为了让这段空间可持续利用,我们其实可以这样:
就是每次头删之后将队列中所有元素向前移,这就很好的解决了问题,完美的提升了空间的利用。可是,每头删一个元素都依次将后续元素前移这个操作无疑增加了时间复杂度。
所以为了降低时间复杂度我们可以设置一段检测队列大小和数组大小关系的代码,只有满足这个条件的时候在将有效数据依次前移,这样就不必每次头删都要前移,在一定程度上降低了时间复杂度。
当然还有另外一个方案解决,就是我们根本不必前移元素,只用改变以下头尾指针(就比喻为指针了)的用法,让队列在逻辑上看起来像个环就行了,这就是我们今天的主角——循环队列:
这是一个空队列,现在加入元素(下面环形队列图中的Rear指向有错,Rear应该指向队尾的下一个,就是空的第一个):
继续加入:
现在队列满了,我们头删元素:
可以看到,我们头删之后队列既多出空间插入新的元素,也不必前移元素,那么怎么去实现逻辑上是个环的这个循环队列呢?其实只需更灵活的使用头尾指针就可以。
我们结合LeetCode第622题来看
LeetCode.622.
现在来讨论它的具体实现:
public class MyCircularQueue {
//数组实现循环队列
private int[] queueArray;
//记录队首位置
private int frontIndex;
//记录队尾位置
private int rearIndex;
//记录队列长度
private int size;
//构造方法
public MyCircularQueue(int k) {
queueArray = new int[k];
frontIndex = 0;
rearIndex = 0;
size = 0;
}
//插入新元素
public boolean enQueue(int value) {
if(size == queueArray.length){
return false;
}
queueArray[rearIndex] = value;
size++;
rearIndex = (rearIndex + 1) % queueArray.length;
return true;
}
//删除元素
public boolean deQueue() {
if (size == 0){
return false;
}
frontIndex = (frontIndex + 1) % queueArray.length;
size--;
return true;
}
//从队首获取元素,如果队列为空返回-1
public int Front() {
if(size == 0){
return -1;
}
return queueArray[frontIndex];
}
//获取队尾元素,如果队列为空,返回-1
public int Rear() {
if(size == 0){
return -1;
}
//rearIndex始终指向第一个空的下标,
//所以要取队尾元素,就得取rearIndex前一个下标内的元素
//为了防止rearIndex指向0号下标
//做以下操作
int index = (rearIndex - 1 + queueArray.length) % queueArray.length;
return queueArray[index];
}
//判断队列是否为空
public boolean isEmpty() {
return size == 0;
}
//判断队列是否满
public boolean isFull() {
return size == queueArray.length;
}
}
以上就是对循环及其实现的简单介绍,如果理解有偏差,还望看官在评论区指正,谢谢