队列(Queue)的一个使用场景

银行排队的案例:

队列(Queue)介绍

  • 队列是一个有序列表,可以用数组或是链表来实现。
  • 遵循先入先出的原则。即:先存入队列的数据,要先取出来。后存入的要后取出来。

数组模拟队列

  • 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量。

  • 因为队列的输出、输入分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则是随着数据输入而改变的。如图所示:

思路分析:

当我们将数据存入队列时称为“addQueue”,addQueue的处理需要有两个步骤:

  • 将尾指针往后移:rear+1,当front == rear【空】
  • 若尾指针rear小于队列的最大下标maxSize-1,则将数据存入rear所指的数组元素中,否则无法存入数据。rear == maxSize-1【队列满】

代码实现

import java.util.Scanner;

public class ArrayQueueDemo {

	public static void main(String[] args) {
// 测试
//创建一个队列
ArrayQueue arrayQueue = 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(show):添加数据到队列");
System.out.println("g(get):从队列取出数据");
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();
System.out.println(value);
arrayQueue.addQueue(value);
break;
case 'g'://从队列取出数据
try {
int res = arrayQueue.getQueue();
System.out.printf("取出数据是%d\n",res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'h'://查看队列头的数据
try {
int res = arrayQueue.headQueue();
System.out.printf("队列头的数据是%d\n",res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'e'://退出程序
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~");
} }
//使用数组模拟队列-编写一个ArrayQueue类
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("队列已满,无法加入数据~~");
return;
}
rear ++;
arr[rear] = n;
}
//获取队列的数据(出队列)
public int getQueue() {
if(isEmpty()) {
throw new RuntimeException("队列为空,无法取数据~~");
}
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];
}
}

输出结果:

问题分析

目前数组使用一次就不能使用了,没有达到复用的效果

优化

  • 对前面的数组模拟队列的优化,充分利用数组,因此将数组看做是有个环形的。(通过取模的方式来实现即可)

    说明:

    • 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意,(rear+1)%maxSize == front[满]
    • rear == front[空]

    思路如下:

    • front变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值=0。
    • rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置。因为希望空出一个空间作为约定,rear的初始值=0。
    • 当队列满时,条件是:(rear+1)%maxSize==front【满】
    • 队列为空的条件:real==front【空】
    • 当我们这样分析后,队列中有效的数据的个数:(rear+maxSize-front) %maxSize

    有了这样一个思路,我们就可以在原来队列上修改得到一个环形队列。

优化后的代码

import java.util.Scanner;

