【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
相关文章
|
16天前
|
存储 Java
【数据结构】优先级队列(堆)从实现到应用详解
本文介绍了优先级队列的概念及其底层数据结构——堆。优先级队列根据元素的优先级而非插入顺序进行出队操作。JDK1.8中的`PriorityQueue`使用堆实现,堆分为大根堆和小根堆。大根堆中每个节点的值都不小于其子节点的值,小根堆则相反。文章详细讲解了如何通过数组模拟实现堆,并提供了创建、插入、删除以及获取堆顶元素的具体步骤。此外,还介绍了堆排序及解决Top K问题的应用,并展示了Java中`PriorityQueue`的基本用法和注意事项。
22 5
【数据结构】优先级队列(堆)从实现到应用详解
|
19天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
3天前
|
前端开发
07_用队列实现栈
07_用队列实现栈
|
3天前
|
测试技术
02_由两个栈组成的队列
02_由两个栈组成的队列
|
7天前
|
存储
|
8天前
|
存储 安全 Java
Java 常用集合分类
Java 常用集合分类
13 2
|
24天前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
147 3
|
25天前
|
Java
【数据结构】栈和队列的深度探索,从实现到应用详解
本文介绍了栈和队列这两种数据结构。栈是一种后进先出(LIFO)的数据结构,元素只能从栈顶进行插入和删除。栈的基本操作包括压栈、出栈、获取栈顶元素、判断是否为空及获取栈的大小。栈可以通过数组或链表实现,并可用于将递归转化为循环。队列则是一种先进先出(FIFO)的数据结构,元素只能从队尾插入,从队首移除。队列的基本操作包括入队、出队、获取队首元素、判断是否为空及获取队列大小。队列可通过双向链表或数组实现。此外,双端队列(Deque)支持两端插入和删除元素,提供了更丰富的操作。
26 0
【数据结构】栈和队列的深度探索,从实现到应用详解
|
存储 Java 编译器
Java工程师必知词汇:堆
堆是Java为类对象的内存分配工作所设置的一种运行时数据区,是一种通用性的内存池(也存在于RAM中),用于存放所有的JAVA对象。
|
5天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
18 2
下一篇
无影云桌面