目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、队列是什么?
1) 队列是一个有序列表,可以用数组或是链表来实现。
2) 遵循先入先出(FIFO)的原则。即:先存入队列的数据,先取出。后存入的要后取出
二、数组模拟队列
1.普通数组模拟队列
思路分析:
若使用数组的结构来存储队列的数据,则队列数组的声明如理解图,其中maxSize 是该队列的最大容量。
需要两个变量front 及 rear 分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear 则是随着数据输入而改变。
数据入队列时需要有两个步骤:
1)将尾指针往后移:rear+1,当front =rear 认为队列为null
2) 若尾指针 rear 小于队列的最大下标maxSize-1,则将数据存入 rear 所指的数组元素中,否则认为队列满,无法存入数据。
数据出队列时需要有两个步骤:
1)将尾指针往后移:front+1,当front =rear 认为队列为null
2)返回队列中的值。
代码示例:
public class QueueArray {
public static void main(String[] args) {
//测试数组模拟队列
Scanner scan = new Scanner(System.in);
//创建队列对象
ArrayQueue queue = new ArrayQueue(3);
boolean bool = true;
while(bool) {
System.out.println("----------------------------");
System.out.println("s(show) - 显示队列");
System.out.println("a(addQueue) - 添加数据到队列");
System.out.println("g(getQueue) - 获取数据出队列");
System.out.println("h(headQueue) - 显示队列头部信息");
System.out.println("e(exit) - 退出");
System.out.println("----------------------------");
char key = scan.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("请输入要添加的数据:");
int n = scan.nextInt();
queue.addQueue(n);
break;
case 'g':
int data = queue.getQueue();
System.out.println(data);
break;
case 'h':
int headQueue = queue.headQueue();
System.out.println(headQueue);
break;
case 'e':
bool = !bool;
break;
}
}
System.out.println("已退出数组模拟队列程序!");
}
//数组模拟队列
static class ArrayQueue {
//数组最大容量
private int maxSize;
//队列头 -- 指向数组头部的前一个位置
private int front;
//队列尾 -- 指向数组尾部
private int rear;
//存放数据的容器
private int[] queueArr;
public ArrayQueue(int maxSize) {
this.maxSize = maxSize;
queueArr = new int[maxSize];
front = -1;
rear = -1;
}
//判断数组是否为null
public boolean isEmpty() {
//如果数组队列头等于队列尾,说明数组为null
return front == rear;
}
public boolean isFull() {
//如果队列尾指向数组最后一个下标,说明数组满载
return rear == maxSize-1;
}
//进队列
public void addQueue(int num) {
//1.判断数组是否满载
if(isFull()) {
System.out.println("队列已经满载,不能再添加数据了");
return;
}
//2.添加数据
rear++;
queueArr[rear] = num;
}
//出队列
public int getQueue() {
//1.判断数组是否为null
if (isEmpty()) {
throw new RuntimeException("队列为null,没有可以取出的元素");
}
//2.出队列
front++;
return queueArr[front];
}
//展示所有队列信息
public void showQueue() {
//1.判断队列是否为null
if (isEmpty()) {
System.out.println("队列为null,没有数据");
return;
}
//2.遍历队列
for(int i = 0; i < queueArr.length; i++) {
System.out.printf("queueArr[%d]=%d\n",i,queueArr[i]);
}
}
//显示队列头部信息,注意:不取出数据,仅仅只是显示
public int headQueue() {
//1.判断队列是否为null
if (isEmpty()) {
throw new RuntimeException("队列为null,没有数据~");
}
//2.显示队列头的信息
return queueArr[front + 1];
}
}
以上数组模拟队列的问题:当数组存满后再取出所有元素,无法再次存入数据,数组无法重复使用,为了解决这个问题,就需要使用通过代码将数组变成环形数组来模拟队列。
2.环形数组模拟队列
思路分析:
主要是因为普通数组无法实现队列复用的问题,所以才会对其优化,用取模“%”的方法来实现环形数组模拟队列
关于环形数组牺牲数组最后一个下标的空间,其实也可以不用浪费这个空间,毕竟环形数组主要是通过取模来实现复用(只要保证取模的值在数组最大容量范围内即可),但是当数组长度为1的时候,就会出现一个小bug:判断队列空和队列满的条件冲突。
代码示例:
import java.util.Scanner;
public class CircleQueueArray {
public static void main(String[] args) {
//测试数组模拟队列
Scanner scan = new Scanner(System.in);
//创建队列对象
CircleArrayQueue queue = new CircleArrayQueue(3);
boolean bool = true;
while(bool) {
System.out.println("----------------------------");
System.out.println("s(show) - 显示队列");
System.out.println("a(addQueue) - 添加数据到队列");
System.out.println("g(getQueue) - 获取数据出队列");
System.out.println("h(headQueue) - 显示队列头部信息");
System.out.println("n(size() - 显示有效元素数量 ");
System.out.println("e(exit) - 退出");
System.out.println("----------------------------");
char key = scan.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("请输入要添加的数据:");
int n = scan.nextInt();
queue.addQueue(n);
break;
case 'g':
int data = queue.getQueue();
System.out.println(data);
break;
case 'h':
int headQueue = queue.headQueue();
System.out.println(headQueue);
break;
case 'n':
int size = queue.size();
System.out.println(size);
break;
case 'e':
bool = false;
break;
}
}
System.out.println("已退出环形数组模拟队列程序!");
}
static class CircleArrayQueue {
//数组最大容量
int maxSize;
//队列头 -- 指向队列头第一个元素的位置
int front;
//队列尾 -- 指向队列尾部前一个位置
int rear;
//数组容器
int[] queueArr;
//初始化环形数组
public CircleArrayQueue(int maxSize) {
this.maxSize = maxSize;
queueArr = new int[maxSize];
}
//判断数组是否为null
public boolean isEmpty() {
return front == rear;
}
//判断数组是否满载
public boolean isFull() {
return (rear+1)%maxSize == front;
}
//进队列
public void addQueue(int num) {
//1.判断是否满载
if (isFull()) {
System.out.println("队列已满,不能再添加数据了");
return;
}
//2.添加元素
queueArr[rear] = num;
rear = (rear+1)%maxSize;//指向队尾的指针后移
}
//出队列
public int getQueue() {
//1.判断是否为null
if(isEmpty()) {
throw new RuntimeException("数组为null,没有数据可取");
}
//2.出队列
int num = queueArr[front];
front = (front+1)%maxSize;
return num;
}
//显示所有队列信息
public void showQueue() {
if(isEmpty()) {
System.out.println("没有数据");
return;
}
for (int i = front; i < front+size(); i++) {
System.out.printf("queueArr[%d]=%d\n",i%maxSize,queueArr[i%maxSize]);
}
}
//求出当前队列的有效个数
public int size() {
return (rear-front+maxSize)%maxSize;
}
//显示队列头部信息
public int headQueue() {
//1.判断队列是否为null
if(isEmpty()) {
throw new RuntimeException("队列为null,没有数据~");
}
//2.显示队列头的信息
return queueArr[front];
}
}
*学习总结自尚硅谷数据结构与算法课程
总结
这里只是简单介绍了数组以及环形数组模拟队列,关于环形数组主要关注取模(%)这个技巧就好了。