通过上一节内容,我们可以发现单向队列只能使用一次,不符合实际情况,所以在这一节学习可以多次循环使用的环形队列。
一、思路分析
1.front的含义做一个调整,front就指向队列第一个元素,也就是说arr[front]就是队列的第一个元素。
front初始值为0。
2.rear的含义做一个调整,rear指向队列的最后一个元素的后一位,因为希望队列空出一个空间做一个约定。
rear初始值为0。
3.当队列满时,条件为(rear+1)%maxSize == front,这里的我理解为,是通过判断rear的下一位是否是front,来得出队列是否达到最大容量(这里的实际最大容量为maxSize-1,因为预留了一个空间)而对maxSize取模,是因为这里是环形队列,把他想象成一个圆,得来的rear在圆上的相对位置,如果不取模,可能会出现rear+1超过队列的最大容量,从而报错下标越界。
4.当队列为空的时候,条件为 rear = = front
5.当我们这样分析,队列中有效的数据个数为(rear-front+maxSize)%maxSize,这里同样也是可以想象成一个圆,然后从圆中一前一后截取两个端点的距离,对maxSize取模,同样也是防止出现超过最大容量的情况出现,甚至可能出现负数。
6.需要注意getQueue和addQueue的时候,都需要先做存取再将下标+1,并且下标+1的时候需要注意下标越界,也就是需要对maxSize取模,即(旧下标+1)%maxSize=新下标。
二、代码实现
public class CircleArrayQueueDemo {
private int maxSize;//队列大小
private int front;//队列头
private int rear;//队列尾
private int[] arr;//用数组模拟队列
//参数为队列大小,同时初始化队列头,队列尾参数
public CircleArrayQueueDemo(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front = 0;
rear = 0;
}
public boolean isFull() {
return (rear+1)%maxSize==front; //通过rear的下一位下标的取模是否与front重合,来判断队列是否满了
}
public boolean isEmpty() {
return front == rear;//通过front是否等于rear来判断,队列是否为空
}
public int getQueue() {
if(isEmpty()) {
throw new RuntimeException("队列为空,无法获取信息");
}
int temp = arr[front];
front = (front+1)%maxSize ;
return temp;//注意这里是先取数据,再将front后移一位,因为front的定义发生了变化,初始化就是0
}
public void addQueue(int queue) {
if(isFull()) {
System.out.println("队列已满,无法增加队列!");
return;
}
arr[rear] = queue;//注意这里是先赋值再将rear后移一位,因为rear的定义也发生了变化,初始化为0,实际指向最后一个数据的后一位下标
rear = (rear+1)%maxSize;
}
public void showQueue() {
if(isEmpty()) {
System.out.println("队列为空");
return;
}
for(int i = front;i < front + size();i++) { //因为是环形队列,所以遍历次数为size(),起始位置为front
System.out.println("arr["+i%maxSize+"]="+arr[i%maxSize]);
}
}
public int headQueue() {
if(isEmpty()) {
throw new RuntimeException("队列为空");
}
return arr[front];
}
public int size() {
return (rear-front+maxSize)%maxSize;
}
}
测试类
public class Test2 {
public static void main(String[] args) {
CircleArrayQueueDemo aq = new CircleArrayQueueDemo(4);
char key = ' ';//模拟用户输入
boolean loop = true;
Scanner sc = new Scanner(System.in);
while(loop) {
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队列");
System.out.println("g(get):从队列中取出数据");
System.out.println("h(head):查看队列头数据");
key = sc.next().charAt(0);
switch (key) {
case 's':
aq.showQueue();
break;
case 'e':
loop = false;
sc.close();
break;
case 'a':
System.out.println("请输入一个数:");
int i = sc.nextInt();
aq.addQueue(i);
break;
case 'g':
try {
int queue = aq.getQueue();
System.out.println("您取出的数为:"+queue);
} catch (Exception e) {
System.out.println("队列为空,无法获取数据!");
}
break;
case 'h':
try {
int queue = aq.headQueue();;
System.out.println("队列头数据为:"+queue);
} catch (Exception e) {
System.out.println("队列为空,无法获取队列头!");
}
break;
default:
break;
}
}
}
}