队列 - 数据结构与算法 - java
文章目录
1、什么是队列?
- 队列是一个有序列表,可以用数组或是链表来实现。
- 遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出 3) 示意图:(使用数组模拟队列示意图)
2、队列的应用场景?
在银行的柜台,需要使用队列进行实现
3、使用Java 进行队列的创建等一系列操作
3.1、创建的队列类
package com.luobin.DataStructure.队列;
/**
* @author LuoBin
* @version 1.0
* @date 2021/8/2 8:54 下午
*/
public class ArrayQueue {
private int maxSize; // 队列的最大值
private int front;
private int rear;
private int[] arr;// 用于存放数据
// 创建队列的构造器
public ArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
front = -1; // 指向队列的头部
rear = -1; // 指向队列的尾部,刚开始头部和尾部是重合的
}
// 判断队列是否是满的
public boolean isFull() {
return rear == maxSize - 1;
}
// 判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
// 将数据添加到队列
public void addQueue(int n) {
// 判断是否是满的
if (isFull()) {
System.out.println("队列是满的,不能加入数据!");
}
rear++; // 将标进行向后移动,添加数据
arr[rear] = n;
}
// 获取队列中的数据,出队列
public int getQueue() {
if (isEmpty()) {
// 通过抛出异常进行控制
throw new RuntimeException("队列为空,不能取出数据");
}
front++; // front 后移,进行取出数据先进,先出的原则
return arr[front];
}
// 显示队列的所有数据
public void showQueue() {
if (isEmpty()) {
System.out.println("队列是空的,没有数据");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.printf("arr[%d]=%d\n", i, arr[i]);
}
}
// 显示队列的头数据,注意不是取出数据
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("队列是空的,没有数据");
}
return arr[front + 1];
}
}
3.2、对创建的对象类进行测试相关的功能(main 方法实现)
package com.luobin.DataStructure.队列;
import java.util.Scanner;
/**
* @author LuoBin
* @version 1.0
* @date 2021/8/2 9:22 下午
*/
public class TestQueue {
public static void main(String[] args) {
// 对于队列进行测试
// 创建一个队列
ArrayQueue queue = new ArrayQueue(3);
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("g(get) : 从队列取出数据");
System.out.println("h(head) : 查看队列的头数据");
System.out.println("Input a char: ");
key = scanner.next().charAt(0); // 接收一个字符
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("请输入一个数字:");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.printf("取出的数据是:%d", res);
} catch (Exception e) {
// 获取到前面写的提示,数据是空的,不能获取到
System.out.println(e.getMessage());
}
case 'h':
try {
int res = queue.headQueue();
System.out.printf("队列头部的数据是:%d",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close(); // 关闭输入
loop = false; // 退出
default:
break;
}
}
System.out.println("程序退出~~");
}
}
4、对于上述的代码进行优化处理
4.1、存在的问题
- 目前数组使用一次就不能用, 没有达到复用的效果
- 将这个数组使用算法,改进成一个环形的队列 取模:%
4.2、优化代码(相关思路)
4.2.1、队列满时的条件
为了方便起见,约定:初始化建空队时,令
front=rear=0,
当队空时:front=rear
当队满时:front=rear 亦成立
因此只凭等式front=rear无法判断队空还是队满。 有两种方法处理上述问题:
(1)另设一个标志位以区别队列是空还是满。
(2)少用一个元素空间,约定以“队列头指针front在队尾指针rear的下一个位置上”作为队列“满”状态的标志。即:
队空时: front=rear
队满时: (rear+1)%maxsize=front
下面的图形表示了,环形队列中存储数据的状态:
4.2.2、获取有效数据个数
数组实现环形队列-获取有效数据个数
rear | 队尾元素下标的下一个 |
---|---|
front | 队头元素的下标 |
maxSize | 队列的最大长度 |
+maxSize | 防止结果为负数 |
%maxSize | 防止size大于maxSize |
如果把这个分段函数写成一个函数的时候,
size = (rear-front+maxSize)%maxSize
4.3、代码实现:
4.3.1、环形队列类的实现
package com.luobin.DataStructure.队列;
/**
* @author LuoBin
* @version 1.0
* @date 2021/8/3 3:38 下午
*/
public class CircleArrayQueue {
private int maxSize; // 队列的最大值
private int front; // 初始值为 0
private int rear; // rear 指向队列的最后一个元素的后一个位置 ,中间空下一个,使用
private int[] arr;// 用于存放数据
// 创建队列的构造器
public CircleArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
front = 0; // 指向队列的头部
rear = 0; // 指向队列的尾部,刚开始头部和尾部是重合的
}
public CircleArrayQueue() {
}
// 判断队列是否是满的
public boolean isFull() {
// 此处的判断是否为满的条件,比较特殊
// rear 后面的有一个是空的
return (rear + 1) % maxSize == front;
}
// 判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
// 将数据添加到队列
public void addQueue(int n) {
// 判断是否是满的
if (isFull()) {
System.out.println("队列是满的,不能加入数据!");
}
// 直接将数据加入
arr[rear] = n;
// 将 rear 进行后移的操作,使用了取模,使得,数据可以进行循环存放,前面有了空位置之后
// rear 是可以无限大的,但是存放的数据一直在循环
rear = (rear + 1) % maxSize;
}
// 获取队列中的数据,出队列
public int getQueue() {
if (isEmpty()) {
// 通过抛出异常进行控制
throw new RuntimeException("队列为空,不能取出数据");
}
// 需要分析 front 是指向队列的第一个元素
// 1、把 front 保存到临时变量
// 2、将front 后移,front 不能无休止的向后移动,使用取模,控制在环形的队列中
// 3、将临时变量返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
/*
为什么不能写成
return arr[front];
front = (front+1) % maxSize;
这种语句不成立,因为 return 之后的代码不会执行
写成
front++;
return arr[front];
没有考虑,环形队列的问题,不成立
写成
front = (front + 1) % maxSize;
return arr[front];
返回的不是第一个元素,不成立
综上,写成上面的形式
*/
}
// 显示队列的所有数据
public void showQueue() {
if (isEmpty()) {
System.out.println("队列是空的,没有数据");
return;
}
//从 front 进行遍历,遍历 size() 停止
for (int i = front; i < front + size(); i++) {
// i 变成 i % maxSize ,控制不要超过了队列的大小
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
// 求出当前队列中的存在的数据,否则无法完成遍历的功能
public int size() {
// rear = 1
// front = 0
// maxSize = 3
return (rear + maxSize - front) % maxSize;
}
// 显示队列的头数据,注意不是取出数据
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("队列是空的,没有数据");
}
// return arr[front + 1];
// 此处的front 代表的是队列的第一个元素,以前是 -1 开始,现在是 0 开始,不需要进行 +1 的操作
return arr[front];
}
}
4.3.2、环形队列的测试
package com.luobin.DataStructure.队列;
import java.util.Scanner;
/**
* @author LuoBin
* @version 1.0
* @date 2021/8/3 3:44 下午
*/
public class TestCircleArrayQueue {
public static void main(String[] args) {
System.out.println("对于环形队列的测试代码");
// 对于队列进行测试
// 创建一个队列
// 4 是最大的空间,只能存储两个数据,因为预留了一个空的位置
CircleArrayQueue queue = new CircleArrayQueue(4);
char key = ' '; // 用于用户的出入操作
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("\ns(show) : 显示队列");
System.out.println("e(exit) : 退出程序");
System.out.println("a(add) : 添加数据到队列");
System.out.println("g(get) : 从队列取出数据");
System.out.println("h(head) : 查看队列的头数据");
System.out.println("Input a char: ");
key = scanner.next().charAt(0); // 接收一个字符
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("请输入一个数字:");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.printf("取出的数据是:%d\n", res);
} catch (Exception e) {
// 获取到前面写的提示,数据是空的,不能获取到
System.out.println(e.getMessage());
}
case 'h':
try {
int res = queue.headQueue();
System.out.printf("队列头部的数据是:%d",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close(); // 关闭输入
loop = false; // 退出
default:
break;
}
}
System.out.println("程序退出~~");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!