循环队列,主要是解决单队列浪费空间问题,当我们使用单队列执行出队操作时,虽然取出数据后的位置空闲,但是没有办法存储新数据,造成了一定程度上的空间浪费,而循环队列就解决了这个问题。
循环队列如何解决浪费空间问题呢?我们发现单队列主要是数组下标无法循环使用,我们让下标循环就好了呗。
怎么让下标循环呢?这里用到一点小算法:取余。
我们来看个图:图片下标有问题,懒得改了,大家将就着看吧。
从图中我们看到几个要点:
- front:指向队列第一个元素,array[front]就是队列中的第一个元素。front的初值=0;
- rear:指向队列的最后一个元素的后一个位置,空出一个位置,比如队列容量为3个,实际只使用2个。rear的初值=0;
- 队满:(rear+1) %maxsize = front;
- 队空:rear = front;
- 队列中有效数据个数:(rear+maxsize-front)%maxsize;
队满的条件为啥是(rear+1) %maxsize = front?可以把(rear+1)看成front的位置,取余是为了判断是否开始循环了,都已经循环了并且头尾(rear+1)重合了,肯定就队满了。
队列中有效数据个数为啥是(rear+maxsize-front)%maxsize?
- rear < maxsize,有效个数:rear-front;
- rear > maxsize:
- 有效个数:rear > front,有效个数:rear+maxsize-front;
- 有效个数:rear < front,有效个数:maxsize-front+rear;
- 两者综合:(rear+maxsize-front)%maxsize
public class CircleArrayQueueDemo {
public static void main(String[] args) {
CircleArrayQueue queue = new CircleArrayQueue(3); // 最大容量3,有效数据为2
boolean loop = true;
Scanner scanner = new Scanner(System.in);
char key;
while(loop){
System.out.println("=====================");
System.out.println("s:显示队列");
System.out.println("a:添加数据到队列");
System.out.println("g:获取队列中的数据");
System.out.println("h:获取队列中第一个数据");
System.out.println("e:退出程序");
System.out.println("=====================");
key = scanner.next().charAt(0);
switch (key){
case 's':queue.showqueue();break;
case 'a':
System.out.println("请输入一个数:");
int data = scanner.nextInt();
queue.addQueue(data);
break;
case 'g':
System.out.println("出队元素:"+queue.getQueue());
break;
case 'h':
System.out.println("队首元素:"+queue.headqueue());
break;
case 'e':loop = false;break;
}
}
}
}
// 数组模拟队列
class CircleArrayQueue{
private int MaxSize;
private int front; //指向队列第一个元素
private int rear; // 指向最后元素的后一个位置
private int[] queue;
// 初始化数组
public CircleArrayQueue(int maxSize){
MaxSize = maxSize;
front = 0;
rear = 0;
queue = new int[MaxSize];
}
public boolean isEmpty(){
return front == rear;
}
public boolean isFull(){
return (rear + 1) % MaxSize == front;
}
// 入队
public void addQueue(int data){
// 判断队列是否已满
if (isFull()){
System.out.println("队列已满,无法存数据");
return;
}
queue[rear] = data;
rear = (rear + 1) % MaxSize; // 循环下标
}
// 出队,与获取队首元素不同的是,每次获取到的元素不一样
public int getQueue(){
// 判断元素是否为空
if (isEmpty()){
throw new RuntimeException("队列为空,无法取数据");
}
int temp = queue[front];
front = (front + 1) % MaxSize; // 循环下标
return temp;
}
// 显示队列所有数据
public void showqueue(){
// (rear+MaxSize-front)%MaxSize 循环队列中有效数据长度
// i%MaxSize 防止下标超过最大长度
for (int i = front; i < (rear+MaxSize-front)%MaxSize; i++) {
System.out.printf("队列中的位置%d,对应值%d\n",i%MaxSize,queue[i%MaxSize]);
}
}
// 显示队列头部信息 ,不是取
public int headqueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,无法获取元素");
}
return queue[front];
}
}
运行结果: