🎉欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨
🎉感谢各位读者在百忙之中抽出时间来垂阅我的文章,我会尽我所能向的大家分享我的知识和经验📖
🎉希望我们在一篇篇的文章中能够共同进步!!!
🌈个人主页:AUGENSTERN_dc
🔥个人专栏:C语言 | Java | 数据结构
⭐个人格言:
一重山有一重山的错落,我有我的平仄
一笔锋有一笔锋的着墨,我有我的舍得
目录
1. 定义:
2. 队列的常用方法和模拟实现:
2.1 常用方法:
2.2 模拟实现:
3. 队列的模拟实现源码:
4. 循环队列
4.1 模拟实现:
5. 双端队列:
1. 定义:
队列和栈类似,是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表;
进入队列的一端称为队尾,离开队列的一端称为队头;
队列这个结构遵循先进先出的原则;
在日常生活中,例如:
多人在网上对老师提交任务时,会将我们所提交的任务存放到一个队列中,然后队列将这些任务按照先进先出的顺序进行出队和入队的操作,老师看到的任务,也就会按照提交时间的先后来排序;
由上图可以看出Queue是一个接口,底层是由链表(LinkedList)实现的;
2. 队列的常用方法和模拟实现:
2.1 常用方法:
方法 作用 offer(E e) 将e进行入队操作 E poll() 将e进行出队列操作,并且返回e的值
E peek() 获取队头元素 int size() 获取队列的长度 boolean isEmpty() 判断队列是否为空
(在队列的模拟实现中,我们并不使用泛型,而是使用整形来代替泛型)
以上就是队列的常用方法,接下来我们进行模拟实现:
2.2 模拟实现:
队列的底层是由链表来实现的,我们先创建一个My_Queue类:
public class My_Queue {public static class ListNode {ListNode next; //节点的后继ListNode prev; //节点的前驱int value; //节点的值public ListNode() {//不带参数的构造方法}public ListNode(int value){//带一个参数的构造方法,将节点的值赋为valuethis.value = value;}}ListNode first; //队头节点ListNode last; //队尾节点int size = 0; //队列长度
}
< 1 > offer方法:
offer方法是将指定元素插入到队列的队尾:
与之前的栈和顺序表不同,由于队列的底层是用链表实现的,故不需要判断队列是否满了;
// 入队列---向双向链表位置插入新节点public void offer(int e){ListNode newNode = new ListNode(e); //实例化一个节点if(first == null){ //若该队列为空first = newNode; //将队头和队尾都更新为newNodelast = newNode;}else{ //若队列不为空last.next = newNode; //将newNode赋值给队尾.nextnewNode.prev = last; //将newNode的pre赋值为队尾last = newNode; //将队尾更新为newNode}last = newNode; //更新队尾size++; //队列长度 +1
}
< 2 > poll方法:
poll方法是将队头的元素进行出队操作,并返回队头元素的值:
在进行该操作之前,我们需要判断队列是否为空,若为空,则需抛出异常:
异常代码如下:
public class QueueEmptyException extends RuntimeException {public QueueEmptyException () {super();}public QueueEmptyException (String str) {super(str);}
}
poll方法如下:
public int poll(){// 1. 队列为空// 2. 队列中只有一个元素----链表中只有一个节点---直接删除// 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除int value = 0;if(first == null){ //若为空,则抛出异常throw new QueueEmptyException("队列为空,不能进行poll操作!!!");}else if(first == last){ //若只有一个节点,则直接删除该节点last = null;first = null;}else{value = first.value; //将队头的元素赋值给valuefirst = first.next; //将队头更新为队头的下一个节点first.prev.next = null;first.prev = null;}size--; //将队列长度 -1return value; //返回队头的值
}
< 3 > peek方法:
peek方法是返回队头的节点的值:
// 获取队头元素---获取链表中第一个节点的值域public int peek(){if(first == null){ //若队列为空,则抛出异常throw new QueueEmptyException("队列为空,不能进行peek操作!!!");}return first.value; //返回队头的值
}
< 4 > size方法:
size方法是返回队列的长度:
public int size() {return size; //返回队列的长度
}
< 5 > isEmpty方法:
isEmpty是判断队列是否为空:
public boolean isEmpty(){return first == null; //返回队头是否为空 的值
}
3. 队列的模拟实现源码:
public class My_Queue {public static class ListNode {ListNode next; //节点的后继ListNode prev; //节点的前驱int value; //节点的值public ListNode() {//不带参数的构造方法}public ListNode(int value){//带一个参数的构造方法,将节点的值赋为valuethis.value = value;}}ListNode first; //队头节点ListNode last; //队尾节点int size = 0; //队列长度// 入队列---向双向链表位置插入新节点public void offer(int e){ListNode newNode = new ListNode(e); //实例化一个节点if(first == null){ //若该队列为空first = newNode; //将队头和队尾都更新为newNodelast = newNode;}else{ //若队列不为空last.next = newNode; //将newNode赋值给队尾.nextnewNode.prev = last; //将newNode的pre赋值为队尾last = newNode; //将队尾更新为newNode}last = newNode; //更新队尾size++; //队列长度 +1}// 出队列---将双向链表第一个节点删除掉public int poll(){// 1. 队列为空// 2. 队列中只有一个元素----链表中只有一个节点---直接删除// 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除int value = 0;if(first == null){ //若为空,则抛出异常throw new QueueEmptyException("队列为空,不能进行poll操作!!!");}else if(first == last){ //若只有一个节点,则直接删除该节点last = null;first = null;}else{value = first.value; //将队头的元素赋值给valuefirst = first.next; //将队头更新为队头的下一个节点first.prev.next = null;first.prev = null;}size--; //将队列长度 -1return value; //返回队头的值}// 获取队头元素---获取链表中第一个节点的值域public int peek(){if(first == null){ //若队列为空,则抛出异常throw new QueueEmptyException("队列为空,不能进行peek操作!!!");}return first.value; //返回队头的值}public int size() {return size; //返回队列的长度}public boolean isEmpty(){return first == null; //返回队头是否为空 的值}
}
4. 循环队列
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。
4.1 模拟实现:
/*解题思路:1. 注意,循环队列底层空间大小是固定的2. 采用计数方式实现队列空或者满的判断3. 入队列时:队列可能满,往队尾插入,注意back在末尾特殊情况4. 出队列时:队列可能空,删除队头元素,注意front可能在队尾5. 获取队头注意空队列时返回-16. 获取队尾时,注意back-1可能为负数,队尾元素下标:(back-1+array.length)%array.length
*/
class MyCircularQueue {int[] array;int front; // 队头int back; // 队尾int count; // 队列中有效元素个数public MyCircularQueue(int k) {array = new int[k];}public boolean enQueue(int value) {if(isFull()){return false;}// 在队尾插入一个元素,然后back往后移动array[back] = value;back++;// back往后移动之后,可能会来到空间末尾// 此时将back挪到空间起始位置if(back == array.length){back = 0;}count++;return true;}public boolean deQueue() {if(isEmpty()){return false;}// 出队列,队头往后移动++front;// 队头往后移动之后也可能会来到空间末尾// 此时需要挪到空间起始位置front %= array.length;--count;return true;}public int Front() {if(isEmpty()){return -1;}// 如果队列不空,说明队列中有元素,队头元素直接返回front即可return array[front];}public int Rear() {if(isEmpty()){return -1;}// 如果队列不空,说明队列中有元素// 队尾元素即:back-1,// 如果back不在0号位置,back-1就是队尾元素下标// 如果back在0号位置,-1之后就是负数,因此需要+数组长度// 两个结合起来:return array[(back - 1 + array.length)%array.length];}public boolean isEmpty() {return 0 == count;}public boolean isFull() {return count == array.length;}
}
5. 双端队列:
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Deque是一个接口,使用时必须创建LinkedList的对象。
以上就是队列的全部内容:感谢观看!!!!
制作不易,三连支持谢谢!!!
以上的模拟实现代码未必是最优解,仅代表本人的思路,望多多理解,谢谢!!
最后送给大家一句话,同时也是对我自己的勉励:
知不足而奋进,望远山而前行!!!!