堆的实现(大量注释)
堆的实现
什么是堆
堆就是用数组实现的二叉树,堆有两种形式:最大堆和最小堆,两者的差别在于节点的排序方式。
在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。
这是一个最大堆,,因为每一个父节点的值都比其子节点要大。根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常有用,因为堆常常被当做优先队列使用,因为可以快速地访问到“最重要”的元素。
注意:堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。例如,在一个最大堆中,最大的那一个元素总是位于 index 0 的位置,但是最小的元素则未必是最后一个元素。--唯一能够保证的是最小的元素是一个叶节点,但是不确定是哪一个。
堆的Java实现
堆的接口
import java.util.NoSuchElementException;/*** Priority queue where objects have a priority that is provided extrinsically,* i.e., priorities are supplied as an argument during insertion and can be changed* using the changePriority method. Cannot contain duplicate or null items.*/
public interface ExtrinsicMinPQ<T> {/*** Adds an item with the given priority value.* @throws IllegalArgumentException if item is null or is already present in the PQ*/void add(T item, double priority);/** Returns true if the PQ contains the given item; false otherwise. */boolean contains(T item);/*** Returns the item with the least-valued priority.* @throws NoSuchElementException if the PQ is empty*/T peekMin();/*** Removes and returns the item with the least-valued priority.* @throws NoSuchElementException if the PQ is empty*/T removeMin();/*** Changes the priority of the given item.* @throws NoSuchElementException if the item is not present in the PQ*/void changePriority(T item, double priority);/** Returns the number of items in the PQ. */int size();/** Returns true if the PQ is empty; false otherwise. */default boolean isEmpty() {return size() == 0;}
}
堆的节点类
class PriorityNode<T> {private final T item;private double priority;PriorityNode(T e, double p) {this.item = e;this.priority = p;}T getItem() {return this.item;}double getPriority() {return this.priority;}void setPriority(double priority) {this.priority = priority;}@Overridepublic String toString() {return "PriorityNode{" +"item=" + item +", priority=" + priority +'}';}
}
最小值堆的实现
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.NoSuchElementException;/*** @see ExtrinsicMinPQ*/
public class ArrayHeapMinPQ<T> implements ExtrinsicMinPQ<T> {static final int START_INDEX = 1;//实现的堆下标从1开始List<PriorityNode<T>> items;//存储元素的数组HashMap<T,Integer> map = new HashMap<>();//使用一个map记录key在数组中的小标序号,增加查找速度// TODO: add fields as necessarypublic ArrayHeapMinPQ() {items = new ArrayList<>();T a = null;this.items.add(new PriorityNode<T>(a,-10000));//因为下标从一开始,所以给第0个位置加入一个元素// TODO: add code as necessary}// Here's a method stub that may be useful. Feel free to change or remove it, if you wish.// You'll probably want to add more helper methods like this one to make your code easier to read./*** A helper method for swapping the items at two indices of the array heap.* 交换堆里的两个元素位置,同时需要修改map里对应的值*/private void swap(int a, int b) {// TODO: replace this with your codePriorityNode<T> t = this.items.get(a);this.items.set(a,this.items.get(b));map.put(this.items.get(b).getItem(),a);this.items.set(b,t);map.put(t.getItem(),b);}//当前节点的父节点下标private int getparent(int a){return a/2;}//当前节点的左子节点下标private int getLeftChid(int a){return 2*a;}//当前节点的右子节点下标private int getRightChild(int a){return 2*a+1;}/*修改了第i个节点的权值后从第i个节点开始向上重新调整这个堆*/private void buildHeap(int i){if(i>0){if(this.items.get(i).getPriority()<this.items.get(getparent(i)).getPriority())//如果这个节点的权值比父节点的权值小的话,与父节点交换位置{swap(i,getparent(i));}buildHeap(getparent(i));//重新调整父节点以上的堆结构}}/*** 添加一个元素*/@Overridepublic void add(T item, double priority) {// TODO: replace this with your codeif(this.contains(item)){throw new IllegalArgumentException();//如果堆里存在这个元素则抛出异常}else{//将该节点先放入堆的最后一个位置,并且加入map中this.items.add(new PriorityNode<>(item,priority));map.put(item,this.items.size()-1);//向上调整堆结构buildHeap(this.items.size() - 1);}}/*使用map检查堆中是否包含指定元素*/@Overridepublic boolean contains(T item) {// TODO: replace this with your codeif(item==null){if(map.containsKey(null))return true;elsereturn false;}else{if(map.containsKey(item))return true;elsereturn false;}}/*查看最小值(堆的顶部)*/@Overridepublic T peekMin() {// TODO: replace this with your codeif(this.items.size()<=1)throw new NoSuchElementException();return this.items.get(1).getItem();}/*调整了第i个节点的权值后,从当前节点向下调整堆结构*/private void fixDown(int i)//从节点i开始向下调整{PriorityNode<T> t = this.items.get(i);int child = i * 2;//左子节点下标,child用来记录两个子节点中权值较小的一个while(child <this.items.size()){//如果右子节点(如果存在的话)的权值比左子节点权值小,那么child++if(child+1<this.items.size() && this.items.get(child+1).getPriority()<this.items.get(child).getPriority()){child++;}//如果当前节点的权值比两个子节点的权值都小,那么不需要调整下面的节点了if(this.items.get(i).getPriority()<this.items.get(child).getPriority()){break;}//和子节点交换,并进行下一层的调整swap(i,child);i = child;child = i*2;}this.items.set(i,t);}/*删除最小的元素,即将顶部元素删除*/@Overridepublic T removeMin() {// TODO: replace this with your codeif(this.items.size()<=1)throw new NoSuchElementException();//将堆的最后元素调整到顶部位置,之后从顶部开始向下调整堆swap(1,this.items.size()-1);T res = this.items.remove(this.items.size()-1).getItem();if(this.items.size()>1){fixDown(1);}map.remove(res);return res;}/*调整某一个节点的权值*/@Overridepublic void changePriority(T item, double priority) {// TODO: replace this with your codefor (int i=1;i<this.items.size();i++){if(this.items.get(i).getItem().equals(item)){double thispri = this.items.get(i).getPriority();this.items.get(i).setPriority(priority);if(thispri> priority){//如果调整的权值比之前小了,那么只需要从该节点开始向上调整堆buildHeap(i);}else{//如果调整的权值比之前大了,那么只需要从该节点开始向下调整堆fixDown(i);}return ;}}throw new NoSuchElementException();}@Overridepublic int size() {// TODO: replace this with your codereturn this.items.size() - 1;}
}
堆的实现(大量注释)相关推荐
- 数据结构--堆(Heap)
堆(Heap) 本文主要介绍以下内容: Heap的实现 HeapSort(堆排序) 完善各种堆的函数接口 TopK经典问题 堆就是一棵完全二叉树.因为它的某些性质,我们可以用数组存储. 堆的性质 1 ...
- 【瑞萨RA4系列】使用TinyMaix识别手写数字
文章目录 一.TinyMaix简介 1.1 TinyMaix开源项目 1.2 下载TinyMaix源码 二.TinyMaix移植 2.1 创建TinyMaix移植项目 2.2 添加TinyMaix源码 ...
- 11GR2 中的常见 RMAN 问题
本文是Oracle support对11GR2 RMAN备份过程中的问题总结 11GR2 中的常见 RMAN 问题 11gR2 中少数几个结构更改对 RMAN 设置产生了广泛的影响 1. Sn ...
- JVM -- 垃圾回收;垃圾回收算法(三)
阅读前可参考 https://blog.csdn.net/MinggeQingchun/article/details/126947384 https://blog.csdn.net/MinggeQi ...
- uboot成功移植到STM32F103ZET6(二)
接上一贴:uboot成功移植到STM32F103ZET6(一) 软件平台:IAR for ARM 7.70 硬件主板:浩宇电子STM32F103ZET6最小系统板 STM32库:HAL库 uboot版 ...
- 【瑞萨RA6系列】使用TinyMaix识别手写数字
一.TinyMaix简介 TinyMaix是国内sipeed团队开发一个轻量级AI推理框架,官方介绍如下: TinyMaix 是面向单片机的超轻量级的神经网络推理库,即 TinyML 推理库,可以让你 ...
- 关于如何理解Glibc堆管理器(Ⅹ——完结、补充、注释——Arena、heap_info、malloc_*)
本篇实为个人笔记,可能存在些许错误:若各位师傅发现哪里存在错误,还望指正.感激不尽. 若有图片及文稿引用,将在本篇结尾处著名来源(也有置于篇首的情况). 截至到本节内容,该系列算是正式完结了,后续或许 ...
- 归并排序(代码注释超详细)
归并排序: (复制粘贴百度百科没什么意思),简单来说,就是对数组进行分组,然后分组进行排序,排序完最后再整合起来排序! 我看了很多博客,都是写的8个数据呀什么的(2^4,分组方便),我就想着,要是10 ...
- 在A*寻路中使用二叉堆
在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序: 这一篇文章,是"A* Pathfinding ...
- 苹果开源代码中惊现“wechat”,老外注释的吐槽亮了!
点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 每个科技大厂的开源项目,几乎都是各领域开发者最重要的研究学习 ...
最新文章
- GRE核心词汇助记与精练-List8倒、流
- 简单分享一个轻量级自动化测试框架目录结构设计
- 《Spark核心技术与高级应用》——1.2节Spark的重要扩展
- 关键词匹配(Ac自动机模板题)
- Linux搭建Node.js环境
- leetcode第72题:编辑距离
- vue php axios 跨域,在vue项目中,使用axios跨域处理
- selenium firefox驱动_Python3+selenium配置常见报错解决方案
- tcpdump - 数据包进行截获的包分析工具
- okhttp配置缓存策略_一网打尽OkHttp中的缓存问题
- 学习python的错误总结
- Postman Sandbox
- Python - turtle画图库 临摹粉色花卉卡片
- 魔兽 怎么查服务器在线人数,网易魔兽世界人口普查查看
- SpringMVC+Mybatis框架集成开发基础——项目开发流程——01
- 鸿蒙思维闪卡训练,提高孩子智力,父母不妨使用思维导图来提升孩子记忆力和创造力...
- java智能算法--机器学习包
- CentOS8安装Docker
- 有一种动物叫做 — 狼
- 4、keil C51多文件创建小记