堆的实现

什么是堆

堆就是用数组实现的二叉树,堆有两种形式:最大堆和最小堆,两者的差别在于节点的排序方式。

在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。

这是一个最大堆,,因为每一个父节点的值都比其子节点要大。根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常有用,因为堆常常被当做优先队列使用,因为可以快速地访问到“最重要”的元素。

注意:堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。例如,在一个最大堆中,最大的那一个元素总是位于 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;}
}

堆的实现(大量注释)相关推荐

  1. 数据结构--堆(Heap)

    堆(Heap) 本文主要介绍以下内容: Heap的实现 HeapSort(堆排序) 完善各种堆的函数接口 TopK经典问题 堆就是一棵完全二叉树.因为它的某些性质,我们可以用数组存储. 堆的性质 1 ...

  2. 【瑞萨RA4系列】使用TinyMaix识别手写数字

    文章目录 一.TinyMaix简介 1.1 TinyMaix开源项目 1.2 下载TinyMaix源码 二.TinyMaix移植 2.1 创建TinyMaix移植项目 2.2 添加TinyMaix源码 ...

  3. 11GR2 中的常见 RMAN 问题

    本文是Oracle support对11GR2 RMAN备份过程中的问题总结 11GR2 中的常见 RMAN 问题   11gR2 中少数几个结构更改对 RMAN 设置产生了广泛的影响   1. Sn ...

  4. JVM -- 垃圾回收;垃圾回收算法(三)

    阅读前可参考 https://blog.csdn.net/MinggeQingchun/article/details/126947384 https://blog.csdn.net/MinggeQi ...

  5. uboot成功移植到STM32F103ZET6(二)

    接上一贴:uboot成功移植到STM32F103ZET6(一) 软件平台:IAR for ARM 7.70 硬件主板:浩宇电子STM32F103ZET6最小系统板 STM32库:HAL库 uboot版 ...

  6. 【瑞萨RA6系列】使用TinyMaix识别手写数字

    一.TinyMaix简介 TinyMaix是国内sipeed团队开发一个轻量级AI推理框架,官方介绍如下: TinyMaix 是面向单片机的超轻量级的神经网络推理库,即 TinyML 推理库,可以让你 ...

  7. 关于如何理解Glibc堆管理器(Ⅹ——完结、补充、注释——Arena、heap_info、malloc_*)

    本篇实为个人笔记,可能存在些许错误:若各位师傅发现哪里存在错误,还望指正.感激不尽. 若有图片及文稿引用,将在本篇结尾处著名来源(也有置于篇首的情况). 截至到本节内容,该系列算是正式完结了,后续或许 ...

  8. 归并排序(代码注释超详细)

    归并排序: (复制粘贴百度百科没什么意思),简单来说,就是对数组进行分组,然后分组进行排序,排序完最后再整合起来排序! 我看了很多博客,都是写的8个数据呀什么的(2^4,分组方便),我就想着,要是10 ...

  9. 在A*寻路中使用二叉堆

    在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding ...

  10. 苹果开源代码中惊现“wechat”,老外注释的吐槽亮了!

    点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 每个科技大厂的开源项目,几乎都是各领域开发者最重要的研究学习 ...

最新文章

  1. GRE核心词汇助记与精练-List8倒、流
  2. 简单分享一个轻量级自动化测试框架目录结构设计
  3. 《Spark核心技术与高级应用》——1.2节Spark的重要扩展
  4. 关键词匹配(Ac自动机模板题)
  5. Linux搭建Node.js环境
  6. leetcode第72题:编辑距离
  7. vue php axios 跨域,在vue项目中,使用axios跨域处理
  8. selenium firefox驱动_Python3+selenium配置常见报错解决方案
  9. tcpdump - 数据包进行截获的包分析工具
  10. okhttp配置缓存策略_一网打尽OkHttp中的缓存问题
  11. 学习python的错误总结
  12. Postman Sandbox
  13. Python - turtle画图库 临摹粉色花卉卡片
  14. 魔兽 怎么查服务器在线人数,网易魔兽世界人口普查查看
  15. SpringMVC+Mybatis框架集成开发基础——项目开发流程——01
  16. 鸿蒙思维闪卡训练,提高孩子智力,父母不妨使用思维导图来提升孩子记忆力和创造力...
  17. java智能算法--机器学习包
  18. CentOS8安装Docker
  19. 有一种动物叫做 — 狼
  20. 4、keil C51多文件创建小记

热门文章

  1. 堆积图--MatplotLib
  2. 计算机的软键盘在哪里,Win8软键盘在哪 Win8.1屏幕键盘打开方法图解
  3. sow 项目范围说明书的区别
  4. 第七章 yaml格式
  5. centos双网卡不能同时工作解决
  6. 软考软件设计师中级考试知识点(一)
  7. IOS逆向分析—终极详细(一)
  8. 一些常用外设DHT11,sg90
  9. matlab-基础 取整函数 向0取整 取最近整数 向上取整 向下取整
  10. Java 在Excel中添加水印