【Java数据结构】集合PriorityQueue及其背后的数据结构堆(优先级队列)(二)

简介: 【Java数据结构】集合PriorityQueue及其背后的数据结构堆(优先级队列)

堆的删除

注意:堆的删除一定删除的是堆顶元素。具体如下:

1. 将堆顶元素对堆中最后一个元素交换

2. 将堆中有效数据个数减少一个

3. 对堆顶元素进行向下调整

1. public void pollHeap() {
2. if(isEmpty()){
3. throw new RuntimeException();
4.         }
5. int temp=elem[0];
6.         elem[0]=elem[usedSize-1];
7.         elem[usedSize-1]=temp;
8.         usedSize--;
9. //保证依然是大根堆
10.         shiftDown(0,usedSize);
11. 
12.     }
13. 
14. public boolean isEmpty() {
15. return usedSize==0;
16.     }
17. 
18. /**
19.      *
20.      * @param root 是每棵子树的根节点的下标
21.      * @param len  是每棵子树调整结束的结束条件
22.      * 向下调整的时间复杂度:O(logn)
23.      */
24. private void shiftDown(int root,int len) {
25. 
26. int child=2*root+1;
27. 
28. while(child<len){
29. 
30. if(child+1<len&&elem[child]<elem[child+1]){
31. 
32.                 child++;
33.             }
34. 
35. if(elem[root]<elem[child]){
36. int temp=elem[root];
37.                 elem[root]=elem[child];
38.                 elem[child]=temp;
39.                 root=child;
40.                 child=2*root+1;
41. 
42.             }else {
43. break;
44.             }
45. 
46.         }
47. 
48. 
49.     }

用堆模拟实现优先级队列(完整代码)

1. import java.util.Arrays;
2. 
3. public class PriorityQueue {
4. public int[] elem;
5. public int usedSize;
6. 
7. public static final int DEFAULT_INIT_USESZIE=10;
8. public PriorityQueue() {
9.         elem=new int[DEFAULT_INIT_USESZIE];
10.     }
11. 
12. /**
13.      * 建堆的时间复杂度:O(n)
14.      *
15.      * @param array
16.      */
17. public void createHeap(int[] array) {
18. 
19. 
20. 
21. for(int i=0;i<array.length;i++){
22.             elem[i]=array[i];
23.             usedSize++;
24. if(isFull()){
25.                 elem= Arrays.copyOf(this.elem,2*this.elem.length);
26.             }
27.         }
28. for(int parent=(usedSize-1-1)/2;parent>=0;parent--){
29. 
30.             shiftDown(parent,usedSize);
31.         }
32. 
33.     }
34. 
35. /**
36.      *
37.      * @param root 是每棵子树的根节点的下标
38.      * @param len  是每棵子树调整结束的结束条件
39.      * 向下调整的时间复杂度:O(logn)
40.      */
41. private void shiftDown(int root,int len) {
42. 
43. int child=2*root+1;
44. 
45. while(child<len){
46. 
47. if(child+1<len&&elem[child]<elem[child+1]){
48. 
49.                 child++;
50.             }
51. 
52. if(elem[root]<elem[child]){
53. int temp=elem[root];
54.                 elem[root]=elem[child];
55.                 elem[child]=temp;
56.                 root=child;
57.                 child=2*root+1;
58. 
59.             }else {
60. break;
61.             }
62. 
63.         }
64. 
65. 
66.     }
67. 
68. 
69. /**
70.      * 入队:仍然要保持是大根堆
71.      * @param val
72.      */
73. public void push(int val) {
74. if(isFull()){
75.             elem= Arrays.copyOf(this.elem,2*this.elem.length);
76.         }
77.         elem[usedSize]=val;
78.         usedSize++;
79.         shiftUp(usedSize-1);
80. 
81.     }
82. 
83. private void shiftUp(int child) {
84. 
85. int parent=(child-1)/2;
86. 
87. while(child>0)
88. if(elem[child]>elem[parent]){
89. 
90. int temp=elem[child];
91.             elem[child]=elem[parent];
92.             elem[parent]=temp;
93.             child=parent;
94.             parent=(child-1)/2;
95.         }else{
96. break;
97.         }
98.     }
99. 
100. public boolean isFull() {
101. return usedSize== elem.length;
102.     }
103. 
104. /**
105.      * 出队【删除】:每次删除的都是优先级高的元素
106.      * 仍然要保持是大根堆
107.      */
108. public void pollHeap() {
109. if(isEmpty()){
110. throw new RuntimeException();
111.         }
112. int temp=elem[0];
113.         elem[0]=elem[usedSize-1];
114.         elem[usedSize-1]=temp;
115.         usedSize--;
116. //保证依然是大根堆
117.         shiftDown(0,usedSize);
118. 
119.     }
120. 
121. public boolean isEmpty() {
122. return usedSize==0;
123.     }
124. 
125. /**
126.      * 获取堆顶元素
127.      * @return
128.      */
129. public int peekHeap() {
130. if(isEmpty()){
131. return -1;
132.         }
133. return elem[0];
134.     }
135. }

常用接口介绍

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,本文主要介绍PriorityQueue。

关于PriorityQueue的使用要注意:

1. 使用时必须导入PriorityQueue所在的包,即:

import java.util.PriorityQueue;

2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出

ClassCastException异常

3. 不能插入null对象,否则会抛出NullPointerException

4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容

5. 插入和删除元素的时间复杂度为

6. PriorityQueue底层使用了堆数据结构, (注意:此处大家可以不用管什么是堆,后文中有介绍)

7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素

PriorityQueue常用接口介绍

构造器 功能介绍
PriorityQueue() 创建一个空的优先级队列,默认容量是11
PriorityQueue(int
initialCapacity)
创建一个初始容量为initialCapacity的优先级队列,注意:
initialCapacity不能小于1,否则会抛IllegalArgumentException异
PriorityQueue(Collection<?
extends E> c)
用一个集合来创建优先级队列

注意:默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器

1. // 用户自己定义的比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
2. class IntCmp implements Comparator<Integer>{
3. @Override
4. public int compare(Integer o1, Integer o2) {
5. return o2-o1;
6. }
7. }
8. public class TestPriorityQueue {
9. public static void main(String[] args) {
10. PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp());

插入/删除/获取优先级最高的元素

函数名 功能介绍
boolean
offer(E e)
插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时
间复杂度 ,注意:空间不够时候会进行扩容
E peek() 获取优先级最高的元素,如果优先级队列为空,返回null
E poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size() 获取有效元素的个数
void
clear()
清空
boolean
isEmpty()
检测优先级队列是否为空,空返回true
相关文章
|
1月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
196 100
|
1月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
217 101
|
21天前
|
存储 算法 安全
Java集合框架:理解类型多样性与限制
总之,在 Java 题材中正确地应对多样化与约束条件要求开发人员深入理解面向对象原则、范式编程思想以及JVM工作机理等核心知识点。通过精心设计与周密规划能够有效地利用 Java 高级特征打造出既健壮又灵活易维护系统软件产品。
53 7
|
11月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
946 9
|
11月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
242 59
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
78 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
374 77
|
8月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
194 11
|
8月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。