首先我们先来了解一下队列是什么?
队列:数据先入先出,后进后出(与栈刚好相反),主要通过数组实现。需要通过两个指针来创建对应的队列;一个指针为前缀pre,一个指针为后缀rear。pre指针指向先进来的数的前面,rear指针指向数组的加入数,即有数据的末尾,以此来判断加入的数组是否已满。(我们这个pre指针指向的是首个数据的前面(要保证先进先出,就得要有个指针指向数据的第一个),而rear指向的是数据中的最后一个数据)
这是我对于队列的总结,但这只是普通队列,该种方式实现的队列只能使用一次(大家有兴趣可以去实现一下这个普通队列);如果要做到循环使用,那我们就要实现环形队列
环形队列:通过取模的方法实现环形队列,需要空出一个空间容量作为约定,此时pre指向的是先进来的数,rear为最后一个元素的后一个位置。此时(rear+1)% maxSize==front(满),rear==front(空)。下图是尚硅谷韩顺平老师对于环形队列的分析,我觉得很形象,图中的MaxSize-1为预留出的空间,我们需要一个预留的空间以达到循环的目的,即我们对于这个空间不操作,用于循环递换。
图中的得到有效数据的个数的公式,为什么加maxSize韩老师没有具体讲,我总结为+maxSize的原因是怕rear-front出现负数,此时无法取模,故加maxSize。
如果对于上图还不是很明白的,我附上代码实现,大家应该就懂了,如果还有不理解的,可以在评论区留言,我会及时回复解答的。
package com.liu.Array;
/**
* @author lwx
* @create 2021-09-06 21:17
*/
public class CircleQueue {
private int pre;//指向先进来的数
private int rear;//指向数据末尾的下一位
private int[] queue;//队列
private int maxSize;//队列的长度
public static void main(String[] args) {
CircleQueue circleQueue = new CircleQueue(10);
circleQueue.addQueue(2);
circleQueue.addQueue(4);
circleQueue.addQueue(5);
circleQueue.addQueue(8);
circleQueue.addQueue(10);
circleQueue.addQueue(10);
circleQueue.addQueue(10);
circleQueue.addQueue(10);
circleQueue.addQueue(10);
circleQueue.addQueue(10);
circleQueue.addQueue(11);
circleQueue.addQueue(12);
System.out.println("加入数据后队列为:");
circleQueue.show();
circleQueue.deleteQueue();
circleQueue.addQueue(0);
System.out.println("删除数据后队列为: ");
circleQueue.show();
}
public CircleQueue(int maxSize) {
this.maxSize = maxSize;
queue = new int[this.maxSize];
pre = 0;
rear = 0;
}
/**
* 判断该队列是否已满
*
* @return
*/
public boolean isFull() {
return (rear + 1) % maxSize == pre;
}
/**
* 判断该队列是否空
*
* @return
*/
public boolean isEmpty() {
return rear == pre;
}
/**
* 加入数据到队列中
*
* @param num 要传入的数据
*/
public void addQueue(int num) {
if (isFull()) {
System.out.println("该队列已满,无法添加");
return;
}
queue[rear] = num;
//加入完数据后rear指针要向后移动,借助取模以达到循环
rear = (rear + 1) % maxSize;
}
/**
* 删除队列中的数据
* 遵循先进先出原则
*/
public int deleteQueue() {
if (isEmpty()) {
throw new RuntimeException("该队列为空,无法取出数据");
}
int result = queue[pre];
//弹出数据后pre指针要向后移动,借助取模以达到循环
pre = (pre + 1) % maxSize;
return result;
}
/**
* 获取头数据
*
* @return
*/
public int getHead() {
return queue[pre + 1];
}
/**
* 获取有效数据的个数
*
* @return
*/
public int size() {
return (rear - pre + maxSize) % maxSize;
}
/**
* 显示队列的所有数据
*/
public void show() {
if (isEmpty()) {
System.out.println("队列中没有数据");
return;
}
for (int i = pre; i < pre + size(); i++) {
i = i % maxSize;//为了防止i的数值大于数组的长度
System.out.print(queue[i] + " ");
}
System.out.println();
}
}