【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
相关文章
|
9天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
18 2
|
8天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
13天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
13天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
13天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
12 0
|
16天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
91 9
|
7天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
16 1
|
10天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
13天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
15天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
43 4