队列的实例:电影院购票、排队打饭、去麦当劳买吃的,银行排队叫号等等这些场合都需要排队,生活中的各种排队现象就展示了队列的实例
队列的介绍:队列是个有序列表
队列的实现方式:
- 数组
- 链表
注意:若使用数组来模拟实现队列,就是顺序存储,若使用链表来实现队列,就是链式存储。
队列的重要原则
(或者叫做特点
):先入先出(FIFO)
,也就是说谁先进入到队列谁就会先被调出去。即:先存入队列的数据要先取出,反之,后存入队列的数据要后取出
使用数组来模拟实现队列
画图分析:
rear : 表示队尾,就是队列的尾部
front:表示对首,就是队列的头部
当把数据添加到队列中时,front的值和位置不会产生变化,而rear队尾的位置和值会随着数据的增加变化而变化。由此说明,往队列中添加数据是从队列尾部rear加,变化的是rear,而不是front
当把数据从队列中取出时,rear的值和位置不会产生变化,而front队首的位置和值会随着数据的减少变化而变化。由此说明:往队列中取出数据是从队列头部front取出的,变化的是front,而不是rear
若使用数组的结构来存储队列的数据,则数组队列的声明如下图所示:
设计队列时,首先定义个ArrayQureue
类,类中有4个属性(也叫做成员变量)分别是数组queueArr[]
、maxsize
、front
和rear
maxsize
:代表队列的最大容量,就是该队列数组最大能存储多少个数据
rear
:用来记录队列的队尾
front
:用来记录队列的队首
queueArr[]
:数组模拟实现队列,队列存的数据就是存放在数组中的。
队列的常用操作:(重要
)
- 创建队列
- 把数据添加到队列中(入队列)
- 把数据从队列从取出来(出队列)
入队列思路分析:
将入队列这个功能写成一个对应的成员方法addQueue(int n)
实现入队列需要两个步骤:
-
首先必须判断队列是否已满
rear == maxsize - 1
,当队尾rear = maxsize - 1
时,则说明队列已经满了,就不能实现入队列了,反之,当队尾rear != maxsize - 1 || real < maxsize - 1
时,则说明队列未满,就可实现入队列操作注意:判断队列是否满,取决于
maxsize
和rear
之间的关系画图分析:
-
将队尾
rear ++
,rear的位置往后移动以下,数据从队尾加入。
出队列思路分析:
将出队列这个功能写成一个对应的成员方法getQueue(int num)
实现出队列需要两个步骤:
-
首先判断队列是否为空
rear == front
,若队首和队尾相等了rear = front
,则证明队列是空的,就不能实现出队列的操作,若强制实现出队列,会抛出数组下标越界异常,反之,则证明队列不为空,则可实现出队列的操作。注意:判断队列是否满,取决于
front
和rear
之间的关系画图分析:
-
将队首
front ++
,front的位置往后移动以下,数据从队首取出。画图分析:
当
front = - 1
时, 队列中的第一个数据是queueArr[0]
,front指向的是队列头的前一个位置,front
不包含这个queueArr[0]
数据,当front ++ ;这时front = 0,然后实现return queueArr[front];
出队列操作,则证明queueArr[0]
出队列了,同理,队列中不再包含queueArr[0]
这个数据,那么队列中的第一个数据所在的位置由原来的queueArr[0]
变为了现在的queueArr[1]
。画图分析:
代码实现:
import java.util.Scanner;
public class ArrayDemoTest{
public static void main(String[] agrs){
// 实例化 ArrayQueue对象
ArrayQueue arrayQueue = new ArrayQueue(3);
char c = ' ';
Scanner input = new Scanner(System.in);
boolean flag = true;
while(flag){
System.out.println("s (showQueue()) : 显示队列中的所有数据");
System.out.println("a(addQueue()): 实现入队列操作,把数据添加到队列中");
System.out.println("g(getQueue()): 实现出队列操作,把数据从队列中取出来");
System.out.println("h (headQueue()) : 查看队列中的第一个数据");
System.out.println("e (exit) : 退出程序");
System.out.println("请选择(s、a、g、h、e):");
c = input.next().charAt(0);
switch(c) {
case 'e':
input.close();
flag = false;
break;
case 's':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("请输入一个数:");
int num = input.nextInt();
arrayQueue.addQueue(num);
break;
case 'g':
try{
System.out.println("取出的数据是" + arrayQueue.getQueue());
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try{
System.out.println("队列的第一个数据是" + arrayQueue.headQueue());
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
default:
System.out.println("您输入的信息错误");
break;
}
}
System.out.println("程序正常退出");
}
}
// 定义个ArrayQureue类
class ArrayQueue{
// 编写属性(共4个)
// maxsize : 表示队列的最大容量
private int maxsize;
// rear : 表示队列的尾部,即:队尾
private int rear;
// front :表示 队列的头部 即:队首
private int front;
// queueArr[] : 数组模拟实现队列,队列存的数据就是存放在数组中的
private int queueArr[];
// 编写队列的构造方法,实现将局部变量maxsize的值赋值给成员变量maxsize并对rear、front和queueArr[] 进行初始化
// 带参构造
public ArrayQueue(int maxsize){
// 将局部变量maxsize的值赋值给成员变量maxsize
this.maxsize = maxsize;
// 对rear、front和queueArr[] 进行初始化
rear = -1;
front = -1;
queueArr = new int[maxsize];
}
// 无参构造
public ArrayQueue(){
}
// 编写成员方法isFull(),用来判断队列是否满
public boolean isFull(){
// true : 满 false : 未满
return rear == maxsize - 1;
}
// 编写成员方法isEmpty(),用来判断队列是否为空
public boolean isEmpty(){
// true : 空 false : 不为空
return rear == front;
}
// 编写无返回值带参的成员方法,实现入队列addQueue(int num),类似于setXxx(形参列表)方法
public void addQueue(int num){
if(isFull()){
// 抛异常做处理,给提示文字
System.out.println("队列已满,不能实现入队列操作");
return;
}
queueArr[++rear] = num;
}
// 编写有返回值无参的成员方法,实现出队列getQueue(),类似于getXxx()方法
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("空队列,不能实现出队列操作");
}
return queueArr[++front];
}
// 编写成员方法,使用增强for循环 | 普通for循环遍历队列中的所有数据.
public void showQueue(){
if(isEmpty()){
System.out.println("空队列,没有数据可以遍历");
return;
}
/*for(int temp : queueArr){
System.out.print(temp + " ");
}*/
for(int i = 0;i < queueArr.length ; i++){
System.out.println("queueArr[" + i + "] = " + queueArr[i]);
}
}
// 编写成员方法,显示队列的第一个数据,注意:不是出队列
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("空队列,队列中没有数据");
}
return queueArr[front + 1];
}
}
问题及优化:
- 目前数组使用一次就不能使用了,没有达到复用的效果
- 将这个数组使用算法改进成环形队列的数组,核心是采用取模% 来实现的
总结:
- front 始终指向的是队列头的前一个位置,不是直接指向队列中的第一个数据,始终不包含队列中的第一个数据,front所指向的存储空间中始终没有数据。当rear 和front相等 时,front不包含队列中的任何数据,因为队列是空的,也无法实现出队列操作。
-
rear指向队列的尾部的具体的数据,包含队列的最后一个数据。当rear 和front相等 时,rear不包含队列中的任何数据,因为队列是空的。
画图分析:
- 判断队列是否满 ,取决于
rear
和maxsize
的关系rear == maxsize - 1
- 判断队列是否为空 ,取决于
rear
和front
的关系rear == front