package com.zzb.queue;
import java.util.Scanner;
/**
* @Auther: Administrator
* @Date: 2020/1/13 18:30
* @Description: 使用 数组 模拟 环形队列(以数组长度为2的极端方式理解)
* (1)front成员变量表示指向队列的第一个元素(即头部数据)的头索引,即array[front]就是队列的第一个元素(即头部数据),front的初始值为0,
* (2)rear成员变量表示指向队列的最后一个元素的后一个位置的尾索引,因为需要空出一个空间作为约定,rear的初始值为0,
* (3)当尾索引的下一个位置(即rear+1)为头索引时表示队列为满,代码表现为(rear+1)%maxSize==front,
* 【理解:队列的最后一个元素的下一个位置的尾索引(即rear);尾索引的下一个位置(即rear+1)】,
* (4)当尾索引的值等于头索引的值时表示队列尾空,代码表现为rear==front,
* (5)队列中有效的数据个数为(rear+maxSize-front)%maxSize
*/
public class CircleArrayQueueTest {
public static void main(String[] args) {
// 创建队列
// maxSize初始化为4,队列的有效数据的最大值为3
CircleArrayQueue queue = new CircleArrayQueue(3);
// 接受用户输入
char key = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while(loop) {
System.out.println("---------------a(add):添加数据到队列----------------");
System.out.println("---------------g(get):从队列中获取数据---------------");
System.out.println("---------------s(show):遍历队列---------------------");
System.out.println("---------------h(head):查看队列的头部数据-------------");
System.out.println("---------------l(size):查看队列中有效数据的个数--------");
System.out.println("---------------e(exit):退出程序----------------------");
// 接收一个字符
key = scanner.next().charAt(0);
switch(key) {
case 'a':
System.out.println("输入一个数据");
int data = scanner.nextInt();
queue.add(data);
break;
case 'g':
int get = queue.get();
System.out.println("获取的数据为 " + get);
break;
case 's':
queue.showQueue();
break;
case 'h':
int head = queue.head();
System.out.println("队列的头部数据为 " + head);
break;
case 'l':
int size = queue.size();
System.out.println("队列中有效数据的个数为 " + size);
break;
case 'e':
loop = false;
scanner.close();
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
// 数组模拟环形队列
class CircleArrayQueue {
// 队列的最大容量,即队列中数组的最大容量
private int maxSize;
// 队列头索引,即输出数据时队列中的数组要移动的索引
// front成员变量表示指向队列的第一个元素(即头部数据)的头索引,即array[front]就是队列的第一个元素(即头部数据),front的初始值为0
private int front;
// 队列尾索引,即输入数据时队列中的数组要移动的索引
// rear成员变量表示指向队列的最后一个元素的后一个位置的尾索引,因为需要空出一个空间作为约定,rear的初始值为0
private int rear;
// 数组用于模拟队列,存储数据
private int[] array;
// 构造器初始化队列
public CircleArrayQueue(int maxSize) {
this.maxSize = maxSize;
this.array = new int[maxSize];
// front成员变量表示指向队列的第一个元素(即头部数据)的头索引,即array[front]就是队列的第一个元素(即头部数据),front的初始值为0
this.front = 0;
// rear成员变量表示指向队列的最后一个元素的后一个位置的尾索引,(因为需要空出一个空间作为约定)rear的初始值为0
this.rear = 0;
}
// 判断队列是否为空
public boolean isEmpty() {
return this.rear == this.front;
}
// 判断队列是否满
public boolean isFull() {
return (this.rear+1)%this.maxSize == this.front;
}
// 添加数据到队列
public void add(int data) {
// 判断队列是否满
if(isFull()) {
System.out.println("队列已满,不能添加数据!");
return;
}
this.array[this.rear] = data;
// 把rear取模后移
// 尾索引rear 取模 分析:不取模的话逐步加1,必然会出现数组下标越界的情况,
// 取模 最大容量maxSize 后,尾索引rear的取值必然 出现在 0 - maxSize-1 范围之间,
// 符合数组下标取值,并且达到循环利用数组的预期效果
this.rear = (this.rear+1)%this.maxSize;
}
// 从队列中获取数据
public int get() {
// 判断队列是否为空
if(isEmpty()) {
throw new RuntimeException("队列为空,不能获取数据!");
}
// 把front索引对应的值存储到一个临时变量当中
int temp = this.array[this.front];
// 把front取模后移
// 头索引front 取模 分析:不取模的话逐步加1,必然会出现数组下标越界的情况,
// 取模 最大容量maxSize 后,头索引front的取值必然 出现在 0 - maxSize-1 范围之间,
// 符合数组下标取值,并且达到循环利用数组的预期效果
this.front = (this.front+1)%this.maxSize;
// 返回获取值
return temp;
}
// 遍历队列中的数据
public void showQueue() {
// 判断队列是否为空
if(isEmpty()) {
System.out.println("队列为空");
return;
}
// 已经获取的数据就不能被遍历出来
for(int i = this.front; i < this.front+size(); i++) {
System.out.print(this.array[i%this.maxSize] + "\t");
}
System.out.println();
}
// 显示队列的头部数据
public int head() {
// 判断队列是否为空
if(isEmpty()) {
throw new RuntimeException("队列为空!");
}
return this.array[this.front];
}
// 查看队列中有效数的个数
public int size() {
return (this.rear+this.maxSize-this.front)%this.maxSize;
}
}