/**
* @Author ITfxsen https://www.cnblogs.com/fxsenblog/
* @Time 2021-3-12 13:11:26
* @Version 1.0
* <p>Description:环形数组队列Demo</p>
*/
public class CircleArrayQueueDemo { public static void main(String[] args) {
// 测试
System.out.println("测试数组模拟环形队列~~");
//创建一个环形队列
CircleArray circleArray = new CircleArray(4);//队列有效数据最大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(show):添加数据到队列");
System.out.println("g(get):从队列取出数据");
System.out.println("h(head):查看队列头的数据");
key = scanner.next().charAt(0);
switch (key) {
case 's'://显示队列
circleArray.showQueue();
break;
case 'a'://添加数据到队列
System.out.println("请输入一个数字:");
int value = scanner.nextInt();
System.out.println(value);
circleArray.addQueue(value);
break;
case 'g'://从队列取出数据
try {
int res = circleArray.getQueue();
System.out.printf("取出数据是%d\n",res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'h'://查看队列头的数据
try {
int res = circleArray.headQueue();
System.out.printf("队列头的数据是%d\n",res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'e'://退出程序
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~"); } }
class CircleArray{
private int maxSize;//表示数组最大容量
//front变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值=0。
private int front;//队列头部
//rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置。因为希望空出一个空间作为约定,rear的初始值=0。
private int rear;//队列尾部
private int[] arr;//该数组用于存放数据,模拟队列 public CircleArray(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int [maxSize];
}
//判断队列是否满
public boolean isFull() {
return (rear+1) % maxSize==front;
}
//判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
//添加数据到队列
public void addQueue(int n) {
//判断队列是否已满
if(isFull()) {
System.out.println("队列已满,无法加入数据~~");
return;
}
//直接将数据加入
arr[rear] = n;
//将rear指针后移,这里必须考虑取模
rear = (rear + 1) % maxSize;
}
//获取队列的数据(出队列)
public int getQueue() {
if(isEmpty()) {
throw new RuntimeException("队列为空,无法取数据~~");
}
//这里需要分析出front是指向队列的第一个元素
//1、先把front对应的值保存到一个临时变量
//2、将front后移,考虑取模
//3、将临时保存的变量返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
//显示所有数据
public void showQueue() {
//判断是否为空
if(isEmpty()) {
System.out.println("队列为空,没有数据~~");
return;
}
//思路:从front开始遍历,遍历多少个元素
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
}
}
//求出当前队列有效数据的个数
public int size() {
return (rear + maxSize - front) % maxSize;
}
//显示队列的头数据,(不是取出数据)
public int headQueue() {
if(isEmpty()) {
throw new RuntimeException("队列为空,无法取数据~~");
}
return arr[front];
}
}

运行截图:

【数据结构与算法】——队列(Queue)的更多相关文章

  1. Airport Simulation (数据结构与算法 – 队列 / Queue 的应用)

    Airport Simulation 是数据结构与算法教材中用于演示Queue的一个小程序(大多数教师似乎会跳过这个练习).主程序会通过输入总的运行时间.队列里可以等待的最多飞机数量,平均每个时间单元 ...

  2. [数据结构与算法]队列Queue 的多种实现

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. javascript数据结构与算法---队列

    javascript数据结构与算法---队列 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按顺序排列的数据,先进先出,这点和栈不一样(后入先出).在栈中,最后入栈的元素 ...

  4. JavaScript数据结构与算法-队列练习

    队列的实现 // 队列类 function Deque () { this.dataStore = []; this.enqueueFront = enqueueFront; this.enqueue ...

  5. python数据结构与算法——队列

    队列结构可以使用数组来模拟,只需要设定头和尾的两个标记 参考自<啊哈> # 按书中的代码会出现索引越界的问题(书中申请了超量的空间) # 尝试令tai初始为len(q)-1则不会出错但少了 ...

  6. 每周一练 之 数据结构与算法(Queue)

    这是第二周的练习题,这里补充下咯,五一节马上就要到了,自己的计划先安排上了,开发一个有趣的玩意儿. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与 ...

  7. C语言- 基础数据结构和算法 - 队列的顺序存储

    听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友 ...

  8. JS数据结构与算法-队列结构

    队列结构 一.认识队列 受限的线性结构: 我们已经学习了一种受限的线性结构:栈结构. 并且已经知道这种受限的数据结构对于解决某些特定问题,会有特别的 效果. 下面,我们再来学习另外一个受限的数据结构: ...

  9. JavaScript数据结构和算法----队列

    前言 队列和栈很像,只是用了不同的原则.队列是遵循先进先出(FIFO)原则的一组有序的的项,队列在尾部添加新元素,从顶部移除元素.最新添加的元素必须必须排队在队列的,末尾.可以想象食堂排队买饭的样子. ...

  10. js数据结构与算法——队列

    <script> //创建一个队列 function Queue(){ let items = []; //向队尾添加一个新的项 this.enqueue = function(eleme ...

随机推荐

  1. 鸟哥的linux私房菜——第七章学习(Linux 磁盘与文件系统管理)

    1.1).文件系统特征 我们称呼一个可被挂载的数据为一个文件系统而不是一个分区! 文件系统通常会将这两部份的数据分别存放在不同的区块,权限与属性放置到 inode 中,至于实际数据则放置到 data ...

  2. codeforces - 978D【思维】

    D. Almost Arithmetic Progression time limit per test 1 second memory limit per test 256 megabytes in ...

  3. ajax和comet

    一,XMLHttpRequest对象 IE5是最早引入XHR对象的浏览器,XHR对象是通过MSXML库中的一个ActiveX对象实现的 使用MSXML库中的XHR对象,编写一个函数如下 functio ...

  4. 洛谷p1637 三元上升子序列(树状数组

    题目描述 Erwin最近对一种叫"thair"的东西巨感兴趣... 在含有n个整数的序列a1,a2......an中, 三个数被称作"thair"当且仅当i&l ...

  5. AbstractQueuedSynchronizer解析

    AbstractQueuedSynchronizer简称为AQS,是juc里很基本的一个包,juc里很多工具类是基于AQS实现的,理解了AQS,其它很多juc工具类也会比较清楚了. 1.方法简述 ge ...

  6. 使用Benchmark.NET测试代码性能

    今天,我们将研究如何使用Benchmark.Net来测试代码性能.借助基准测试,我们可以创建基准来验证所做的更改是否按预期工作并且不会导致性能下降. 并非每个项目都需要进行基准测试,但是如果您正在开发 ...

  7. virtual whiteboard

    virtual whiteboard 虚拟白板 / canvas https://twitter.com/excalidraw https://excalidraw.com/ https://gith ...

  8. Chrome DevTools & Slow 3G Network

    Chrome DevTools & Slow 3G Network shortcuts https://developers.google.com/web/tools/chrome-devto ...

  9. 基本ILS面的评估

    一.定义与用途 基本ILS面是ICAO DOC8168飞行程序设计规范中提到的一种限制面. 它相当于附件14中代码为3或4的精密进近跑道所规定的障碍物限制面的子集. 包含:进近面(分为两部分).过渡面 ...

  10. django学习-1.开始hello world!

    1.前言 当你想走上测试开发之路,用python开发出一个web页面的时候,需要找一个支持python语言的web框架.django框架有丰富的文档和学习资料,也是非常成熟的web开发框架,想学pyt ...