1、什么是优先队列

优先队列也是一种队列,它的接口函数和队列相同。

public interface Queue {

int getSize();

boolean isEmpty();

E dequeue();

void enqueue(E e);

E getFront();

}

虽然代码相同,需要注意的是,出队操作:拿出最大值(优先级最高)。但相对于普通的队列有着宏观上的不同。普通队列:先进先出,后进后出

优先队列:出队和入队得顺序无关,和优先级有关

形象地理解就是超市和医院的排队。超市排队这种特性就符合普通队列的形式。先排队先结账。医院就不一样啦,医院要优先处理急诊的病人,这就跟优先级有关,优先级越高的元素放在最前面。优先进行处理。

不同的底层实现方法:

作为一种抽象的数据结构,底层实现的方法包含很多。数组或者链表这种线性结构,当然还有我们的树结构,当然我们也可以引入顺序的线性结构。具体的复杂度如下:

2、什么是二叉堆

二叉堆是一个完全二叉树。那什么是完全二叉树呢? 满二叉树就是除了最下面一层,其他的节点都是具有左右孩子节点,就类似于这样。

完全二叉树就类似这种:

完全二叉树不是一颗满的二叉树,但是它的不满的那一部分一定在他的右下角部分。存放的过程也就是从左向右的过程。

堆的特性和二分搜索树不同,堆的某个节点总是不大于其父亲节点的值。也就是它并不具有顺序性。我们可以看一下下面这张图。

可以看出任意子树的最大值永远是自己的父亲节点。

2.1、实现方法

这里我们可以看出来二叉堆是一层一层的从左到右这么依次排列的,所以这里我们使用数组进行存储二叉树。通过数组索引找到节点。

这样我们就非常巧妙的将树结构存储到了数组当中。我们还可以发现下面的规则: + 左孩子的索引等于该父亲节点索引值的 2 倍 + 1 + 有孩子的索引等于该父亲节点的索引值的 2 倍 + 2 + 父亲节点的索引值等于左右孩子节点的(索引值 - 1) / 2

用代码展示就是:

parent(i) = (i - 1)/ 2;//获得i索引值的父亲节点索引值leftChild(i) = i * 2 + 1

rightChild(i) = i * 2 + 2

2.2、初始化操作

在最大堆这个数据结构当中我们使用的是数组的底层实现,当然我们也就需要动态数组来实现这个动态大小的最大堆。关于Array动态数组这一章可以参考Array 动态数组。当然也可以直接使用Java自带的动态数组。

初始化程序实现:

public MaxHeap() {

data = new Array<>();

}

public MaxHeap(int capacity) {

data = new Array<>(capacity);

}

节点索引查询实现: 我们需要对查询父亲节点进行判断,因为index-1操作会导致负值出现。

private int parent(int index) {

if (index == 0)

throw new IllegalArgumentException("index isn't zero");

return (index - 1) / 2;

}

private int leftChild(int index) {

return index * 2 + 1;

}

private int rightChild(int index) {

return index * 2 + 2;

}

2.3、添加元素

这里的操作底层实现其实是上浮(SiftUp)操作。下面我们就来看看是如何上浮的。 + 向数组末尾添加一个元素,也就是向树的最下角添加一个元素; + 根据堆的性质,父亲节点大于它的左右孩子节点,来进行替换操作 + 不断进行第二步操作直到待添加节点小于它的父亲节点

程序实现:

public void add(E e) {

data.addLast(e);

siftUp(data.getSize() - 1);

}

private void siftUp(int index) {

while (index > 0 && data.get(parent(index)).compareTo(data.get(index)) < 0) {

data.swap(parent(index), index);

index = (index - 1) / 2; //父亲节点也就是待插入元素现在的位置 }

}

2.4、提取最大值

对于我们上面实现的最大堆,看得出来,最大值的地方存在于根节点的位置。也就是数组索引位0的位置。而且我们需要维护二叉堆的性质。 步骤: + 用树最后一个节点移动到根节点 + 判断待下沉操作的节点必须大于孩子节点的最大值,如果大于那么循环结束,否则替换孩子节点最大值和待下沉节点的位置。

提取最大值程序实现:

public E extractMax() {

E ret = findMax(); //查找最大值 data.swap(0, size() - 1); //移动最后一个节点到根节点 data.removeLast();

siftDown(0);

return ret;

}

// 下沉操作private void siftDown(int index) {

while (leftChild(index) < size()) {

int j = leftChild(index);

if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0)

j++; //右孩子节点值大 if (data.get(index).compareTo(data.get(j)) >= 0)

break;

else

data.swap(index, j);

index = j;

}

}

2.5 查询操作

查询操作就是查找元素最大的值,这里就是根节点位置,也就是索引为 0 的位置。

2.6、replace操作

replace替换操作主要包括:去除最大元素,放入一个新的元素。这其实是一个组合操作。但这里我们准备封装一下,并对其进行优化。

优化的方式就是在删除元素这里,如果我们分extraMax和add操作就需要两次 O(log(N)) 级别的时间复杂度。在replace操作中,我们可以直接将待添加的元素元素替换到根节点的位置,然后在执行下沉操作就可以,这样就是一次 O(log(N)) 级别的时间复杂度。

public E replace(E e) {

E ret = findMax();

data.set(0, e);

siftDown(0);

return ret;

}

2.7、Heapify数组堆化

