1. 什么是队列?
-
队列的定义:
队列是一种操作受限的线性表,是指只允许在表的一端进行插入操作的数据结构
-
队列的特点:
-
队列是一种先进先出(FIFO)的顺序结构。先存入的数据先取出,后存入的数据后取出。
-
在队尾插入元素,在队头删除元素
-
2. 队列的分类
-
顺序队列:
- 用数组(顺序存储结构)实现的队列称为顺序队列
- front 指向队列第一个元素的前一个位置
- rear 指向队列的最后一个元素的位置
- 有效数据个数 = rear - front
-
循环队列:
- 顺序队列的优化版,可以解决顺序队列的“假溢出现象”。
- front 指向队列的第一个元素
- rear 指向队列的最后一个元素的后一个位置
- 有效数据个数 = (rear + capacity - front) % capacity
-
链队列:
- front 指向队列的第一个元素
- rear 指向队列
用链表(链式存储结构)实现的队列称为链队列
-
顺序队列和链队列的区别:
- 顺序队列一次性要分配大量保证够用的空间,效率较高,因为是基于数组的,长度也是固定的。所以可能会发生”假溢出现象“,解决方法就是将队列的数据区看成头尾相连的循环结构,称为”循环队列“
- 链队列是基于链表的,要动态创建和删除节点,效率较低,但是可以动态增长
3. 顺序队列实现代码
//顺序队列
public class ArrayQueue {
//模拟 c语言 中的头指针
private int front;
//模拟 c语言 中的尾指针
private int rear;
//初始化数组的最大容量
private int capacity;
//存放数据的数组,(可以存任何类)
private Object[] arr;
/**
* 通过有参构造创建顺序队列
* @param capacity 容量大小
*/
public ArrayQueue(int capacity) {
this.capacity=capacity;
this.arr=new Object[capacity];
//指向队列头部第一个数据的前一个位置,初始值为 -1
this.front=-1;
//指向队列尾部,初始值为 -1
this.rear=-1;
}
/**
* 判断队列是否满了
* @return 返回布尔值(满 or 未满)
*/
public boolean isFull(){
return rear==capacity-1;
}
/**
* 判断队列是否为空
* @return 返回布尔值(空 or 非空)
*/
public boolean isEmpty(){
return front==rear;
}
/**
* 入队列
* @param obj 所以存放的数据
*/
public void add(Object obj){
//先判断队列是否满了
if (isFull()) {
System.out.println("队列已满,不能再添加数据...");
}else {
// ++rear 是让尾指针后移一位,并且可以作为数组的下标
arr[++rear]=obj;
}
}
/**
* 出队列
* @return 返回出队的数据
*/
public Object poll(){
//先判断队列是否为空,空的话则不能取出数据
if (isEmpty()) {
//有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
throw new RuntimeException("队列为空,不能取出数据...");
}else {
//返回出队的数据
return arr[++front];
}
}
/**
* 显示队列的所有数据
*/
public void show(){
//判断队列是否为空
if (isEmpty()) {
System.out.println("队列为空...");
}else {
for (int i = front+1; i < rear+1; i++) {
System.out.print(arr[i]+"\t");
}
}
}
/**
* 查看队列的第一个数据,不是出队
* @return 队列的第一个数据
*/
public Object head(){
//判断队列是否为空
if (isEmpty()) {
//有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
throw new RuntimeException("队列为空...");
}else {
return arr[front+1];
}
}
}
4. 循环队列的实现代码
//循环队列
public class CircleQueue {
//模拟 c语言 中的头指针
private int front;
//模拟 c语言 中的尾指针
private int rear;
//初始化数组的最大容量
private int capacity;
//存放数据的数组,(可以存任何类)
private Object[] arr;
/**
* 通过有参构造创建顺序队列
* @param capacity 容量大小
*/
public CircleQueue(int capacity) {
this.capacity=capacity;
//在队列尾部预留一个空间,形成约定
this.arr=new Object[capacity+1];
//指向队列头部的第一个数据,初始值为 0
this.front= 0;
//指向队列尾部最后一个数据的后一个位置,初始值为 0
this.rear = 0;
}
/**
* 判断队列是否满了
* @return 返回布尔值(满 or 未满)
*/
public boolean isFull(){
//只有当头指针和尾指针紧挨着时,队列才是满的(想一下环形结构)
return (rear+1)%(capacity+1)==front;
}
/**
* 判断队列是否为空
* @return 返回布尔值(空 or 非空)
*/
public boolean isEmpty(){
return front==rear;
}
/**
* 入队列
* @param obj 所以存放的数据
*/
public void add(Object obj){
//先判断队列是否满了
if (isFull()) {
System.out.println("队列已满,不能再添加数据...");
}else {
// 直接将数据加入
arr[rear]=obj;
//将尾指针后移一位,为下次入队做准备
rear = (rear+1)%(capacity+1);
}
}
/**
* 出队列
* @return 返回出队的数据
*/
public Object poll(){
//先判断队列是否为空,空的话则不能取出数据
if (isEmpty()) {
//有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
throw new RuntimeException("队列为空,不能取出数据...");
}else {
//用临时变量保存要出队的数据
Object target = arr[front];
//将头指针后移一位,为下次出队做准备
front = (front+1)%(capacity+1);
//返回要出队的数据
return target;
}
}
/**
* 显示队列的所有数据
*/
public void show(){
//判断队列是否为空
if (isEmpty()) {
System.out.println("队列为空...");
}else {
//利用 size()方法求出有效数据个数,这样就知道应该遍历几次了
for (int i = front; i < front + size(); i++) {
System.out.print(arr[i]+"\t");
}
}
}
/**
* 查看队列的第一个数据,不是出队
* @return 队列的第一个数据
*/
public Object head(){
//判断队列是否为空
if (isEmpty()) {
//有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
throw new RuntimeException("队列为空...");
}else {
return arr[front];
}
}
/**
* 求循环队列的有效数据个数
* @return 有效数据个数
*/
public int size(){
return (rear+(capacity+1)-front)%(capacity+1);
}
}