1 .概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)
![](https://i-blog.csdnimg.cn/blog_migrate/1a8852673a4a7890ad4e8841b3821752.png)
2 .队列的方法
![](https://i-blog.csdnimg.cn/blog_migrate/21a0d000782725c917f25ff675c39df8.png)
3.队列的实现(这里我们使用单链表来实现队列)
package Queue;
//用单链表实现队列
public class MyQueue {
//队列是:先进先出(头删尾插)
static class Node{
public int val;
public Node next;
public Node(int val){
this.val=val;
}
}
public Node head;
public Node last;
public int usedSize;
//入队
public void offer(int val){
Node node=new Node(val);
if(head==null){
head=node;
}else{
last.next=node;
}
last=node;
usedSize++;
}
//出队
public int poll(){
//此处得判断此时队列是否为空
if(isEmpty()){
return -1;// 一般这里得抛异常,但是在牛客或力扣上等写返回值-1
}
int ret=head.val;
head=head.next;
usedSize--;
return ret;
}
private boolean isEmpty(){
return usedSize==0;
}
//获取队首元素
public int peek(){
//此处得判断此时队列是否为空
if(isEmpty()){
return -1;// 一般这里得抛异常,但是在牛客或力扣上等写返回值-1
}
return head.val;
}
//获取队列长度
public int getUsedSize(){
return usedSize;
}
}
4 循环队列
实际中我们有时还会使用一种队列叫循环队列,环形队列通常使用数组实现。
![](https://i-blog.csdnimg.cn/blog_migrate/2459c90cdd23351d966dc737f032115c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e6f40118746d77f7b07128f978f79505.png)
数组下标循环:rear=(rear+1)%数组.length
此处目的是让下标可以从7到0下标出,以此来达到循环效果
如何判断队列是否为满
1:使用usedSize来记录队列长度,以此来判断是否为满
2:牺牲一个空间,通过rear+1(此处表示牺牲的数组空间下标)与数组长度求模来判断是否与front相等,相等则为 满,反之不满。
package Queue;
public class MyCircularQueue {
//设计循环队列[先进先出]
//这里用数组来实现
private int[] elem;//定义一个数组
private int front;//用来表示队列的头
private int rear;//用来表示队列的尾
public MyCircularQueue(int k) {
this.elem = new int[k + 1];//这里我们是牺牲一个空间来做的,因此K+1来多给一个空间
}
//入队列
public boolean enQueue(int value) {
//1.检查队列是否为满
if (isFull()) {
return false;
}
elem[rear] = value;
//rear++;
// [此处不能是rear++,因为该数组为循环数组,如果使用rear++时,当rear走到elem.length-1时,就不能走到0下标位置]
rear = (rear + 1) % elem.length;
return true;
}
//出队列
public boolean deQueue() {
if (isEmpty()) {
return false;
}
front = (front + 1) % elem.length;
return true;
}
//头元素
public int Front() {
if (isEmpty()) {
return -1;
}
return elem[front];
}
//尾元素
public int Rear() {
if (isEmpty()) {
return -1;
}
int index = (rear == 0) ? (elem.length - 1) : (rear - 1);
//此处为rear-1时因为我们牺牲一个空间来表示在是否为满,
// 而rear时那个数组空间的下标因此求尾元素等让rear-1
return elem[index];
}
//判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
//判断队列是否为满
public boolean isFull() {
//【这里有两种方法 1:加一个usedSize来表示数组长度,当长度等于k即表示满了
// 2:牺牲一个数组空间,通过rear+1(此处表示牺牲的数组空间下标)与数组长度求模来判断是否与front相等,
// 若相等即表示满了,反之没有满[这里我们使用第二种方法]】
/*if((rear+1)%elem.length==front){
return true;
}
return false;*/
return (rear + 1) % elem.length == front;
}
}
5. 双端队列 (Deque)
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
![](https://i-blog.csdnimg.cn/blog_migrate/b0e3fc293d7576eeed172cd2139120f2.png)
使用Deque接口是比较多的,栈和队列均可以使用该接口
Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现 (数组实现的双端列)
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现 (链表实现的双端队列)
Queue<Integer> queue =new LinkedList<>();//队列
LinkedList<Integer> stack =new LinkedList<>();//队列栈 (双向链表实现的栈)
List<Integer> list =new LinkedList<>();//双向队列
注意:在队列中,offerFirst()方法优于addFirst()方法,因为add方法无法插入元素时,会抛异常【一般情况下我们使用offerFirst()方法会比较多】