数组实现环形队列(java)
分析图示
- 牺牲一个数组空间的原因是为了代码看起来容易理解。如果不这么做,我们判断队列空和队列满就会有点问题。规定初始时rear=front=0,当插入一个数据时,rear+1;取出一个数据时,front-1;(注意:队列是先进先出的数据结构,插入数据只能从队尾进,取输入只能从队头取。)如果不预留一个空间,那么队列满时,rear==front,队列空时rear也等于front。
- 因此我们规定队列的最大容量要比数组的长度小1(如上图,数组长度为4,而实际上队列可以存放的最大容量是3)。规定rear指向队尾元素的下一个位置(即预留空间)。
-当然也可以不这么规定!!
- 接下来用图示模拟一下队列的操作:
此时队列按规定是满的,可推出队满条件:(rear+1) % maxSize == front
取模(%)运算尤为重要,假设队列满了,取出两个数据后,那么队列又有两个空位置,这时要再新增一个数据8,判断(rear+1) % maxSize != front(队未满)后,将数据放到下标rear的位置上,然后rear+1,rear = 4;这时如果要再新增一个数据9,判断队未满后,将数据放到下标为rear的位置下,就产生了数组越界。因此这里rear必须要对数组长度取模!!!
如上一番操作后,此时队列如下图:
这时候rear=1,front=2,我们要计算队列中数据的个数,就不能直接用rear-front,会得到负数,应该是(rear+arr.length-front)%arr.length
代码实现
/**
* @author :Mrs.You
* @date :2020/10/11 19:21
* @description:用数组实现循环队列
*/
public class CircleArrayQueueDemo {
public static void main(String[] args) {
System.out.println("测试环形队列");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数组大小(队列实际容量比数组小1):");
int queueSize = scanner.nextInt();
ArrayQueue queue = new ArrayQueue(queueSize);
char key = ' '; //接收用户输入
boolean loop = true;
while (loop){
System.out.println("=====================");
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):查看队头元素");
System.out.println("l(length):查看队列长度");
key = scanner.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'e':
scanner.close();
loop = false;
break;
case 'a':
System.out.println("请输入要添加的数据:");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.println("出队数据是: "+res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int head = queue.headQueue();
System.out.println(head);
}catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'l':
System.out.println("队列长度:"+queue.size());
default:
break;
}
}
}
}
//使用数组模拟实现队列--编写一个ArrayQueue类
class ArrayQueue {
private int maxSize; //指数组长度(队列实际长度比数组容量小1)
private int front; //指向队头元素
private int rear; //指向预留空间(队尾元素的后一个位置)
private int[] arr; //模拟队列
public int getRear() {
return rear;
}
//创建队列的构造器
public ArrayQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
}
//判断队列是否满
public boolean isFull() {
return (rear+1) % maxSize == front;
}
//判断队列是否空
public boolean isEmpty() {
return rear == front;
}
//入队
public void addQueue(int n) {
//判断队列是否满
if (!isFull()) {
arr[rear % maxSize] = n;
rear = (rear+1) % maxSize;
} else {
System.out.println("队列满,不能加入数据");
return;
}
}
//出队
public int getQueue() {
//判断队列是否空
if (isEmpty()) {
//抛异常
throw new RuntimeException("队列空,不能取数据");
}
int value = arr[front];
front = (front+1) % maxSize;
return value;
}
//显示队列的所有数据
public void showQueue() {
if (isEmpty()) {
System.out.println("空队列");
return;
}
System.out.println("当前的队列:");
//从front开始遍历,遍历个数为队列内有效数据个数
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\t", i % maxSize, arr[i % maxSize]);
}
System.out.println();
}
//当前队列中(从front===》rear)有效数据的个数
public int size(){
//相当于rear-front的绝对值
return (rear-front+maxSize) % maxSize;
}
//显示队列的头数据
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列空的");
}
return arr[front];
}
}
手动整理----如有错误欢迎指出,欢迎探讨~
-转载请注明出处