前言
-🏀大家好,我是BXuan,热爱编程与篮球的软件工程大二学生一名
-📚近期在准备4月份的蓝桥省赛,本章与大家一起聊聊有关队列的问题!如文有误,请大家指出并多多包涵。
-🏃放弃不难,但坚持一定很酷。
文章目录
🚩知识点
- 普通队列实现原理与应用
- 循环队列实现原理与应用
🚩概念
如果说链表和顺序表是对数据的存取位置的组织方式,那么队列就是一种对于存取方式限制的组织方式。换一种方式描述的话就是,队列既可以采用链表来表示,也可以采用数组(线性表)来表示,我们限制的是对于存放数据的存取方式。
🚩存储方式
顺序存储
链式存储
🚩队列
🌑队列的逻辑操作
- 队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表。
- 空队列:不含任何数据元素的队列。
- 允许插入(也称入队、进队)的一端称为队尾
- 允许删除(也称出队)的一端称为队头。
🌓队列的操作特性
先进先出(FIFO)
🌕循环队列
逻辑上是首尾相连的数组,可是在数组中其实不存在这样的数组,所以在物理实现上是不存在的。
1.循环队列的实现方法
我们可以用取模的方法将其实现:
-
tail=(tail+1)% MAXSIZE
-
head=(head+1) % MAZSIZE
2.关于循环队列必须要解决的问题
-
出队时判断循环队列队为空
队空:
head == tail
跟线性队列一样。 -
出队时判断循环队列队为满
队满:(tail+1) mod QueueSize==head
-
获得循环队列中的元素个数
length = (tail - head + QueueSize) % QueueSize;
由于顺序存储队列必须预先确定一个固定的长度,所以存在存储元素个数的限制和空间浪费的问题,循环队列可以减少此问题的出现。
🚀真题巩固
一、CLZ的银行(普通队列)
问题描述
CLZ 银行只有两个接待窗口,VIP 窗口和普通窗口,VIP 用户进入 VIP 窗口排队,剩下的进入普通窗口排队。现有 M 次操作,操作有四种类型,如下:
IN name V
:表示一名叫name
的用户到 VIP 窗口排队OUT V
:表示 VIP 窗口队尾的用户离开排队IN name N
:表示一名叫name
的用户到普通窗口排队OUT N
:表示普通窗口队尾的用户离开排队
求 M 次操作结束后 VIP 窗口队列和普通窗口队列中的姓名。
要求:使用普通队列实现该题
输入描述
第一行是一个整数 M(1≤M≤1000),表示一共有 M 次操作。
第二行到第 M+1 行输入操作,格式如下:
IN name V
OUT V
IN name N
OUT N
输出描述
输出 M 次操作后 VIP 窗口队列和普通窗口队列中的姓名(从头到尾),先输出 VIP 窗口队列后输出普通窗口队列。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
输入输出示例
输入:
5
IN xiaoming N
IN Adel V
IN laozhao N
OUT N
IN CLZ V
输出:
Adel
CLZ
laozhao
代码示例
package E_lanqiao;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
//主函数
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
Queue<String> vipQueue = new LinkedList<>();
Queue<String> nQueue = new LinkedList<>();
int M = scan.nextInt();// 表示M种操作
scan.nextLine();// 吸收换行符
while(M > 0) {
String string = scan.nextLine();
String[] arrsStrings = string.split(" ");
if(arrsStrings[0].equals("IN")) {
if(arrsStrings[2].equals("V")) {
//进队列
/*
* add与offer两者都是往队列尾部插入元素,不同的时候,当超出队列界限的时候,
* add()方法是抛出异常让你处理,而offer()方法是直接返回false
*/
// vipQueue.add(arrsStrings[1]);
vipQueue.offer(arrsStrings[1]);
}else {
nQueue.offer(arrsStrings[1]);
}
}else {
if(arrsStrings[1].equals("V")) {
vipQueue.poll();
}else {
nQueue.poll();
}
}
M--;
}
for (String string : vipQueue) {
System.out.println(string);
}
for (String string : nQueue) {
System.out.println(string);
}
scan.close();
}
}
二、CLZ的银行(循环队列)
问题描述
CLZ 银行只有两个接待窗口,VIP 窗口和普通窗口,VIP 用户进入 VIP 窗口排队,剩下的进入普通窗口排队。现有 M 次操作,操作有四种类型,如下:
IN name V
:表示一名叫name
的用户到 VIP 窗口排队OUT V
:表示 VIP 窗口队尾的用户离开排队IN name N
:表示一名叫name
的用户到普通窗口排队OUT N
:表示普通窗口队尾的用户离开排队
求 M 次操作结束后 VIP 窗口队列和普通窗口队列中的姓名。
要求:使用循环队列实现该题
输入描述
第一行是一个整数 M(1≤M≤1000),表示一共有 M 次操作。
第二行到第 M+1 行输入操作,格式如下:
IN name V
OUT V
IN name N
OUT N
输出描述
输出 M 次操作后 VIP 窗口队列和普通窗口队列中的姓名(从头到尾),先输出 VIP 窗口队列后输出普通窗口队列。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
输入输出示例
输入:
5
IN xiaoming N
IN Adel V
IN laozhao N
OUT N
IN CLZ V
输出:
Adel
CLZ
laozhao
代码示例
package E_lanqiao;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
// 创建两个数组构造队列
static Integer MAXSIZE = 1000;
static String[] viparrsStrings = new String[MAXSIZE];
static int vipfrontInteger = 0;
static int viprearInteger = 0;
static String[] narrStrings = new String[MAXSIZE];
static int nfrontInteger = 0;
static int nrearInteger = 0;
// 入队列
static boolean inQueue(String name1, String types) {
// 队列头指针在队尾指针的下一位位置上,说明满了
if(types.equals("V")) {
if((viprearInteger + 1)%MAXSIZE == vipfrontInteger) {
return false;
}else {
viparrsStrings[viprearInteger] = name1;
viprearInteger = (viprearInteger + 1) % MAXSIZE;
return true;
}
}else {
if((nrearInteger + 1)%MAXSIZE == nfrontInteger) {
return false;
}else {
narrStrings[nrearInteger] = name1;
nrearInteger = (nrearInteger + 1) % MAXSIZE;
return true;
}
}
}
// 出队列
private static boolean outQueue(String types) {
//出队列前判断队列是否为空
if(types.equals("V")) {
if(viprearInteger == vipfrontInteger) {
return false;
}else {
vipfrontInteger = (vipfrontInteger+1)%MAXSIZE;
return true;
}
}else {
if(nrearInteger == nfrontInteger) {
return false;
}else {
nfrontInteger = (nfrontInteger+1)%MAXSIZE;
return true;
}
}
}
// 获取函数
private static String getHead(String types) {
if(types.equals("V")) {
// 队列空 则返回空格
if(viprearInteger == vipfrontInteger) {
return "";
}else {
return viparrsStrings[vipfrontInteger];
}
}else {
if(nfrontInteger == nrearInteger) {
return "";
}else {
return narrStrings[nfrontInteger];
}
}
}
//主函数
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int M = scan.nextInt();// 个数
scan.nextLine();// 吃掉换行符
while(M > 0) {
String string = scan.nextLine();
String[] arrsStrings = string.split(" ");
if(arrsStrings[0].equals("IN")) {
inQueue(arrsStrings[1], arrsStrings[2]);
}else {
outQueue(arrsStrings[1]);
}
M--;
}
String string = getHead("V");
while(outQueue("V")) {
System.out.println(string);
string = getHead("V");
}
string = getHead("N");
while (string != null) {
System.out.println(string);
nfrontInteger++;
string = getHead("N");
}
scan.close();
}
}
👏小结
本章学习了java中有关队列的实现,在java中有可调用的api实现队列(import java.util.Queue;)(Queue q = new LinkedList();)(具体实现方法与细节后面介绍,可提前关注👆😁),在比赛中可无需花费大量的时间手撕队列,但学习的路上还是不能将其跳过,应面面俱到。冲冲冲!