当前位置:网站首页>优先级队列 (堆)常用接口介绍 堆的存储 堆的创建
优先级队列 (堆)常用接口介绍 堆的存储 堆的创建
2022-04-21 13:50:00 【招桃花都没用】
优先级队列【堆】
1.优先级队列
1.1 概念
队列:是一个先进先出的数据结构,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素出队列。
数据结构应该提供两个基本的操作:
1.返回最高优先级对象
2.添加新的对象
1.2常用接口介绍
1.2.1 PriorityQueue的特性
Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,==PriorityQueue(优先队列)==是线程不安全的,==PriorityBlockingQueue(优先阻塞队列)==是线程安全的
关于PriorityQueue使用要注意:
- 使用时必须导入PriorityQueue所在的包
import java.util.PriorityQueue;
- PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象, 否则会抛出ClassCastException(类型转化异常)
- 不能插入 null 对象,否则会抛出NullPointerException(空指针异常)
** - 没有容量限制,可以插入任意多个元素,其内部可以自动扩容**
- 插入和删除元素的时间复杂度O(log N)
** - PriorityQueue底层使用了堆结构**
** - PriorityQueue默认情况下是小堆(每次获取到的元素都是最小的元素)**
1.2.2 PriorityQueue常用接口介绍

默认情况下, PriorityQueue队列是小堆
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
public class PriorityQueueN {
static void TestPriorityQueue(){
//创建一个空的优先级队列,底层默认为11
PriorityQueue<Integer> q1 = new PriorityQueue<>();
//创建一个空的优先级队列,底层容量是initialCapacity
PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
ArrayList<Integer> list = new ArrayList<>();
List.add(4);
List.add(3);
List.add(2);
List.add(1;
//用arraylist对象来构造一个优先级队列的对象
//q3中已经包含三个元素
PriorityQueue<Integer> q3 = new PriorityQueue<>(List);
System.out.println(q3.size());
System.out.println(q3.peek());
}
}
1.2.3 优先级队列的应用
top-k问题
在海量数据中找出前k个数(频率最高或最大的数)
class Solution {
public int[] smallestK(int[] arr, int k) {
int[] ret = new int[k];
if(arr == null || k<=0){
return ret;
}
//用数组中的所有元素构造一个堆
PriorityQueue<Integer> p = new PriorityQueue<>();
for(int i = 0 ;i<arr.length;++i){
p.offer(arr[i]);
}
//获取堆中前k个元素
for(int i = 0;i<k;++i){
ret[i] = p.poll();
}
return ret;
}
}
2 优先级队列的模拟实现
PriorityQueue底层使用了堆的数据结构,而堆就是在完全二叉树的基础上之上进行了一些元素的调整
2.1 堆的概念
1.完全二叉树
2.根必须比自己的左右孩子节点大(小)
堆的性质:
- 堆中某个节点的值总是不大于或者不小于其父节点的值
- 堆总是完全二叉树(堆一定是完全二叉树,完全二叉树不一定是堆)
大根堆:每一棵树的最大值都为根节点
小根堆:每一棵树的最小值都为根节点

2.2堆的存储方式
堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储
注意:对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。
将元素存储到数组中后,可以根据二叉树章节的性质5对树进行还原。假设i为节点在数组中的下标,则有:
如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1否则没有左孩子
如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2否则没有右孩子
2.3 堆的创建
2.3.1堆的创建

根节点的左右子树已经完全满足堆的性质,因此只需将根节点向下调整好即可

将27与左右孩子进行比较,然后与较小的孩子交换位置 ,会发现下面的又不符合。
int child = parent *2 +2 ====>右孩子
int child = parent *2 +1 ====>左孩子
int parent = 0;
默认让child标记左孩子
//找两个孩子中的较小的孩子
if(array[child+1] < array[child]){
child += 1;
}
//2.双亲中如果比较小堆孩子大
if(array[parent] > array[child] ){
//将双亲与较小的孩子交换
int temp = array[parent];
array[parent] = array[child];
array[child] = temp;
//需要继续往下更新
parent = child;
child = parent *2+1;
}else{
return;
}
完整代码:
public void shiftDown(int[] array, int parent) {
// child先标记parent的左孩子,因为parent可能有左没有右
int child = 2 * parent + 1;
int size = array.length;
while (child < size) {
// 如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
if(child+1 < size && array[child+1] < array[child]){
child += 1;
}
// 如果双亲比其最小的孩子还小,说明该结构已经满足堆的特性了
if (array[parent] <= array[child]) {
break;
}else{
// 将双亲与较小的孩子交换
int t = array[parent];
array[parent] = array[child];
array[child] = t;
// parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
parent = child;
child = parent * 2 + 1;
}
}
}
注意:在调整以 parent 为根的二叉树时,必须要满足parent的左子树和右子树已经是堆了才可以向下调整
时间复杂度分析: O(logN)
2.3.2 堆的创建(普通)
- 初始化堆
- 根节点与左右孩子比较,与较大的孩子交换
- 其子树形成的堆结构被破坏(因此每一次发生元素交换的时候,都需要递归调用重新构造堆的结构)
- 构造出来大根堆

- 找当前完全二叉树中倒数第一个叶子节点
- 注意:倒数第一个叶子节点刚好是最后一个节点的双亲
- 最后一个节点的编号是size -1 ,倒数第一个非叶子节点的小标(size-1-1)
public static void creatHeap(int[] array){
//找到第一个非叶子节点,从该节点位置开始往前一直到根节点,遇到一个根节点,向下调整
int root = ((array.legth-1)>> 1);
for(; root >= 0;root--){
shifDown(array,root);
}
}
版权声明
本文为[招桃花都没用]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45939887/article/details/121214587
边栏推荐
- 并发锁机制之synchronized
- Summary of several problems of esgyndb using JDBC UDR to access remote trafodion
- MySQL mvcc multi version concurrent version control and bufferpool caching mechanism
- SECOND: Sparsely Embedded Convolutional Detection
- NPM --- NPM configuration file
- EsgynDB 清理不一致对象
- Color gradient (columns, rings, etc.)
- Web -- user registration interface
- <2021SC@SDUSC>山东大学软件工程应用与实践JPress代码分析(三)
- 图像分类的训练基本过程——以MobileNet_v3为例
猜你喜欢

<2021SC@SDUSC>山东大学软件工程应用与实践JPress代码分析(八)

机器学习笔记 - Moore-Penrose 伪逆

深度学习与图像识别:原理与实践 笔记Day_10

【leetcode】144. Preorder traversal of binary tree

JVM字节码文件结构深度剖析

EsgynDB CQD-traf_lock_ddl

《商用密码应用与安全性评估》第三章 商用密码标准与产品应用-小结

POI与EasyExcel读写测试

Detailed explanation of JVM memory allocation mechanism

POI and easyexcel reading and writing test
随机推荐
并发编程之深入理解
机器学习笔记 - SVD奇异值分解(3) 在图像上应用 SVD
自动化监控系统Prometheus&Grafana入门实战
Chapter 4 - hierarchical query of SQL query
POI与EasyExcel读写测试
Character sorting in the string (10 points): please write the function fun to sort the strings with a length of 8 characters in descending order.
MySQL high performance business table structure and index design practice
2021-10-21软件测试理论
<2021SC@SDUSC>山东大学软件工程应用与实践JPress代码分析(十)
<2021SC@SDUSC>山东大学软件工程应用与实践JPress代码分析(十三)
Web -- user registration interface
<2021SC@SDUSC>山东大学软件工程应用与实践JPress代码分析(八)
New technology is coming again, embrace agp7 0, are you ready to say goodbye to transform?
EsgynDB 使用JDBC UDR访问远程Trafodion的几个问题小结
字符串 - 1. 字符串長度 (10 分)C語言標准函數庫中包括 strlen 函數,用於計算字符串的長度。作為練習,我們自己編寫一個功能與之相同的函數。
Oracle 的体系结构
Tool function - decimal place processing
Common configuration items of echart (line, area, text)
Synchronized of concurrent locking mechanism
Explication détaillée du mécanisme d'allocation de mémoire JVM