文章目录
前言
生活中很多情况都是先来后到, 最直接的就是银行的业务了吧, 先来的先处理, 队列可以看成是顺序的结构, 我们排队来一个新人是排在这一队的尾部, 每次处理头部的一个人, 队列可以用数组 和链表来实现
一、队列介绍
队列本身是有序的列表, 若使用数组的结构来存储队列的数据, 则队列数组中的声明如下面所示( 我们用maxSize来代表队列最大容量):
因为队列的输入、输出分别从前后端来进行处理的。所以需要两个变量(相当于指针的作用)分别来记录队列的 队首 和 队尾 的下标。显然,front会随数据的输出发生变化(在头部出队列:排队的时候在前面的先走);rear是在数据输入的时候发生变化(新的人过来,排在队尾),具体如下图所示(将两个指针都初始化为-1):
二、数组模拟队列
1.编写 队列 的类
代码如下:
class ArrayQueue{
private int maxSize;//队列容量
private int front; //队列头
private int rear; //队列尾
private int[] arr; //存放数据,模拟队列
//构造器:
public ArrayQueue(int maxSize){
this.maxSize = maxSize;
arr = new int[maxSize];
front = -1; //指向对象头部,指向队列头的前一个位置
rear = -1; //指向队列的尾部,指向队列尾部具体的数据(就是队列最后一个数据)
}
}
2.判断队列是否满
当rear指针等于maxSize - 1的时候就满了,代码如下:
//判断队列是否满
public boolean isFull(){
return rear == maxSize - 1;//上面已经提到
}
3.判断队列是否空
当rear指针等于front即为空(和排队时候对比即可),代码如下:
//判断队列是否为空
public boolean isEmpty(){
return rear == front;
}
4.入队列
当我们将数据存入队列的时候,定义方法"addQueue()",处理分为两个步骤即可:
1.调用isFull()方法判断队列是否满;
2.若队列没有满,可以添加数据:
2.1 尾指针rear后移:即rear = rear + 1;(指针指向空位置给新人)
2.2 将数据存入rear所指的数组位置中即可,
否则,不能加入数据(提醒用户),返回即可
代码如下:
// 添加数据
public void addData(int data){
if(isFull()){
System.out.println("队列满,加入数据失败...");
return;
}
rear++;//排队有人过来了,队尾指针后移(到空位置)
arr[rear] = data;//
}
5.出队列
当我们出队列的时候,处理分为以下两个步骤即可:
1.调用isEmpty()方法判断队列是否空;
2.若队列不为空,可以出队列(还有人在排队):
2.2 将头指针front后移(指向的第一个顾客前一个位置),找到第一个顾客
2.3 将arr[front]出列即可(对顾客进行服务)
否则,不能出队列(这里我们采用抛出异常的方法(也可打印提示))
抛出自定义的运行时异常,不用再进行return;(基础知识点,需要注意下)
代码如下:
public int getData(){
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
front++;//front后移
return arr[front];
}
6.遍历队列
当我们遍历队列的时候,分为以下步骤:
1.调用isEmpty()方法判断队列是否空;
2.若队列不为空,用 foreach 遍历即可:
否则,提示队列为空即可;
代码如下:
public void showData(){
//遍历
if(isEmpty()){
System.out.println("队列为空,没有数据");
return;
}
for(int i = 0 ; i < arr.length ; i++){
System.out.printf("a[%d] = %d\n" , i , arr[i]);
}
}
三、数组模拟环形队列
对上面的数组进行优化,充分利用数组:将其看作一个环形的(我们在此通过取模的方式完成) :1.调整思路如下:
1.front变量的含义做一个改变:front就是指向队列第一个元素。
也就是说,现在arr[front]就是队列的第一个元素;front的初始值 = 0;
2.rear变量的含义做出调整:rear就是指向的队列的元素的后一个位置。
因为希望空出一个空间来做一个约定(可以不预留)。rear初始值 = 0;
3.当队列满的时候,条件是(rear + 1)% maxSize == front
4.队列为空的时候,rear == front
5.队列中有效的数据个数为:(rear + maxSize - front) % maxSize
2. CircleArray的实现:
class CircleArray{
private int maxSize; //表示数组最大容量
private int front; //队列首部
private int rear; //队列尾部
private int[] arr; //该数组用于存放数据,模拟队列
// 创建队列的构造器
public CircleArray (int maxSize){
this.maxSize = maxSize;
arr = new int[maxSize];
front = 0;//初始化为0
rear = 0;//初始化为0
}
}
3.添加数据(入队列)
public void addData(int data){
if(isFull()){
System.out.println("队列满,不能加入数据");
return;
}
arr[rear] = data;
//后移数据
rear = (rear + 1) % maxSize;
}
4.获取数据(出队列)
public int getData(){
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
//这里考虑front指向的队列第一个元素
//1.先把front对应的值保存到一个临时变量
//2.将front后移,考虑取模
//3.将临时变量的值返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
5.得到有效数据个数🔺
public int size(){
return (rear + maxSize - front) % maxSize;
}
6.队列是否为空
public boolean isEmpty(){
return rear == front;
}
7.队列是否满
// 判断队列是否满
public boolean isFull(){
return ((rear + 1) % maxSize == front);
}
8.遍历环形队列
// 显示队列的所有数据
public void showData(){
//遍历
if(isEmpty()){
System.out.println("队列为空,没有数据");
return;
}
for(int i = front ; i < front + size() ; i++){
//这里需要注意一下:
System.out.printf("a[%d] = %d\n" , i % maxSize , arr[i % maxSize]);
}
}
四、总结
1. 对于普通的队列:front指向的是第一个元素的前一个位置;2. 对于普通的队列:rear指向的是最后一个数据本身位置;
3. 对于环形队列:reae指向最后一个数据的后一个位置;
4. 对于环形队列:front指向的就是第一个数据的位置;
5. 对于环形队列(front 和 rear初始为0):
需要注意的是关于队列中元素个数的计算方式;
测试代码
public class ArrayQueueDemo {
public static void main(String[] args) {
//测试
ArrayQueue queue = new ArrayQueue(3);
char key = ' ';//接收用户输入;
Scanner s = 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):查看队列头部数据");
key = s.next().charAt(0);
switch (key){
case 's':
queue.showData();
break;
case 'a':
System.out.println("请输入添加的数字:");
int data = s.nextInt();
queue.addData(data);
break;
case 'g':
try {
int res = queue.getData();
System.out.println("去除的数据是:" + res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int head = queue.headData();
System.out.println("队列头的数据是" + head);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
default:
System.out.println("操作不存在,请重新输入:");
break;
}
}
}
}
class ArrayQueue{
private int maxSize; //表示数组最大容量
private int front; //队列首部
private int rear; //队列尾部
private int[] arr; //该数组用于存放数据,模拟队列
// 创建队列的构造器
public ArrayQueue(int maxSize){
this.maxSize = maxSize;
arr = new int[maxSize];
front = -1; //指向对象头部,指向队列头的前一个位置
rear = -1; //指向队列的尾部,指向队列尾部具体的数据(就是队列最后一个数据)
}
// 判断队列是否满
public boolean isFull(){
return rear == maxSize - 1;
}
// 判断队列是否为空
public boolean isEmpty(){
return rear == front;
}
// 添加数据
public void addData(int data){
if(isFull()){
System.out.println("队列满,不能加入数据");
}
rear++;
arr[rear] = data;
}
// 获取数据
public int getData(){
// 判断是否为空
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
front++;
return arr[front];
}
// 显示队列的所有数据
public void showData(){
//遍历
if(isEmpty()){
System.out.println("队列为空,没有数据");
return;
}
for(int i = 0 ; i < arr.length ; i++){
System.out.printf("a[%d] = %d\n" , i , arr[i]);
}
}
// 显示头部数据
public int headData(){
// 判断
if(isEmpty()){
throw new RuntimeException("队列为空,没有数据...");
}
return arr[front + 1];
}
}