博客主页:【小扳_-CSDN博客】
❤感谢大家点赞收藏⭐评论✍
文章目录
1.0 队列的说明
1.1 队列的几种常用操作
2.0 使用链表实现队列说明
2.1 链表实现队列
2.2 链表实现队列 – 入栈操作
2.3 链表实现队列 – 出栈操作
2.4 链表实现队列 – 获取队头元素操作(不删除)
2.5 链表实现队列 – 获取队列有效元素个数操作
2.6 链表实现队列 – 判空处理操作
2.7 用链表实现队列的完整代码
3.0 使用数组实现循环队列说明
3.1 数组实现循环队列的操作
3.2 数组实现循环队列 – 入队列操作
3.3 数组实现循环队列 – 出队列操作
3.4 数组实现队列 -得到队头元素操作(不删除)
3.5 数组实现队列 – 得到队尾元素操作(不删除)
3.6 数组实现队列 – 判空队列操作
3.7 数组实现队列 – 判满队列操作
3.8 用数组实现队列完整代码
1.0 队列的说明
队列是一种线性数据结构,具有先进先出(First In First Out,FIFO)的特性。它类似于排队的概念,新元素被添加到队列的尾部,而从队列中移除元素时则从队列的头部开始。队列通常用于需要按照特定顺序处理元素的场景,比如任务调度、消息传递等。
1.1 队列的几种常用操作
– 队首元素(front):队列的头部元素。
– 队尾元素(rear):队列的尾部元素。
– 入队(offer):将新元素添加到队列的尾部。
– 出队(poll):从队列的头部移除元素。
– 获取队头元素(peek):从队列的头部获取元素,不移除。
– 判空(isEmpty):判断队列是否为空。
– 判满(isFull):判断队列是否已满(对于有限大小的队列)。
– 元素个数(size):获取队列有效的元素个数。
接口代码如下:
public interface QueueInterface{/** * 入列 */boolean offer(int e);/** * 出列 */int poll();/** * 获取队列头元素 */int peek();/** * 获取队列中有效元素个数 */int size();/** * 检验队列是否为空 */boolean isEmpty();}
2.0 使用链表实现队列说明
使用链表实现队列,无疑就是用链表的数据结构的方式来实现队列的操作(实现队列的接口)。跟栈不同的是:栈只能对一端进行操作,而队列是对头尾进行操作。一般对于单链表来说,头节点当作队列中的队头(front),尾节点当作队列中的队尾(rear)。而入队列相当于尾插,在链表尾部插入节点,出队列相当于头删,在链表头部删除头节点。对于双向链表来说,就比较自由了,头节点既可以作为队头,也可以作为队尾。尾节点既可以作为队头,也可以作为队尾。
2.1 链表实现队列
用双向链表来实现队列,既然头尾都可以作为队列,选其中一种即可,对于队尾来说也是如此。这里就用头节点作为队列中的队头,而尾节点作为队列中的队尾。
简单分析:
– 实现入栈操作:在链表尾部插入节点即可。
– 实现出栈操作:在链表头部删除节点即可。
– 实现获取队列头部元素:获取链表头部节点的元素即可。
– 实现总计有效元素个数:需要定义一个成员变量 size ,入栈时进行 size++ ,出栈时 size–
– 实现判空处理:当 size == 0 ,则为空队列。
– 实现判断满队列:当 size >= 创建队列时默认大小,则为满队列。
2.2 链表实现队列 – 入栈操作
实现入栈操作:在链表尾部插入节点即可。分为两种情况:当队列为空时,则入栈的节点即是队头也是队尾;当队列不为空时,则入栈的节点一般来说就是新的队尾。每一次入栈完成后,都需要进行 size++ 。
代码如下:
//入列@Overridepublic boolean offer(int e) {if (isEmpty()) {front = rear = new Node(null,e,null);size++;return true;}Node node = new Node(rear,e,null);rear.next = node;rear = node;size++;return true;}
2.3 链表实现队列 – 出栈操作
实现出栈操作:在链表头部删除节点即可。出栈一般分为三种情况:
第一种情况,当队列为空时,不应该出栈了,直接返回 -1 或者抛异常。
第二种情况,当只有一个节点时,出栈之后,就不会再有元素了,所以 front 与 rear 需要置为空。返回出栈节点的值即可。
第三种情况,除了第一、二种情况之后,第三种情况就可以正常的进行头删节点操作处理了。需要注意的是,出栈完成后,进行 size– 。最后,返回出栈节点的数值即可。
代码如下:
//出列@Overridepublic int poll() {if (isEmpty()){return -1;}//注意特例:只有一个节点的情况if (front.next == null) {int temp = front.val;front = null;rear = null;return temp;}Node temp = front;front = front.next;front.prev = null;size--;return temp.val;}
2.4 链表实现队列 – 获取队头元素操作(不删除)
获取链表头部节点的元素即可。一般分为两种情况:当队列为空时,可以返回 -1 或者抛异常处理;当队列不为空时,直接返回头部节点的值即可。
代码如下:
@Overridepublic int peek() {if (isEmpty()) {return -1;}return front.val;}
2.5 链表实现队列 – 获取队列有效元素个数操作
直接返回 size 即可。
@Overridepublic int size() {return size;}
2.6 链表实现队列 – 判空处理操作
当 size == 0 时,返回 true 。否则返回 false 。也可以用 front == null 来判断是否为空队列。
代码如下:
@Overridepublic boolean isEmpty() {return front == null;}
2.7 用链表实现队列的完整代码
public class MyLinkedQueue implements QueueInterface {static class Node {public Node prev;public intval;public Node next;public Node(Node prev, int val, Node next) {this.prev = prev;this.val = val;this.next = next;}}private Node front;private Node rear;private int size;//入列@Overridepublic boolean offer(int e) {if (isEmpty()) {front = rear = new Node(null,e,null);size++;return true;}Node node = new Node(rear,e,null);node.prev = rear;rear.next = node;rear = node;size++;return true;}//出列@Overridepublic int poll() {if (isEmpty()){return -1;}//注意特例:只有一个节点的情况if (front.next == null) {int temp = front.val;front = null;rear = null;return temp;}Node temp = front;front = front.next;front.prev = null;size--;return temp.val;}@Overridepublic int peek() {if (isEmpty()) {return -1;}return front.val;}@Overridepublic int size() {return size;}@Overridepublic boolean isEmpty() {return front == null;}}
3.0 使用数组实现循环队列说明
用数组实现队列,一般来说是循环队列,循环队列可以解决普通队列在出队操作后产生的空间浪费问题,同时可以利用数组的固定大小来实现队列的循环利用。
循环队列的接口代码如下:
public interface QueueInterface{/** * 入列 */boolean offer(int e);/** * 出列 */int poll();/** * 获取队列头元素,不删除 */int peek();/** * 检验队列是否为空 */boolean isEmpty();/** * 判断是否为满队列 */boolean isFull();/** * 得到队尾元素,不删除 */int Rear();}
使用数组实现队列,无疑就是用数组的数据结构的方式来实现队列的操作(实现队列的接口)。循环队列的关键是使用两个指针来标记队列的头部和尾部,分别称为 front 和 rear 。当入队时,rear 指针向后移动;当出队时,front 指针向后移动。当 rear 指针到达数组的末尾时,可以通过取模运算将 rear 指针置为 0 ,实现循环的效果。
3.1 数组实现循环队列的操作
– 入队操作:将元素添加到 rear 指针所指向的位置,并更新 rear 指针。
– 出队操作:从 front 指针所指向的位置移除元素,并更新 front 指针。
– 判空操作:当 front 指针等于 rear 指针时,队列为空。
– 判满操作:当 (rear+1) % 数组长度等于 front 指针时,队列为满。
3.2 数组实现循环队列 – 入队列操作
将元素添加到 rear 指针所指向的位置,并更新 rear 指针。更新 rear 就是往后走一步,但是为了实现循环,可不能简单的进行 +1 处理,需要 rear = (rear + 1) % arr.length,这样就可以数组中循环走了。在入队前,需要先判断是否为满队列了。
代码如下:
// 入队列@Overridepublic boolean offer(int e) {if (isFull()) {return false;}arr[rear] = e;rear = (rear+1) % arr.length;return true;}
3.3 数组实现循环队列 – 出队列操作
从 front 指针所指向的位置移除元素,并更新 front 指针。同样的,更新可不能简单的 +1 处理,需要将 front = (front + 1) % arr.length ,每次出栈前需要记录一下出栈的元素,接着才往后走,最后返回记录的元素即可。出栈前,需要判断是否为空队列,如果为空队列,就需要抛异常或者返回 -1 处理。
代码如下:
//出队列@Overridepublic int poll() {if (isEmpty()) {return -1;}int temp = arr[front];front = (front + 1) % arr.length;return temp;}
3.4 数组实现队列 -得到队头元素操作(不删除)
先判断是否为空队列,若不是,则返回队头元素即可。
代码如下:
//得到队头元素,不删除@Overridepublic int peek() {if (isEmpty()) {return -1;}return arr[front];}
3.5 数组实现队列 – 得到队尾元素操作(不删除)
先判断队列是否为空,如果为空队列,则返回 -1 或者抛异常。如果不为空,则需要返回 arr[rear – 1],但是需要注意的是:有一种情况需要额外考虑进去,当 rear == 0 时,那么 rear – 1 == -1 ,所以不合理,数组中的索引不存在 -1 。因此这个情况要分开讨论,当 rear == 0 时,那么需要返回的值为 arr[arr.length – 1];当 rear != 0 时,那么返回的值为 arr[rear – 1] 。
代码如下:
//得到队尾元素,不删除@Overridepublic int Rear() {if (isEmpty()) {return -1;}int temp = (rear == 0) " />3.6 数组实现队列 - 判空队列操作
当且仅当 rear == front 时,则队列为空。
代码如下:
@Overridepublic boolean isEmpty() {return front == rear;}
3.7 数组实现队列 - 判满队列操作
有很多种方式可以来判断队列是否满,比如,定义 size 变量来总计元素个数,然后跟 arr.lengrh进行对比,相等即满队列了,不相等即为还没有满队列;使用标记也可以实现判断是否为满队列。
这里介绍牺牲空间来判断满队列,即当且仅当 (rear + 1) % arr.lengrh == front 时,该队列满了。由于这里牺牲了一个空间,所以需要在自定义初始化数组大小的时候额外 +1 。
代码如下:
// 自定义数组大小public ArrayQueue(int capacity) {arr = new int[capacity + 1];}// 默认数组大小为: 10public ArrayQueue() {arr = new int[10];}
@Override//判断是否为满队列(有很多种判断方法,这里使用牺牲空间方法来判断)public boolean isFull() {return (rear + 1) % arr.length == front;}
3.8 用数组实现队列完整代码
public class ArrayQueue implements QueueInterface{private int front;private int rear;private int[] arr;// 自定义数组大小public ArrayQueue(int capacity) {arr = new int[capacity + 1];}// 默认数组大小为: 10public ArrayQueue() {arr = new int[10];}// 入队列@Overridepublic boolean offer(int e) {if (isFull()) {return false;}arr[rear] = e;rear = (rear+1) % arr.length;return true;}//出队列@Overridepublic int poll() {if (isEmpty()) {return -1;}int temp = arr[front];front = (front + 1) % arr.length;return temp;}//得到队头元素,不删除@Overridepublic int peek() {if (isEmpty()) {return -1;}return arr[front];}//得到队尾元素,不删除@Overridepublic int Rear() {if (isEmpty()) {return -1;}int temp = (rear == 0) ? arr.length - 1 : rear - 1;return arr[temp];}@Overridepublic boolean isEmpty() {return front == rear;}@Override//判断是否为满队列(有很多种判断方法,这里使用牺牲空间方法来判断)public boolean isFull() {return (rear + 1) % arr.length == front;}}