什么是队列?
队列是一种固定大小的有序列表,它的特点是先进先出。
队列有四个重要参数,【头】【尾】【最大长度】【数据区】
在 Java 中的声明方式:
当队列构建完成以后,队尾和队首同时指向 地址 1 ,当向队列插入数据时,队尾向后移动,直至队尾等于 maxSize时 ((全文:队首、队尾初始值为 0),maxSize = 5) 队列已满,我们便无法再向队列插入数据
每当我们取出一个数据,队首就向后移动一个地址,直至 队首等于队尾,所有数据取完,队列为空。
根据上面的分析,我们可以知道,当队尾 = 队首时 队列为空,当 队尾 = maxSize 时,队列已满。
这是一个传统的队列,每当我们取出一个数据,队列的可用空间就会失去一个,也就是说,这个队列只能使用一次。
那么如何让队列空间可以重复利用呢?
循环队列它来了!循环队列是通过一定的算法,将一个线性队列看作一个环,使得这个队列空间可以重复利用的数据结构。
循环队列,理解上可以将它理解成一个环,但它实际还是一个线性队列,只是再传统队列的基础之上通过算法,使它的空间可以重复利用。
在环形队列中,我们无法再像传统队列那样,使用队尾 = maxSize 来判断队列是否已满。
所以,为了能够判断队列是否已经存储满,我们需要浪费掉一个空间来判断是否已满。而这个空间,始终是队尾的后一个空间。而这个判断条件就是,浪费掉的空间 取模 maxSize 是否等于队首,队尾的值,始终取 队尾%maxSize
即 (rear+1)% 8 == front | rear = rear%8
为了理解,这里做出几个数据假设:
假设 队首(front) 队尾(rear)maxSize = 8
下表是填充数据不取出的情况
队尾(rear) | 浪费掉的空间(rear+1)% maxSize | 队首(front) | 队列是否已满(T/F) |
0 | 1 | 0 | F |
1 | 2 | 0 | F |
2 | 3 | 0 | F |
.... | .... | .... | .... |
7 | 0 ( 8 % 8) | 0 | T |
填充,并取出两个数据即 队首 = 2 (取出0,1两个地址的数据后,队首的位置)
队尾(rear) | 浪费掉的空间(rear+1)% maxSize | 队首(front) | 队列是否已满(T/F) |
7 | 0 | 2 | F |
8 | 1 ( 8+1 = 9 % 8 ) | 2 | F |
1 | 2 (1+1 = 2 % 8) | 2 | T |
ok,我们总结一下,传统队列和循环队列,空,满时的条件
空 | 满 | |
传统队列 | front = rear | rear = maxSize |
循环队列 | front = rear | front = (rear+1)%maxSize |
在传统队列中,队首和队尾的取值最大为maxSize ,而循环队列中,队首和队尾的取值都是在 %maxSize 进行一个循环 即(rear % 8 ,front%8)
最后:书写不易,多多支持!附上代码:
传统队列
package com.uxteam.data;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/*
* 队列: 队列是一种先进先出的线性表,他只允许从尾部插入数据,头部删除数据,通常由链表或数组实现
*
* */
public class ArrayQueue {
// 队列的最大长度
private int maxSize;
// 队列头部位置
private int front;
// 队列尾部位置
private int rear;
// 队列数据存储区域
private int[] data;
public ArrayQueue(int maxSize){
init(maxSize);
}
// 初始化队列数据
private void init(int maxSize){
this.maxSize = maxSize;
this.front = 0;
this.rear = 0;
this.data = new int[maxSize];
}
/**
* 判断队列是否为空
* @return true / false
*/
// todo 判断队列是否为空 -- 完成
public boolean isEmpty(){
return rear - front == 0;
}
/***
* 判断队列是否已满
* @return true / false
*/
// todo 判断队列是否已满 -- 完成
public boolean isFull(){
return rear == maxSize;
}
// todo 向队列插入元素 -- 完成
public void insert(int ele){
// 如果队列已满,抛出异常
if (isFull()){
throw new RuntimeException("队列已满");
}
this.data[rear++] = ele;
}
// todo 从队列删除元素 -- 完成
public int remove(){
// 如果队列是空,抛出异常
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return this.data[front++];
}
// todo 显示队列所有元素 -- 完成
public void list(){
List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
System.out.println(collect.subList(front,rear));
}
// todo 显示队列头部元素 -- 完成
public int first(){
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return this.data[front];
}
}
循环队列
package com.uxteam.data;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CircleQuque {
/***
* 环形队列最大容量
*/
private int maxSize;
/***
* 队首位置
*/
private int front;
/***
* 队尾位置
*/
private int rear;
/***
* 数据区
*/
private int[] data;
/***
* 队列构造器
* @param maxSize 队列最大容量
*/
public CircleQuque(int maxSize){
init(maxSize);
}
/***
* 初始化内部参数
* @param maxSize 队列最大容量
*/
private void init(int maxSize){
this.maxSize = maxSize;
this.front = 0;
this.rear = 0;
this.data = new int[maxSize];
}
// todo 判断队列是否为空
/***
* 判断队列是否为空
* @return true / false
*/
public boolean isEmpty(){
return front == rear;
}
// todo 判断队列是否已满
/***
* 判断队列是否已满
* @return true / false
*/
public boolean isFull(){
return (rear+1)%maxSize == front;
}
// todo 向队列添加元素
/***
* 向队列添加元素
* @param ele 要添加的元素
*/
public void insert(int ele){
// 判断队列是否已满
if (isFull()){
System.out.println("队列已满!");
return;
}
// 插入元素,队尾后移
this.data[rear] = ele;
rear = (rear+1) % maxSize;
}
// todo 从队列取出元素
/***
* 从队列取出元素
* @return 取出的元素
*/
public int remove(){
// 判断队列是否为空
if (isEmpty()){
throw new RuntimeException("队列为空");
}
// 返回队首数据,队首后移
int remove = this.data[front];
front = (front+1) % maxSize;
return remove;
}
// todo 显示队列中所有元素
/***
* 显示队列中所有元素
*/
public void list(){
List<Integer> collect = Arrays.stream(this.data).boxed().collect(Collectors.toList());
if (rear < front){
System.out.println(collect.subList(0,rear));
System.out.println(collect.subList(front,maxSize));
}else {
System.out.println(collect.subList(front,rear));
}
}
// todo 显示队列首元素
/***
* 显示队列首元素
* @return 队列首元素
*/
public int first(){
// 判断队列是否为空
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return this.data[front];
}
}