文章目录
Queue队列
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

队列中既然可以存储元素,那底层肯定要有能够保存元素的空间,通过我之前的文章了解到常见的空间类型有两种:顺序结构(ArrayList)和链式结构(LinkedList)(双向链表)。
单向队列自我实现
public class Mysqueue {
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;
last=node;
}else {
last.next=node;
last=node;
}
usedSize++;
}
//出队
public int poll(){
if (!Empty()){
throw new EmptyEixception("队列为空");
}
int ret= head.val;;
head=head.next;
//判断出一个节点,head和last都为空
if (head==null){
last=null;
}
usedSize--;
return ret;
}
private boolean Empty(){
return usedSize==0;
}
public int peek(){
if (!Empty()){
throw new EmptyEixception("队列为空");
}
return head.val;
}
public int getUsedSize(){
return usedSize;
}
}
双端队列 (Deque)
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

双端对列的实现其实与单向队列的实现差别不大,主要是增加了头出队和尾入队的功能,无论对于用链表实现还是顺序表实现,都可以。
这里我用我继续用链表实现头的入队和出队:
//头入队
public void offerFirst(int val){
Node node=new Node(val);
if (head==null){
head=node;
last=node;
}else {
last.next=node;
last=node;
}
usedSize++;
}
//头出队
public void pollFirst(){
if (head==null){
return;
}else {
head=head.next;
}
usedSize--;
}
这里我用我继续用链表实现尾的入队和出队:
public int pollLast(){
if (!Empty()){
throw new EmptyEixception("队列为空");
}
int ret= head.val;;
head=head.next;
//判断出一个节点,head和last都为空
if (head==null){
last=null;
}
usedSize--;
return ret;
}
public void offerLast(int val){
Node node=new Node(val);
if (last==null){
return ;
}else {
last.next=node;
last=node;
}
}
循环队列
生产者消费者模型时可以就会使用循环队列,什么是生产与消费者模型呢?这个主要是在多线程中会有体现,这个模型可以理解为,一个生产猫罐头的车间,这个我称呼它为生产者,而猫就是这个罐头的消费者,问题来了,一个车间的生产效率是一定的,猫的数量看增长情况。而为了使效率最大化,一个循环的车间就必不可少。理解成数据结构中的循环队列就可。

其实大家可以看见,对于此模型在队头和队尾中间有个空白格。这其实就涉及到循环队列的两种实现方法。而这个图片就是其中一个实现方法。这里我先不说,请看下面的。
首先我们先思考一个问题。需要用什么结构进行实现?队列的实现方式无非就是顺序表或者是链表。若是使用链表的话,我们只需要保证(尾节点)last.next存储(头结点)head的位置信息就可以保证相连。那么如果用顺序表又该如何实现呢?
如果使用顺序表,那么就要明确一个概念就是。如何确定结构中元素是满的?实际上在内存中,是没有这个环状的存储模型,这个只是我们需要设计成这样,我们需要用逻辑去将下面的顺序表用逻辑去实现上面的图。

其实我们在这里就可以设置一个双指针针,一个指针保持在头的位置,还有一个指针随着填充的元素不断向后。很好,问题又出现了,假设整个数组已经满了,那么如果这个指针再往后面移动,那么就会爆出空指针异常,为了应对这个情况。此时就出现了两种方式,一种是通过取余的方式获取两个指针之间的位置。而这种方式呢,我们就需要用一个空余一个位置来防止。指针出现超出的情况。 还有一种呢,就是通过记录元素个数来判断。
这里呢,我们选择一种较为难的方式来进行实现,也就是取余的方式。其实取余呢,就是在循环。大家手中有纸笔的话,可以去尝试做一件事情就是假设的一个变量对四进行取值余,我们从1开始。到时结束我们会发现。其实在4这个范围内循环了两次半。

视频:
循环队列添加元素
而删除的操作就是将last的位置向前移动,就可以将这个元素进行删除,如果要进行锁定删除,那么就需要去查找这个元素的所在位置。
循环队列的实现
这里我将我所实现的代码进行上传。
public class MyCircularQueue {
private int[] elem;
private int front;//队列的头
private int rear;//队列的尾
//浪费空间就得+1
public MyCircularQueue(int k) {
this.elem=new int[k+1];
}
//添加元素
public boolean enQueue(int value) {
if (isFull()){
return false;
}
elem[rear]=value;
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;
return elem[index];
}
public boolean isEmpty() {
return front==rear;
}
//检查队列是否为满
public boolean isFull() {
if ((rear+1)%elem.length==front){
return true;
}
return false;
}
}
问题:
- 用什么结构进行构造?
- 无论是链表还是顺序表都是线性结构,如何让他们循环起来?
- 如何判断是否满了?
答:
- 链表或顺序表都可以,但这里我用的是顺序表
- 可以通过三种方式,
第1种,通过取余的方式获取循环的位置。
第2种,通过记录元素个数。来判断元素指针所达到的位置。
第3种,通过标记位置来判断。
这里我通过的是取余的方式获取循环位置。 - 通过两种方式。
第1种。通过记录元素个数来达到数组容量。
第2种就是。在设置的数组容量之上加一个空白来判断末尾。
小结
- 实际java中双端队列提供了两种。(常用),单向列的功能,双端都有。。。
Deque stack = new ArrayDeque<>();//双端队列的线性实现
Deque queue = new LinkedList<>();//双端队列的链式实现 - Deque的队列是实际上是接口,需要具体实例化
- 数据结构中最重要的是思路以及方法,具体实现功能其实在库中已有。所以学会这种处理模式才是终身受益。
十一、其他文章接口
1.String方法(重要,对于操作字符串有巨大的帮助)
2.java常用的接口及其方法(包含拷贝,比较,排序,构造器)
3.初阶数据结构
3.1 顺序表:ArrayList
3.2 链表:LinkedList
3.3 栈:Stack
3.4 队列:Queue
3.5 二叉树:Tree
3.6 优先级队列:PriorityQueue(堆排序)
3.7 Map和Set
HashMap和HashSet,TreeMap和TreeSet
文章链接
4. 排序(7种方式)
4.1 插入排序(两种)
4.2 选择排序(两种)
4.3 快速排序
4.4 堆排序
里面有堆排序的实现和逻辑
文章链接
文章介绍了Java中队列的基本概念,包括普通队列、双端队列(Deque)和循环队列的实现,提供了链表和数组两种结构的示例代码。此外,提到了String方法的重要性以及多种排序算法和数据结构如栈、二叉树、优先级队列和Map与Set的相关内容。
1067





