在上一篇JAVA 数组模拟队列的文章中存在问题:
当队列中的元素全部取出后,输出队列元素为空。再次向队列中添加元素时,提示队列已满,无法添加。
因为队列中数组只能使用一次,没有达到复用的效果。
本文将使用环形队列解决这个问题。
数组模拟环形队列思路分析:
1. 基于之前的 front 变量,在环形队列中, front 调整为 指向队列的第一个元素, 即 arr[front]。front 的初始值 为0。
2. 基于之前的 rear 变量,在环形队列中,rear 调整为指向队列的最后一个元素的前一个位置. 将最后一个位置空出来作为约定。rear 的初始值 为 0。
3. 当队列满时,使用条件 (rear + 1) % maxSize == front 来判断。(这里rear+1即为最后一个位置的下标,与队列的最大容量取模,再与front相比,front=0)。
4. 当队列为空时,使用条件 rear == front 来判断。
5. 基于上述分析,可以得出队列中有效数据的个数为: (rear + maxSize - front) % maxSize 。(取模是因为是环形队列,这样可以使队列的首尾相接。如果直接使用rear - front 来获取有效数据个数,可能会出现负数。
代码实现:
1、创建CircleQueue类
1)添加构造方法,完成队列的初始化操作。
public CircleQueue(int maxSize){
this.maxSize = maxSize;
queueArr = new int[maxSize];
}
2)判断队列是否已满
//判断队列是否已满
public boolean isFull(){
return (rear+1)%maxSize == front;
}
3)判断队列是否为空
//判断队列是否为空
public boolean isEmpty(){
return front==rear;
}
4) 向队列中添加元素
public void addQueue(int num){
if(isFull()){
System.out.println("队列已满,不能再添加数据~~~~");
return;
}
queueArr[rear] = num;
rear = (rear+1)%maxSize;
}
5)获取队列中有效数据的个数
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法获取数据~~~~~~");
}
int frontVal = queueArr[front];
front = (front+1)%maxSize;
return frontVal;
}
6)获取队列的头部元素
public int getHeadQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法获取数据~~~~~~");
}
return queueArr[front];
}
7) 打印队列中所有有效的数据
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空~~~~");
return;
}
for(int i=front;i<front+getQueueNum();i++){
System.out.printf("QueueArry[%d]=%d\n",i%maxSize,queueArr[i%maxSize]);
}
}
public int getQueueNum(){
return (rear+maxSize-front)%maxSize;
}
8)测试
public static void main(String[] args) {
CircleQueue queueArr = new CircleQueue(4);
Scanner sc = new Scanner(System.in);
char option =' ';
boolean flag = true;
while (flag){
System.out.println("s(show):查看队列中的所有元素");
System.out.println("a(add):向队列中添加元素");
System.out.println("g(get):获取出队列的元素");
System.out.println("h(head):获取队列的头部元素");
System.out.println("e(exit):退出队列");
option= sc.next().charAt(0);
switch (option){
case 's':
queueArr.showQueue();
break;
case 'a':
System.out.println("请输入要插入的元素:");
int index = sc.nextInt();
queueArr.addQueue(index);
break;
case 'g':
try {
int Queue = queueArr.getQueue();
System.out.println("取出的元素为:"+Queue);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int head = queueArr.getHeadQueue();
System.out.println("队列头部元素为:"+head);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
sc.close();
flag=false;
break;
default:
System.out.println("请输入正确的字符");
break;
}
}
System.out.println("退出队列~~~~~~~");
}
完整代码
package com.sc.test02;
import java.util.Scanner;
public class CircleQueueArray {
public static void main(String[] args) {
CircleQueue queueArr = new CircleQueue(4);
Scanner sc = new Scanner(System.in);
char option =' ';
boolean flag = true;
while (flag){
System.out.println("s(show):查看队列中的所有元素");
System.out.println("a(add):向队列中添加元素");
System.out.println("g(get):获取出队列的元素");
System.out.println("h(head):获取队列的头部元素");
System.out.println("e(exit):退出队列");
option= sc.next().charAt(0);
switch (option){
case 's':
queueArr.showQueue();
break;
case 'a':
System.out.println("请输入要插入的元素:");
int index = sc.nextInt();
queueArr.addQueue(index);
break;
case 'g':
try {
int Queue = queueArr.getQueue();
System.out.println("取出的元素为:"+Queue);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int head = queueArr.getHeadQueue();
System.out.println("队列头部元素为:"+head);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
sc.close();
flag=false;
break;
default:
System.out.println("请输入正确的字符");
break;
}
}
System.out.println("退出队列~~~~~~~");
}
}
class CircleQueue{
int front;
int rear;
int maxSize;
int[]queueArr;
public CircleQueue(int maxSize){
this.maxSize = maxSize;
queueArr = new int[maxSize];
}
//判断队列是否已满
public boolean isFull(){
return (rear+1)%maxSize == front;
}
//判断队列是否为空
public boolean isEmpty(){
return front==rear;
}
public void addQueue(int num){
if(isFull()){
System.out.println("队列已满,不能再添加数据~~~~");
return;
}
queueArr[rear] = num;
rear = (rear+1)%maxSize;
}
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法获取数据~~~~~~");
}
int frontVal = queueArr[front];
front = (front+1)%maxSize;
return frontVal;
}
public int getHeadQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法获取数据~~~~~~");
}
return queueArr[front];
}
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空~~~~");
return;
}
for(int i=front;i<front+getQueueNum();i++){
System.out.printf("QueueArry[%d]=%d\n",i%maxSize,queueArr[i%maxSize]);
}
}
public int getQueueNum(){
return (rear+maxSize-front)%maxSize;
}
}
输出结果:
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
s
队列为空~~~~
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
a
请输入要插入的元素:
1
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
a
请输入要插入的元素:
2
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
a
请输入要插入的元素:
3
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
g
取出的元素为:1
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
g
取出的元素为:2
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
s
QueueArry[2]=3
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
a
请输入要插入的元素:
4
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
a
请输入要插入的元素:
5
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
s
QueueArry[2]=3
QueueArry[3]=4
QueueArry[0]=5
s(show):查看队列中的所有元素
a(add):向队列中添加元素
g(get):获取出队列的元素
h(head):获取队列的头部元素
e(exit):退出队列
e
退出队列~~~~~~~
ok,可以看到,环形队列成功达到复用数据的效果。