在引用循环队列前,我们需要了解队列是如何线性实现的(下图有错,x=sq[front++])。
简单地讲,便是当队列为空时,front = rear = 0,每当插入元素尾指针+1,删除元素是头指针+1。但是,我们会发现一个问题,如上面的第四个图,0,1,2三个空间并没有使用。因此,为了占用该空间,我们使用了循环队列来实现。
循环队列原理图:
我们可以发现,当循环队列属于上图的d1情况时,是无法判断当前状态是队空还是队满。为了达到判断队列状态的目的,可以通过牺牲一个存储空间来实现。
如上图d2所示,
队头指针在队尾指针的下一位置时,队满。 Q.front == (Q.rear + 1) % MAXSIZE 因为队头指针可能又重新从0位置开始,而此时队尾指针是MAXSIZE - 1,所以需要求余。
当队头和队尾指针在同一位置时,队空。 Q.front == Q.rear;
以下是java关于循环队列的实现代码:
public class CircleQueue {
public int MaxSize; //最大长度
public int front; //头,指向队列头
public int rear; //尾,指向队列尾的后一个位置
public int[] arr; //数组
public CircleQueue(){}
//构造模拟队列的数组
public CircleQueue(int MaxSize){
this.MaxSize = MaxSize;
arr = new int[MaxSize];
front = 0;
rear = 0;
}
//判断队列满
public boolean isFull(){ //ture为满
return (rear+1)%MaxSize == front;
}
//判断队列空
public boolean isEmpty(){ //true为空
return front == rear;
}
//添加队列(rear变),注意队列是否已满
public void addQueue(int x){
boolean b = isFull();
if(b){
System.out.println("队列已满");
return; //如果你的 //code 只是在 else 里,一般说明这是 if 的另一种情况,写在里面比较好,合乎逻辑。
// 但是如果这个 if 只是个判断,遇 false 就return,不用走下面的逻辑,那么 写在外面比较好。
}
arr[rear] = x;
rear = (rear+1)%MaxSize;
}
//删除队列(front变),注意队列为空,并返回删除的值
public int getQueue(){
boolean b = isEmpty();
if(b) {
throw new RuntimeException("队列为空"); //throw之后就停止了,无需return
}
int a = arr[front];
front = (front+1)%MaxSize;
return a; //返回被删除的值
}
//输出队列中的所有值
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空");
return;
}
//遍历,从front开始,到front+(rear-front+MaxSize)%MaxSize
for(int i = front;i<front+size();i++){
//front始终在MaxSize的范围内,但是随着front的增长,加上有效数据个数后就有可能超出MaxSize范围,所以需要取模
System.out.printf("a[%d] = %d\n",i%MaxSize,arr[i%MaxSize]); //%同时可以起到一个替换的工作,每当遇到一个%要用后面的进行替换
}
}
//队列中的有效数据个数
public int size(){
return (rear-front+MaxSize)%MaxSize;
}
//获取队头的值
public int getHead(){
if(isEmpty()) {
throw new RuntimeException("队列为空"); //throw之后就停止了,无需return
}
return arr[front];
}
}