Java队列
1.概念
队列是一种数据结构。队列的作用就像电影院前的人们站成的排一样:第一个进入窗口的人将最先到达队头买票。最后排队的人最后才能买到票。
2.特性
队列就是一个只允许在一端进行插入,在另一端进行删除操作的线性表。
先进先出(FIFO)
三个基本操作:
- 从尾部(rear)添加元素
- 从其(front)头部移除元素
- 在元素顶部查看
方法 | 描述 |
---|---|
boolean add(E e) | 如果可能,向队列中添加一个元素。否则,它抛出异常。 |
boolean offer(E e) | 如果不能添加元素,则将元素添加到队列中,而不抛出异常。 它在失败时返回false,在成功时返回true。 |
E remove() | 删除队列的头。如果队列为空,它会抛出异常。此方法返回已移除的项目。 |
E poll() | 从队列中删除元素。如果队列为空而不是抛出异常,则返回null。 |
Eelement() | 偷看队列的头,而不从队列中删除它。 如果队列为空,它会抛出异常。 |
E peek() | 查看队列,如果队列为空而不是抛出异常,则返回null。 |
3.分类
按照存储方式
- 基于数组的顺序存储方式
- 基于链表的链式存储方式
3.1 基于数组的顺序队列
简要理解:
顺序队列和栈的不同
- 栈:在同一端进栈出栈
- 顺序队列:在一端进行插入,在另一端进行删除操作
插入队列值
删除队列值
数据项被移除后,同时队头指针增加一。通常实现队列时,删除的数据项还会保存在内存中,只是它不能被访问了,因为队头指针已经移到它的下一个位置了。
假溢出
现象:
实现顺序队列时,是头front和尾rear分别进行出队和入队操作,当尾部插入速度小于头部删除速度时,出现rear==front的现象,但此时队列并没有满,而是队列为空,存储空间最大,但继续插入元素时,rear值已经到达MAXSIZE边界条件,此时无法插入也无法删除。
解决办法可以使用循环队列。循环队列在判断指针位置可以使用rear = (rear + 1) % this.maxSize;front = (front + 1) % this.maxSize;(示例代码中的添加与删除方法)。
- 循环队列的队满和队空
由于队满和队空条件都是front = rear,所以队满时损失一个空间。
示例代码:
import java.util.Arrays;
/**
* 顺序队列实现
*
* @Author swd
* @Create 2020/8/7 0007 16:17
*/
public class OrderQueue<T> {
private T[] datas; //数组模拟队列
private int maxSize; //队列元素个数
private int front; //队列中第一个对象位置
private int rear; //队列中当前对象位置
public OrderQueue(int maxSize) {
if (maxSize < 1) {
maxSize = 1;
}
this.maxSize = maxSize;
this.datas = (T[]) new Object[this.maxSize];//初始化数组必须放到上一行之后
this.front = 0;
this.rear = 0;
}
//队列的状态 队空 & 队满
public boolean isNull() {
if (this.front == this.rear)
return true;
else
return false;
}
public boolean isFull() {
if ((rear + 1) % this.maxSize == front)
return true;
else
return false;
}
//添加
public boolean offer(T data) {
if (isFull()) {
return false;//队满
} else {
this.datas[this.rear] = data;
this.rear = (this.rear + 1) % this.maxSize; //队尾指针 +1
return true;
}
}
//删除
public T poll() {
if (isNull()) {
return null;//队空
} else {
T pollData = this.datas[front];
this.front = (this.front + 1) % this.maxSize; //队头指针 +1
return pollData;
}
}
//get/set
public T[] getDatas() {
return datas;
}
public void setDatas(T[] datas) {
this.datas = datas;
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public int getFront() {
return front;
}
public void setFront(int front) {
this.front = front;
}
public int getRear() {
return rear;
}
public void setRear(int rear) {
this.rear = rear;
}
@Override
public String toString() {
return "OrderQueue{" +
"datas=" + Arrays.toString(datas) +
", maxSize=" + maxSize +
", front=" + front +
", rear=" + rear +
'}';
}
}
测试
public class TestResult {
public static void main(String[] args) {
OrderQueue<String> orderQueue = new OrderQueue<>(5);
System.out.println("初始化:" + orderQueue.toString());
System.out.println("队列是否为空:" + orderQueue.isNull());
orderQueue.offer("a");
orderQueue.offer("b");
orderQueue.offer("c");
orderQueue.offer("d");
orderQueue.offer("e");//循环队列会减少1个空间,此数据插入不了
System.out.println("插入数据:" + orderQueue.toString());
//OrderQueue{datas=[a, b, c, d, null], maxSize=5, front=0, rear=4}
System.out.println("队列是否已满:" + orderQueue.isFull());
System.out.println(orderQueue.poll());
System.out.println("删除1个数据:" + orderQueue.toString());
System.out.println(orderQueue.poll());
System.out.println("删除2个数据:" + orderQueue.toString());
System.out.println(orderQueue.poll());
System.out.println("删除3个数据:" + orderQueue.toString());
System.out.println(orderQueue.poll());
System.out.println("删除4个数据:" + orderQueue.toString());
System.out.println(orderQueue.poll());
System.out.println("删除5个数据:" + orderQueue.toString());
}
}
结果
3.2 基于链表的链式存储方式
简要理解:
- 插入队列值
- 删除队列值
示例代码
package test;
public class LinkQueue<T>{
private QNode<T> front;//队头指针
private QNode<T> rear;//队尾指针
private int maxSize;//为了便于操作,使用这个变量表示链队的数据容量
//初始化
public LinkQueue(){
this.front = new QNode<T>();
this.rear = new QNode<T>();
this.maxSize = 0;
}
//初始化队列
public void initQueue(){
front.next = null;
rear.next = null;
maxSize = 0;
}
//队空判断
public boolean isNull(){
if(front.next==null || rear.next==null)
return true;
else
return false;
}
//进队
public void push(QNode<T> node){
if(isNull()){
//第一次
front.next = node;
rear.next = node;
maxSize++;
}
else{
node.next = front.next;
front.next = node;
maxSize++;
}
}
//出队
public QNode<T> pop(){
if(isNull())
return null;//队为空时,无法出队
else if(maxSize==1){
//队只有一个元素时直接初始化即可
QNode<T> node = front.next;
initQueue();
return node;
}
else{
//准备工作
QNode<T> p = front;//使用p指针来遍历队列
for(int i=1;i<maxSize-1;i++)
p = p.next;
//pop
QNode<T> node = rear.next;
rear.next = p.next;
maxSize--;
return node;
}
}
}
//链队结点
class QNode<T>{
private T data;//数据域
public QNode<T> next;//指针域
//初始化1
public QNode(){
this.data = null;
this.next = null;
}
//初始化2
public QNode(T data){
this.data = data;
this.next = null;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
测试
package test;
import org.junit.Test;
public class testQueue {
@Test
public void fun(){
LinkQueue<Integer> lq = new LinkQueue<Integer>();
System.out.println("队列是否为空:"+lq.isNull());
//依次插入1、2、3、4
lq.push(new QNode<Integer>(1));
lq.push(new QNode<Integer>(2));
lq.push(new QNode<Integer>(3));
lq.push(new QNode<Integer>(4));
//依次出队
System.out.println("依次出队:");
while(!lq.isNull()){
System.out.println(lq.pop().getData());
}
}
}
参考文章:
作者:风之之
https://www.cnblogs.com/fzz9/p/8159679.html
https://baijiahao.baidu.com/s?id=1637126358227832423&wfr=spider&for=pc
谢谢O(∩_∩)O