Java 中的栈、队列和双端队列
Java 提供了多种类和接口支持栈、队列和双端队列的实现。
Stack \texttt{Stack}Stack 类是早期版本的栈的实现类,继承自 Vector \texttt{Vector}Vector 类。在后续版本中,JDK 的官方文档不建议使用 Stack \texttt{Stack}Stack 类实现栈的功能,而是建议使用 Deque \texttt{Deque}Deque 接口及其实现类实现栈的功能。
Queue \texttt{Queue}Queue 接口是队列的接口,需要通过实现类完成实例化,常见的实现类包括 ArrayDeque \texttt{ArrayDeque}ArrayDeque 类和 LinkedList \texttt{LinkedList}LinkedList 类。
Deque \texttt{Deque}Deque 接口是双端队列的接口,需要通过实现类完成实例化,常见的实现类包括 ArrayDeque \texttt{ArrayDeque}ArrayDeque 类和 LinkedList \texttt{LinkedList}LinkedList 类。
ArrayDeque \texttt{ArrayDeque}ArrayDeque 类和 LinkedList \texttt{LinkedList}LinkedList 类都可以作为栈和队列的实现类,区别在于,ArrayDeque \texttt{ArrayDeque}ArrayDeque 类的底层实现是循环数组,LinkedList \texttt{LinkedList}LinkedList 类的底层实现是双向链表。根据 JDK 的官方文档,ArrayDeque \texttt{ArrayDeque}ArrayDeque 类作为栈使用时效率高于 Stack \texttt{Stack}Stack 类,ArrayDeque \texttt{ArrayDeque}ArrayDeque 类作为队列使用时效率高于 LinkedList \texttt{LinkedList}LinkedList 类。无论是栈的实现还是队列的实现,都推荐使用 ArrayDeque \texttt{ArrayDeque}ArrayDeque 类。
单调栈和单调队列
单调栈和单调队列是栈和队列的高级应用,可以解决一些复杂的问题。
单调栈和单调队列满足元素的单调性。具体而言,单调栈内从栈底到栈顶的元素依次递增或递减,单调队列内从队首到队尾的元素依次递增或递减。在单调栈和单调队列中添加元素时,必须维护元素的单调性。
向单调栈添加元素时,首先需要检查栈顶元素和待添加元素是否满足单调性,如果不满足单调性则将栈顶元素出栈,直到栈为空或者栈顶元素和待添加元素满足单调性,然后将待添加元素入栈。
向单调队列添加元素时,首先需要检查队尾元素和待添加元素是否满足单调性,如果不满足单调性则将队尾元素出队,直到队列为空或者队尾元素和待添加元素满足单调性,然后将待添加元素入队。
由于普通的队列不支持在队尾将元素出队,因此需要使用双端队列实现单调队列的功能。
单调栈和单调队列的应用需要考虑具体情况。有时需要维护下标信息,因此在单调栈和单调队列中存储的不是元素本身,而是元素下标,下标对应的元素满足单调性。
使用单调栈和单调队列实现通常需要两层循环,但是由于每个元素最多只会在单调栈或单调队列中被添加一次和删除一次,因此时间复杂度是线性复杂度,而不是平方复杂度。
二叉堆和优先队列
优先队列是一种不同于栈、队列和双端队列的数据结构。栈、队列和双端队列的实现原理是线性表,而优先队列的实现原理是二叉堆。
二叉堆
在介绍二叉堆之前,首先需要介绍二叉树和完全二叉树。
二叉树是一个树的结构,每个结点最多有两个子结点,称为左子结点和右子结点。
完全二叉树的性质是,除了层数最大的层以外,其余各层的结点数都达到最大值,且层数最大的层的所有结点都连续集中在最左边。假设完全二叉树有 l ll 层,其中根结点位于第 0 00 层,则对于 0 ≤ i < l − 1 0 \le i < l - 10≤i<l−1,第 i ii 层有 2 i 2^i2
i
个结点。
二叉堆是一棵完全二叉树,其中的元素按照特定规则排列。常见的例子有小根堆和大根堆。
小根堆的性质是,每个结点的值都小于其子结点的值,根结点的值是堆中最小的;
大根堆的性质是,每个结点的值都大于其子结点的值,根结点的值是堆中最大的。
在二叉堆中添加元素和删除元素时,必须维护二叉堆的性质。以小根堆为例,添加元素和删除元素的操作如下:
添加元素时,假设添加的元素是 x xx,首先将 x xx 添加到末尾,然后比较 x xx 和父结点元素的大小,如果 x xx 小于父结点元素,则将 x xx 和父结点交换,直到 x xx 到达根结点或者大于等于父结点元素;
删除元素时,假设堆中的最后一个元素是 x xx,首先将 x xx 放置到根结点处,然后比较 x xx 和子结点元素的大小,如果 x xx 大于至少一个子结点元素,则将 x xx 和较小的子结点交换,直到 x xx 到达叶结点(没有子结点)或者小于等于全部子结点元素。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/stormsunshine/article/details/120731362