队列知识及编程练习总结
目录
一、背景知识
二、队列的应用
(一)在Spring中的应用
(二)在其他框架中的应用
(三)在实际开发中的应用
三、相关编程练习
(一)用队列实现栈
(二)使用栈实现队列
(三)设计循环队列
(四)滑动窗口最大值
(五)课程表
(六)队列的最大值
(七)用数组实现一个队列
一、背景知识
队列是一种常见的数据结构,其特点是先进先出(First-In-First-Out,FIFO),也就是最先入队的元素最先出队。队列可以用来实现任务调度、缓存、消息传递等应用场景。
队列通常有两个基本操作:入队(enqueue)和出队(dequeue)。入队操作将一个元素加入队列的尾部,出队操作将队列头部的元素移除并返回其值。队列还有一个获取队头元素但不移除的操作(peek)。
队列有多种实现方式,包括数组实现和链表实现。数组实现的队列通常需要指定一个固定的容量,而链表实现的队列可以动态增长。
队列还有一些变种,如双端队列(deque)和优先队列(priority queue)。双端队列支持在队头和队尾进行插入和删除操作,优先队列中元素按照一定的优先级顺序出队。
总的来说,队列的基本操作包括:
- 入队(enqueue):将一个元素加入队列的尾部。
- 出队(dequeue):将队列头部的元素移除并返回其值。
- 获取队头元素但不移除(peek):返回队列头部的元素值,但不将其移除。
- 判断队列是否为空(isEmpty):如果队列中没有元素则返回 true,否则返回 false。
- 判断队列是否已满(isFull):如果队列已满则返回 true,否则返回 false。但是对于链表实现的队列来说,不需要判断队列是否已满,因为链表的长度是动态变化的。(对于数组实现的队列而言才有这个操作)
除了这些基本操作之外,队列的具体实现还可以包括其他的一些操作,例如扩容、缩容等。
按照以上的背景,展示举例:队列的大致流程就像是往管道中一个一个地放入小球,然后小球从管道前头一个个出来。(图来自图灵社区)
二、队列的应用
(一)在Spring中的应用
在 Spring 框架中,队列主要用于异步消息处理,其中的应用包括:
- Spring JMS(Java Message Service):Spring JMS 可以使用 JMS 队列实现异步消息处理。消息生产者将消息发送到队列中,消息消费者从队列中获取消息并进行处理。
- Spring AMQP(Advanced Message Queuing Protocol):Spring AMQP 是 Spring 对 AMQP 消息协议的支持,可以使用 AMQP 的队列实现异步消息处理。与 JMS 相比,AMQP 具有更强的消息路由和交换机管理能力。
- Spring Integration:Spring Integration 提供了丰富的消息通道和消息处理器,可以使用队列实现异步消息处理。
- Spring Batch:Spring Batch 是 Spring 提供的批处理框架,其中的 JobLauncher 实现了异步任务处理,使用了内部的任务队列进行任务调度。
总的来说,Spring 框架中队列的应用主要涉及异步消息处理,其背后的思想是将任务分发给多个线程或者处理器,提高任务的处理效率和并发能力。
(二)在其他框架中的应用
除了 Spring 框架,队列在其他一些框架中也有广泛的应用,例如:
- Apache Kafka:Apache Kafka 是一个分布式消息队列,被广泛用于大规模数据流处理和实时数据管道。它提供高可用、高可靠的消息传输服务,支持多个消费者和分区,同时还具有高性能和可扩展性。
- RabbitMQ:RabbitMQ 是一个 AMQP 实现,支持多种消息队列模式,包括点对点、发布/订阅和路由等。它具有高可用、高可靠性和高性能,支持多种客户端语言和多种平台。
- Redis:Redis 是一个内存中的数据结构存储系统,可以使用 Redis List 实现队列。它支持数据持久化、集群和复制,同时还支持多种数据结构操作和多种客户端语言。
- ActiveMQ:ActiveMQ 是一个开源的 JMS 实现,支持多种消息队列模式,包括点对点、发布/订阅和通配符等。它具有高可用、高可靠性和高性能,同时还支持多种客户端语言和多种平台。
总的来说,队列在分布式系统和大规模数据处理中扮演着重要的角色,被广泛应用于消息传输、任务调度、数据流处理等场景。
(三)在实际开发中的应用
在实际开发工作中,队列可以应用于多个场景,例如:
- 异步任务处理:当系统需要执行大量耗时的任务时,可以将任务放入队列中,由多个工作者线程异步地处理任务,从而提高系统的并发能力和性能。
- 消息队列:当系统需要在多个进程或者机器之间传递消息时,可以使用消息队列。生产者将消息放入队列中,消费者从队列中获取消息并进行处理,从而实现不同进程或者机器之间的异步通信。
- 数据流处理:当系统需要处理大规模的数据流时,可以使用队列将数据分配给多个处理节点进行处理。例如,将用户行为日志放入队列中,由多个处理节点进行数据分析和挖掘。
- 任务调度:当系统需要执行周期性的任务时,可以使用队列进行任务调度。将任务放入队列中,由任务调度器定时执行任务,并将执行结果返回给系统。
- 网络流量控制:当系统需要控制网络流量时,可以使用队列进行流量控制。例如,将网络请求放入队列中,限制同时处理请求的数量,从而避免系统崩溃。
总的来说,队列在实际开发工作中应用广泛,涉及任务调度、消息传输、数据处理等多个场景,可以提高系统的并发能力和性能,提高系统的可靠性和稳定性。
三、相关编程练习
(一)用队列实现栈
与栈知识及编程练习总结_张彦峰ZYF的博客-CSDN博客中练习三(五)相同,请直接跳转阅读。
(二)使用栈实现队列
与栈知识及编程练习总结_张彦峰ZYF的博客-CSDN博客中练习三(四)相同,请直接跳转阅读。
(三)设计循环队列
题目描述:设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
- MyCircularQueue(k): 构造器,设置队列长度为 k 。
- Front: 从队首获取元素。如果队列为空,返回 -1 。
- Rear: 获取队尾元素。如果队列为空,返回 -1 。
- enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
- deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
- isEmpty(): 检查循环队列是否为空。
- isFull(): 检查循环队列是否已满。
示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1); // 返回 true
circularQueue.enQueue(2); // 返回 true
circularQueue.enQueue(3); // 返回 true
circularQueue.enQueue(4); // 返回 false,队列已满
circularQueue.Rear(); // 返回 3
circularQueue.isFull(); // 返回 true
circularQueue.deQueue(); // 返回 true
circularQueue.enQueue(4); // 返回 true
circularQueue.Rear(); // 返回 4提示:
- 所有的值都在 0 至 1000 的范围内;
- 操作数将在 1 至 1000 的范围内;
- 请不要使用内置的队列库。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/design-circular-queue
解题思路
比较常见的实现方式,使用一个数组和两个指针 front 和 rear 分别指向队列的头部和尾部,同时使用一个变量 size 维护队列中元素的个数,在 enQueue() 和 deQueue() 方法中,需要将指针向后移动一位,并使用取模操作保证指针不会越界。在 enQueue() 方法中,还需要注意特殊情况,即当队列为空时,需要将 front 指向插入的元素。
这个实现方式的时间复杂度为O(1)。
具体代码展示
package org.zyf.javabasic.letcode.queue;/*** @author yanfengzhang* @description 设计你的循环队列实现。* 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。* <p>* 循环队列的一个好处是我们可以利用这个队列之前用过的空间。* 在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。* 但是使用循环队列,我们能使用这些空间去存储新的值。* @date 2023/4/9 14:58*/
public class MyCircularQueue {/*存储队列元素的数组*/private int[] data;/*队头指针,指向队头元素*/private int front;/*队尾指针,指向队尾元素的下一个位置*/private int rear;/*队列中元素的个数*/private int size;public MyCircularQueue(int k) {/*初始化数组*/data = new int[k];/*初始时队头指针指向 -1*/front = -1;/*初始时队尾指针指向 -1*/rear = -1;/*初始时队列中元素个数为 0*/size = 0;}public boolean enQueue(int value) {/*队列已满,插入失败*/if (isFull()) {return false;}/*队列为空,需要将 front 指向插入的元素*/if (isEmpty()) {front = 0;}/*队尾指针向后移动一位,并使用取模操作保证指针不会越界*/rear = (rear + 1) % data.length;/*在队尾插入元素*/data[rear] = value;/*队列中元素个数加一*/size++;/*插入成功*/return true;}public boolean deQueue() {/*队列为空,删除失败*/if (isEmpty()) {return false;}/*队列中只有一个元素,需要将 front 和 rear 指向 -1*/if (front == rear) {front = -1;rear = -1;}/*队列中有多个元素,需要将 front 指针向后移动一位*/else {/*队头指针向后移动一位,并使用取模操作保证指针不会越界*/front = (front + 1) % data.length;}/*队列中元素个数减一*/size--;/*删除成功*/return true;}public int Front() {if (isEmpty()) {/*队列为空,返回 -1*/return -1;}/*返回队头元素*/return data[front];}public int Rear() {/*队列为空,返回 -1*/if (isEmpty()) {return -1;}/*返回队尾元素*/return data[rear];}public boolean isEmpty() {/*判断队列是否为空*/return size == 0;}public boolean isFull() {/*判断队列是否已满*/return size == data.length;}/*** 在该测试代码中,我们创建了一个容量为 3 的循环队列,* 然后进行了一系列操作来测试该类的实现是否正确。* 最后输出的结果符合预期,说明该循环队列的实现是正确的。*/public static void main(String[] args) {/*创建容量为 3 的循环队列*/MyCircularQueue circularQueue = new MyCircularQueue(3);/*输出 true,队列变为 [1]*/System.out.println(circularQueue.enQueue(1));/*输出 true,队列变为 [1, 2]*/System.out.println(circularQueue.enQueue(2));/*输出 true,队列变为 [1, 2, 3]*/System.out.println(circularQueue.enQueue(3));/*输出 false,队列已满,插入失败*/System.out.println(circularQueue.enQueue(4));/*输出 3,队尾元素为 3*/System.out.println(circularQueue.Rear());/*输出 true,队列已满*/System.out.println(circularQueue.isFull());/*输出 true,队列变为 [2, 3]*/System.out.println(circularQueue.deQueue());/*输出 true,队列变为 [2, 3, 4]*/System.out.println(circularQueue.enQueue(4));/*输出 4,队尾元素为 4*/System.out.println(circularQueue.Rear());}
}
(四)滑动窗口最大值
题目描述:给定一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例:输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 输出: [3,3,5,5,6,7]
解释:滑动窗口的位置 最大值
- [1 3 -1] -3 5 3 6 7 3
- 1 [3 -1 -3] 5 3 6 7 3
- 1 3 [-1 -3 5] 3 6 7 5
- 1 3 -1 [-3 5 3] 6 7 5
- 1 3 -1 -3 [5 3 6] 7 6
- 1 3 -1 -3 5 [3 6 7] 7
提示:你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
进阶:你能在线性时间复杂度内解决此题吗?
解题思路
滑动窗口最大值问题可以使用单调队列来解决,具体思路如下:
- 我们使用双端队列 deque,存储数组的下标。deque 中的元素按照从大到小的顺序排列,即 deque 中的第一个元素是滑动窗口中的最大值。
- 我们遍历数组,依次将元素放入 deque 中。当元素个数大于 k 时,我们需要将 deque 的第一个元素弹出,因为它不在滑动窗口中了。
- 对于新加入 deque 的元素,从队尾开始比较,如果队尾的元素比当前元素小,则说明队尾的元素不可能是滑动窗口中的最大值,将其弹出。直到队尾的元素比当前元素大,或者 deque 为空,我们再将当前元素插入队尾。
- 每次队列中的最大值即为 deque 的第一个元素,我们将其存入结果数组中。
由于每个元素最多进 deque 和出 deque 一次,因此时间复杂度为 O(n)。
需要注意的是,deque 中存储的是数组中元素的下标,而不是元素本身。因此在计算 deque 中的最大值时,需要根据下标从原数组中取出对应的元素。
具体代码展示
package org.zyf.javabasic.letcode.queue;import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;/*** @author yanfengzhang* @description 给定一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。* 你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。* 返回滑动窗口中的最大值。* @date 2023/4/9 15:23*/
public class MaxSlidingWindow {/*** 1 我们使用双端队列 deque,存储数组的下标。deque 中的元素按照从大到小的顺序排列,即 deque 中的第一个元素是滑动窗口中的最大值。* 2 我们遍历数组,依次将元素放入 deque 中。当元素个数大于 k 时,我们需要将 deque 的第一个元素弹出,因为它不在滑动窗口中了。* 3 对于新加入 deque 的元素,从队尾开始比较,如果队尾的元素比当前元素小,* 则说明队尾的元素不可能是滑动窗口中的最大值,将其弹出。* 直到队尾的元素比当前元素大,或者 deque 为空,我们再将当前元素插入队尾。* 4 每次队列中的最大值即为 deque 的第一个元素,我们将其存入结果数组中。*/public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;if (n == 0) {return new int[0];}if (k == 1) {return nums;}/*双端队列,存储数组下标*/Deque<Integer> deque = new LinkedList<>();/*初始化队列,从 0 到 k - 1,把队列中比 nums[i] 小的元素全部弹出*/for (int i = 0; i < k; i++) {while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast();}deque.offerLast(i);}int[] ans = new int[n - k + 1];ans[0] = nums[deque.peekFirst()];/*遍历数组,维护队列中的元素*/for (int i = k; i < n; i++) {/*判断队首是否在滑动窗口中*/if (deque.peekFirst() <= i - k) {deque.pollFirst();}/*把队列中比 nums[i] 小的元素全部弹出*/while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast();}/*将当前元素插入队尾*/deque.offerLast(i);ans[i - k + 1] = nums[deque.peekFirst()];}return ans;}public static void main(String[] args) {int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};int k = 3;int[] result = new MaxSlidingWindow().maxSlidingWindow(nums, k);/*输出:[3, 3, 5, 5, 6, 7]*/System.out.println(Arrays.toString(result));}
}
(五)课程表
题目描述:你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
提示:
- 1 <= numCourses <= 105
- 0 <= prerequisites.length <= 5000
- prerequisites[i].length == 2
- 0 <= ai, bi < numCourses
- prerequisites[i] 中的所有课程对 互不相同
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/course-schedule
解题思路
该问题可以抽象成一个有向图,课程之间的先修关系可以表示为图中的边。因此,该问题就转化为在有向图中判断是否存在环。若存在环,那么就无法完成所有课程的学习,否则就可以完成。
使用拓扑排序算法可以解决该问题。拓扑排序可以输出图的节点,满足节点的前驱节点已经全部输出。对于本题,我们可以使用拓扑排序来判断有向图中是否存在环。具体做法是,每次选择一个入度为 0 的节点,并移除该节点以及以该节点为起点的所有边,重复这个过程直到图为空,若过程中存在没有入度为 0 的节点的情况,那么就说明图中存在环。如果最终能够将所有节点输出,那么就说明没有环,可以完成所有课程的学习。
也可以使用队列实现拓扑排序算法。具体实现方法是:
- 统计所有节点的入度,将入度为 0 的节点加入队列。
- 取出队首节点,输出该节点,并将以该节点为起点的所有边移除,更新它们的入度。如果某个节点入度变为 0,则将该节点加入队列。
- 重复第 2 步,直到队列为空或者无法再取出入度为 0 的节点。
如果最终能够输出所有节点,说明不存在环;否则,说明存在环。
具体代码展示
package org.zyf.javabasic.letcode.queue;import java.util.LinkedList;
import java.util.Queue;/*** @author yanfengzhang* @description 你这个学期必须选修 numCourses 门课程,记为0到numCourses - 1 。* 在选修某些课程之前需要一些先修课程。* 先修课程按数组prerequisites 给出,其中prerequisites[i] = [ai, bi] ,表示如果要学习课程ai 则 必须 先学习课程bi 。* <p>* 例如,先修课程对[0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。* 请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。* @date 2023/4/9 15:55*/
public class CanFinishCourses {/*** 使用队列实现拓扑排序算法。具体实现方法是:* 统计所有节点的入度,将入度为 0 的节点加入队列。* 取出队首节点,输出该节点,并将以该节点为起点的所有边移除,更新它们的入度。如果某个节点入度变为 0,则将该节点加入队列。* 重复第 2 步,直到队列为空或者无法再取出入度为 0 的节点。* 如果最终能够输出所有节点,说明不存在环;否则,说明存在环。*/public boolean canFinish(int numCourses, int[][] prerequisites) {/*记录每个节点的入度*/int[] inDegree = new int[numCourses];for (int[] pre : prerequisites) {inDegree[pre[0]]++;}Queue<Integer> queue = new LinkedList<>();/*将入度为 0 的节点加入队列*/for (int i = 0; i < numCourses; i++) {if (inDegree[i] == 0) {queue.offer(i);}}int count = 0;/*取出队首节点,输出该节点,并将以该节点为起点的所有边移除,更新它们的入度*/while (!queue.isEmpty()) {int curr = queue.poll();count++;for (int[] pre : prerequisites) {if (pre[1] == curr) {inDegree[pre[0]]--;if (inDegree[pre[0]] == 0) {queue.offer(pre[0]);}}}}/*如果最终能够输出所有节点,说明不存在环;否则,说明存在环*/return count == numCourses;}
}
(六)队列的最大值
题目描述:请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
限制:
- 1 <= push_back,pop_front,max_value的总操作数 <= 10000
- 1 <= value <= 10^5
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof
解题思路
可以使用两个队列来实现,一个队列用来存储插入的元素,另一个队列用来存储当前队列中的最大值。
具体实现时,我们可以使用两个 LinkedList 来实现双端队列,一个队列用来存储插入的元素,另一个队列用来存储当前队列中的最大值。
每次插入元素时,先将该元素插入到存储元素的队列中,然后将最大值队列中小于等于该元素的元素全部弹出,保证最大值队列中的元素始终是递减的。然后将该元素插入到最大值队列中。
当需要弹出队首元素时,如果队首元素等于最大值队列中的第一个元素,则同时弹出该元素。
由于每个元素最多只会被弹入和弹出一次,因此总时间复杂度为O(n),均摊时间复杂度为 O(1)。
具体代码展示
package org.zyf.javabasic.letcode.queue;import java.util.LinkedList;/*** @author yanfengzhang* @description 请定义一个队列并实现函数 max_value 得到队列里的最大值,* 要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。* <p>* 若队列为空,pop_front 和 max_value需要返回 -1* @date 2023/4/9 16:19*/
public class MaxQueue {/*存储正常数据的队列*/private LinkedList<Integer> queue;/*存储当前队列中最大值的队列*/private LinkedList<Integer> maxQueue;public MaxQueue() {queue = new LinkedList<>();maxQueue = new LinkedList<>();}public int max_value() {if (maxQueue.isEmpty()) {return -1;}/*返回最大值队列的队首元素*/return maxQueue.peekFirst();}public void push_back(int value) {/*将元素加入正常队列*/queue.offerLast(value);while (!maxQueue.isEmpty() && maxQueue.peekLast() < value) {/*将小于当前元素的元素从最大值队列中弹出*/maxQueue.pollLast();}/*将当前元素加入最大值队列*/maxQueue.offerLast(value);}public int pop_front() {if (queue.isEmpty()) {return -1;}/*弹出正常队列的队首元素*/int front = queue.pollFirst();if (front == maxQueue.peekFirst()) {/*如果该元素是最大值队列的队首元素,则同时弹出*/maxQueue.pollFirst();}return front;}public static void main(String[] args) {MaxQueue q = new MaxQueue();/*输出 -1*/System.out.println(q.max_value());q.push_back(1);q.push_back(3);q.push_back(2);/*输出 3*/System.out.println(q.max_value());/*输出 1*/System.out.println(q.pop_front());/*输出 3*/System.out.println(q.max_value());/*输出 3*/System.out.println(q.pop_front());/*输出 2*/System.out.println(q.max_value());/*输出 2*/System.out.println(q.pop_front());/*输出 -1*/System.out.println(q.max_value());}}
(七)用数组实现一个队列
题目描述:设计并实现一个基于数组的队列(Queue)数据结构,要求支持入队(enqueue)和出队(dequeue)操作,并能够正确地维护队列的顺序。
解题思路
要使用数组实现一个队列,可以利用数组的特性进行操作。以下是一种常见的实现思路:
- 创建一个固定大小的数组,用于存储队列的元素。
- 使用两个指针,分别指向队列的头部和尾部。
- 初始时,头部和尾部指针都指向数组的起始位置。
- 入队操作:将元素添加到尾部指针所指向的位置,然后将尾部指针后移一位。
- 出队操作:将头部指针所指向的元素移除,并将头部指针后移一位。
- 队列为空时,头部和尾部指针指向同一个位置。
具体代码展示
package org.zyf.javabasic.letcode.queue;/*** @author yanfengzhang* @description 设计并实现一个基于数组的队列(Queue)数据结构,* 要求支持入队(enqueue)和出队(dequeue)操作,* 并能够正确地维护队列的顺序。* enqueue 和 dequeue 操作的时间复杂度为 O(1),isEmpty 和 size 方法的时间复杂度也为 O(1)。** 要使用数组实现一个队列,可以利用数组的特性进行操作。以下是一种常见的实现思路:* 1. 创建一个固定大小的数组,用于存储队列的元素。* 2. 使用两个指针,分别指向队列的头部和尾部。* 3. 初始时,头部和尾部指针都指向数组的起始位置。* 4. 入队操作:将元素添加到尾部指针所指向的位置,然后将尾部指针后移一位。* 5. 出队操作:将头部指针所指向的元素移除,并将头部指针后移一位。* 6. 队列为空时,头部和尾部指针指向同一个位置。* @date 2023/6/14 23:51*/
public class ImplementQueueUseArray {private int capacity;private int[] queue;// 头部指针private int head;// 尾部指针private int tail;public ImplementQueueUseArray(int capacity) {this.capacity = capacity;this.queue = new int[capacity];this.head = 0;this.tail = 0;}public void enqueue(int item) {if (tail == capacity) {// 队列已满throw new IndexOutOfBoundsException("Queue is full");}queue[tail] = item;tail++;}public int dequeue() {if (head == tail) {// 队列为空throw new IndexOutOfBoundsException("Queue is empty");}int item = queue[head];head++;return item;}public boolean isEmpty() {return head == tail;}public int size() {return tail - head;}public static void main(String[] args) {ImplementQueueUseArray queue = new ImplementQueueUseArray(5);queue.enqueue(10);queue.enqueue(20);queue.enqueue(30);System.out.println("Size of queue: " + queue.size());int item1 = queue.dequeue();int item2 = queue.dequeue();System.out.println("Dequeued items: " + item1 + ", " + item2);System.out.println("Size of queue after dequeue: " + queue.size());}
}
队列知识及编程练习总结相关推荐
- 计算机基础知识对编程的重要性
码农和架构师的差别在哪里 从题目看文章,大家的第一想法是本篇文章是一篇讲述计算机基础知识和编程之间的关系,但是为什么开篇是这样的呢?当然这样的开篇并没有多大的意义,唯一的目的就是吸引读者而已. 纵观计 ...
- 数据结构(C语言版) 第 三 章 栈与队列 知识梳理 + 作业习题详解
目录 一.栈 0.栈的基本概念 1.栈的实现 2.栈与递归 3.Hanoi塔问题 二.队列 0.队列的基本概念 1.队列的实现 2.循环队列 2.1循环队列的相关条件和公式: 3.链队列 4.链队列完 ...
- 树相关知识及编程练习总结
目录 一.背景知识 二.树的应用举例 (一)Spring中的应用举例 (二)其他框架中的应用举例 (三)实际开发中的应用举例 三.相关编程练习 (一)二叉树遍历:包括前序遍历.中序遍历.后序遍历.层序 ...
- java 并发队列_JAVA并发编程:阻塞队列BlockingQueue之SynchronousQueue
前面在讲解Executors工厂创建可缓存线程的线程池(newCachedThreadPool)的时候有提到过SynchronousQueue队列,该线程池使用 SynchronousQueue 作为 ...
- socketmq 设置队列大小_C++编程实例:面向对象的整形队列实现
C++三大特性:多态,封装,继承.相较于C的结构,C++引入了类定义,从而引入封装程序设计思想. 以下实验基本实现思想和上篇面向结构编程相同,主要不同在于C++类的特殊定义和体会.包括关于C++类元素 ...
- java最全基础知识_Java编程入门,计数排序(Counting Sort)怎么做?
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中. 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数. 计数排序(Counting sort)是一种稳定的排 ...
- java最全基础知识_Java编程入门,选择排序(Selection Sort)怎么做?
表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好.唯一的好处可能就是不占用额外的内存空间了吧.理论上讲,选择排序可能也是平时排序一般人想到的 ...
- c++知识整理 编程模块
最近开始看c++primer,做一点记录! 函数的基础知识: 要使用函数,必须完成: 1. 提供函数的定义 2.提供函数原型 3.调用函数 了解一下,函数是如何返回它的返回值: 函数会通过将返回值复制 ...
- C# 线程知识--异步编程模型(APM)
在构建高性能.可伸缩的应用程序时,必定会采用异步操作来提升应用程序性能,改善用户体验,异步操作与线程池结合允许使用很少的线程执行许多的操作.CLR中提供了一种异步操作的模式即异步编程模式. 1.异步编 ...
最新文章
- php 使用 curl 报错,PHP CURL post数据报错 failed creating formpost data
- Collection集合概述
- Java 中静态方法 实例方法 具体方法区别与联系
- VMware vSphere5.0 HA高可用性原理
- linux查看删除init内容,linux常用命令
- 再谈研发那些事——两项核心工作的区别与联系
- 双系统linux引导修复
- wget连接指定端口_WGET常用命令 WGET下载HTTPS链接
- 扩展欧几里得算法——java
- 8个国外在线学习网课的网站
- oracle数据库中汉字转化成拼音
- 二代身份证号码编码规则
- Android ActionBar 更改返回图标
- 10.Go复合类型-切片
- 鲤鱼溪传说:神鱼与三仙姑
- 车联网---V2X介绍、V2X现有的两大通信标准DSRC和LTE V2X
- ECharts实现带钓鱼岛和南海诸岛的中国(China)地图
- Linux内存管理 之 KSM功能介绍
- 活期账户10亿个+日均交易4亿笔,建设银行如何啃下系统转型的“硬骨头”?
- MVC实现SQL多表查询并导出表格