体会:环形队列相比普通队列多了一个复用性,类似左轮与自动手枪的弹夹之分,左轮的弹夹(环形队列)中第一发子弹的索引并不会实时小于最后一发子弹的索引(如果给六个孔刻上编号),而且当六号弹孔有弹而一共不满六颗子弹时我不可能让队列尾索引再加一来给七号弹孔塞子弹,所以关键在于取模。
尾索引:rear 头索引:front 队列实际容量:maxSize-1
注意:rear指向最后一个元素的下一位,需要一个空位置来作为预留,所以maxSize-1才是本队列真正能塞进的个数。
判空:尾索引与头索引没有间距
判满:尾索引与预留位的和等于头索引为满 若不加预留位则会导致判空与判满区分困难。
循环遍历:头索引到末尾的情况下再i++就会越界,所以动态的让i也取模到虚拟的下一循环。
入队列:rear已经是下一位,所以直接插入再++取模
出队列:front不是普通队列的-1而是0,所以直接取出再++取模
代码
public class QueueStudy {
//队列容量
private int maxSize;
//队列头指针
private int front = 0;
//队列尾指针
private int rear = 0;
//队列
private int[] myQueue;
/*
创建队列
*/
public void createQueue(int size){
this.maxSize = size;
myQueue = new int[maxSize];
}
/*
是否为空
空即首尾指针处于同一索引
*/
public boolean isEmpty(){
return front == rear;
}
/*
队列已有数据
环形队列的队尾索引不恒大于队头索引,加一个容量来扩充,计算出有效个数后
再取模还原
*/
public int dataCount(){
return (rear + maxSize -front)%maxSize;
}
/*
是否已满
rear作为队列尾部元素的下一位约定,若与队列头重合则满
*/
public boolean isFull(){
return (rear + 1)%maxSize == front;
}
/*
输出队列
*/
public void showQueueData(){
int count = 0;
for(int i = front ; count < dataCount() ; i = (i+1)%maxSize){
count++;
System.out.printf("queue[%d] = %d \n ",i,myQueue[i]);
}
}
/*
入队列
*/
public void inData(int data){
//队列满不可入
if(isFull()){
System.out.println("队列满,插入不可");
}else{
myQueue[rear] = data;
System.out.println("入 :"+myQueue[rear]);
rear = (rear + 1) % maxSize;
}
}
/*
出队列
*/
public void outData(){
if(isEmpty()){
System.out.println("队列无数据");
}else{
System.out.println("出 :"+myQueue[front]);
front = (front + 1)%maxSize;
}
}
public static void main(String[] args) {
QueueStudy queueStudy = new QueueStudy();
queueStudy.createQueue(4);
System.out.println(queueStudy.isEmpty());
System.out.println(queueStudy.isFull());
queueStudy.inData(1);
queueStudy.inData(2);
queueStudy.inData(3);
queueStudy.outData();
queueStudy.inData(4);
queueStudy.showQueueData();
}
}