操作就是将任意数组整理成堆的形状。 具体的过程就是: + 找到树结构的倒数第一个非叶子节点; + 不断向上进行下沉SiftDown操作

初始位置的查询就是最后一个节点的父亲节点。

程序实现:

public MaxHeap(E[] arr) {

data = new Array<>(arr);

for (int i = parent(arr.length - 1); i >= 0; i--)

siftDown(i);

}

3、优先队列的实现——基于二叉堆

具体的函数方法其实在最大堆已经映射过了。

@Override

public E dequeue() {

return maxHeap.extractMax();

}

@Override

public void enqueue(E e) {

maxHeap.add(e);

}

@Override

public E getFront() {

return maxHeap.findMax();

}

最后

更多精彩内容,大家可以转到我的主页:首页 | 曲怪曲怪​quguai.cn:8090

java maxheap_Java底层PriorityQueue 优先队列——基于MaxHeap最大堆相关推荐

  1. 【Java】用PriorityQueue优先队列实现最小堆和最大堆

    用PriorityQueue优先队列实现最小堆和最大堆 1.写法一:使用lambda写法来构建比较规则 2.写法二:比较器实现 3.泛型为Map,并且需要比较的是哈希表的值 使用写法一: 使用写法二: ...

  2. JAVA Socket 底层是怎样基于TCP/IP 实现的???

    首先必须明确:TCP/IP模型中有四层结构:       应用层(Application Layer).传输层(Transport  Layer).网络层(Internet Layer  ).链路层( ...

  3. Java 调用http接口(基于OkHttp的Http工具类方法示例)

    目录 Java 调用http接口(基于OkHttp的Http工具类方法示例) OkHttp3 MAVEN依赖 Http get操作示例 Http Post操作示例 Http 超时控制 工具类示例 Ja ...

  4. java底层原理书籍_不愧是阿里p8大佬!终于把Java 虚拟机底层原理讲清楚了,请签收...

    概述 JVM 的内存模型和 JVM 的垃圾回收机制一直是 Java 业内从业者绕不开的话题(实际调优.面试)JVM是java中很重要的一块知识,也是面试常问的问题之一,直至今天,仍然还有许多面试者在被 ...

  5. java语音jvm_java环境中基于jvm的两大语言:scala,groovy

    一.java环境中基于jvm的两大语言:scala,groovy 可以在java项目里混编这两种语言: scala:静态语言,多范式语言,糅合了面向对象.面向过程:可以与java和net互操作:融汇了 ...

  6. java项目-第90期基于ssm的嘟嘟二手书商城系统

    源码获取:本博客首页"资源"专栏下载! java项目-第90期基于ssm的嘟嘟二手书商城系统 1.项目简述 该项目是二手书城商城系统,包含普通用户和管理员两个角色.普通用户可以购买 ...

  7. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  8. stm32运行java虚拟机_windows下的基于Eclipse的STM32开发调试环境搭建

    这段时间在玩STM32,但官方库的代码也确实是有点多,记忆力有点不太好了.突然就想起了以前用Eclipse的那个代码提示功能,谷歌了一段时间, (一)安装编译环境 1.下载和安装JAVA虚拟机 因为E ...

  9. Java课程project(SMAC计算器)----基于JavaSE

    Java课程project(SMAC计算器)----基于JavaSE 新开了一门外教课程,Object-oriented Programming(JAVA),本章记录结课project. This p ...

最新文章

  1. c语言ctype中替换查找字符,c – std :: ctype是否总是按“C”语言环境对字符进行分类?...
  2. Fiddler小技巧-测试上传文件接口多参数并传情况
  3. Springboot-mongodb MongoRepository接口 save方法 详解
  4. ubuntu时钟不显示的解决方法
  5. vue.js源码学习分享(一)
  6. 计算机护角,纸护角抗压测试仪
  7. google浏览器 隐藏功能开启
  8. [转]spring入门(六)【springMVC中各数据源配置】
  9. handwritten dataset手写体数据集(IAM,RIMES,CVL)
  10. 【小程序合集】来一组适合你的表情包-表情包大全
  11. 怎样培养数据分析的能力
  12. 【论文笔记】SimplE Embedding for Link Prediction in Knowledge Graphs
  13. 2月人民日报申论范文合辑(含获取方式)
  14. HDOJ 月之数 2502
  15. 基于C语言扫雷游戏的设计与实现
  16. HDU- 1151 Air Raid(最小路径覆盖)
  17. wps插入C/C++代码
  18. 一键彻底关闭WIN10自动更新_BlockWin10AU
  19. 例题5.23 蚂蚁 LA4043
  20. 怎么去除烦人的WPS广告

热门文章

  1. eval函数pythonmopn_python eval函数
  2. 怎么学好python leetcode的题目太难了_为什么leetcode中的python解法过于pythonic,而忽略了算法题主要关注的复杂度问题?...
  3. osip和mysql_osip2和eXosip2协议
  4. 入门指南_Spring Boot2: 快速入门指南
  5. linux无法将文件移入回收站,linux中使用rm命令将文件移到回收站的方法
  6. java 下载文件大小_如何在浏览器中显示使用角度5下载的文件的文件大小?
  7. http状态码_一些常见的HTTP状态码
  8. c语言的各种类型的指针,简单总结C语言中各种类型的指针的概念
  9. 3500x架构_如何评价超威半导体(AMD)新发布的 锐龙(Ryzen)3500X?
  10. v-for能倒序遍历吗_神级遍历——morris