环形队列介绍:
- 队列是一个有序列表,可以用数组或者链表来实现;
- 遵循先入先出的原则,即:先存入队列的数据,先取出,后存入的后取出;即先进先出原则。
- 队列空间可以循环使用
- 示意图
实现思路:
这里要解释一下取模运算,取模这个操作,比如a-b%c=d,可以理解为a和b之间的差值是n个c加上d,当数据是循环编号时,代表了a和b之间的绝对距离,这个距离的值为d。但是为什么我们求有效值不是用的(rear-front)%maxsize而是(rear+maxsize-front)%maxsize呢,因为在java中,%运算实际上是取余运算,计算的结果和设想的会有出入,可以看下百度百科的这个解释:
所以为了避免出错,我们把被除数a换算成非负数!
代码实现:
package com.xrw.queue;
import java.util.Scanner;
/**
* @program: DataStructures
* @description: 用数组实现环形队列:队列的特点:先进先出,后进后出;
* 实现思路:1、定义属性,队列的大小maxSize,队列的头部front指向队列的第一个元素,队列的尾部rear指向队列的最后一个元素的后一个节点,默认队列空出来一个节点
* 2、front = 0 ,rear = 0;
* 3、插入一个值:front不变,插入数据,rear = (rear+1)%maxSize;直到队列满:(rear+1-front)%maxsize == 0,就不允许插入
* 4、取出一个值:front = (front+1)%maxSize,取出数据;直到队列为空:rear == front,就不允许取出
* 5、队列的有效值的个数为 (rear+maxsize-front)%maxsize
* @author: 谢荣旺 1429382875@qq.com
* @create: 2021-04-01 22:23
**/
public class CircleArrayQueueDemo {
public static void main(String[] args) {
//新建一个队列
CircleArrayQueue arrayQueue = new CircleArrayQueue(4);
//接收用户输入
char key = ' ';
//输入流
Scanner scanner = new Scanner(System.in);
//控制程序结束的标记
boolean loop = true;
//程序运行,提供一个循环操作给用户
while (loop){
System.out.println("s(show): 显示队列");
System.out.println("e(exit): 退出程序");
System.out.println("a(add): 添加数据到队列");
System.out.println("p(pop): 从队列取出数据");
System.out.println("h(head): 查看队列头的数据");
key = scanner.next().charAt(0);//获取用户输入的第一个字符
switch (key){
case 's':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("输入一个数");
int value = scanner.nextInt();
arrayQueue.addQueue(value);
break;
case 'p':
try {
int i = arrayQueue.popQueue();
System.out.printf("取出的数据是%d\n",i);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int i = arrayQueue.getHead();
System.out.printf("队列的头数据为%d\n",i);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
loop = false;
break;
default:
System.out.println("输入非法,请重新输入");
break;
}
}
System.out.println("程序退出~~");
}
}
/**
* @Description: 环形队列
* @Author: 谢荣旺
* @Date: 2021/4/1
*/
class CircleArrayQueue{
//队列最大容量
private int maxSize;
//队列第一个元素的位置
private int front;
//队列最后一个元素的后一个位置
private int rear;
//实际存储数据的数组
private int[] arr;
/**
* @Description: 构造函数
* @param maxSize: 最大容量
* @return:
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public CircleArrayQueue(int maxSize) {
this.maxSize = maxSize;
front = 0;
rear = 0;
arr = new int[maxSize];
}
/**
* @Description: 判断队列是否已满
* @param :
* @return: boolean
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public boolean isFull(){
return (rear+1-front)%maxSize == 0;
}
/**
* @Description: 判断队列是否为空
* @param :
* @return: boolean
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public boolean isNull(){
return rear == front;
}
/**
* @Description: 往队列里面添加数组
* @param n: 要插入的数据
* @return: void
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public void addQueue(int n){
if (isFull()){
System.out.println("队列已满,无法插入");
return;
}
arr[rear] = n;
rear = (rear+1)%maxSize;
}
/**
* @Description: 从队列中取出一个数据
* @param :
* @return: int
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public int popQueue(){
if (isNull()){
//队列为空就抛出异常
throw new RuntimeException("队列为空,没有数据");
}
int pop = arr[front];
front = (front+1)%maxSize;
return pop;
}
/**
* @Description: 显示队列
* @param :
* @return: void
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public void showQueue(){
if (isNull()){
System.out.println("队列为空,没有数据");
return;
}
//先赋值是因为java的for循环对于函数条件,每次都会重新计算值,提前赋值可以提高运算效率
int size = size();
for (int i = front;i<front+size;i++){
System.out.printf("arr[%d] = %d\n",i%maxSize,arr[i%maxSize]);
}
}
/**
* @Description: 获取队列的第一个数据,但是不删除该数据
* @param :
* @return: int
* @Author: 谢荣旺
* @Date: 2021/3/31
*/
public int getHead(){
if (isNull()){
throw new RuntimeException("队列为空,没有数据");
}
return arr[front];
}
/**
* @Description: 判断队列有效数据的个数
* @param :
* @return: int
* @Author: 谢荣旺
* @Date: 2021/4/1
*/
public int size(){
return (rear+maxSize-front)%maxSize;
}
}
效果:
D:\code\java\jdk1.8.0_181\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:56152,suspend=y,server=n -javaagent:C:\Users\A\.IntelliJIdea2019.3\system\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\code\java\jdk1.8.0_181\jre\lib\charsets.jar;D:\code\java\jdk1.8.0_181\jre\lib\deploy.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\code\java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\code\java\jdk1.8.0_181\jre\lib\javaws.jar;D:\code\java\jdk1.8.0_181\jre\lib\jce.jar;D:\code\java\jdk1.8.0_181\jre\lib\jfr.jar;D:\code\java\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\code\java\jdk1.8.0_181\jre\lib\jsse.jar;D:\code\java\jdk1.8.0_181\jre\lib\management-agent.jar;D:\code\java\jdk1.8.0_181\jre\lib\plugin.jar;D:\code\java\jdk1.8.0_181\jre\lib\resources.jar;D:\code\java\jdk1.8.0_181\jre\lib\rt.jar;E:\我的文件\学习\数据结构与算法\源代码\DataStructures\out\production\DataStructures;D:\code\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar" com.xrw.queue.CircleArrayQueueDemo
Connected to the target VM, address: '127.0.0.1:56152', transport: 'socket'
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
1
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
2
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
3
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
s
arr[0] = 1
arr[1] = 2
arr[2] = 3
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
1
队列已满,无法插入
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
p
取出的数据是1
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
4
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
s
arr[1] = 2
arr[2] = 3
arr[3] = 4
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
p
取出的数据是2
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
a
输入一个数
7
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
s
arr[2] = 3
arr[3] = 4
arr[0] = 7
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
h
队列的头数据为3
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
s
arr[2] = 3
arr[3] = 4
arr[0] = 7
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
p(pop): 从队列取出数据
h(head): 查看队列头的数据
e
程序退出~~
Disconnected from the target VM, address: '127.0.0.1:56152', transport: 'socket'
Process finished with exit code 0