堆(Heap)详解——Java实现
Heap
堆定义:(这里只讲二叉堆)堆实为二叉树的一种,分为最小堆和最大堆,具有以下性质:
- 任意节点小于/大于它的所有后裔,最小/大元在堆的根上。
- 堆总是一棵完全二叉树
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的相关操作:
- 建立
- 插入
- 删除
应用:
- 堆排序
- 优先队列
- 合并容器元素
- 找出第k大元素
Java实现:
/**
* Created by XuTao on 2018/11/5 22:10
* ···最小堆···
* 《注意: 实际上并不需要用节点来真正构造一颗树,我们只是在数组中操作排序,调整好的数组就是一个堆的层遍历结果》
*
* 插入:
* 也是插入末尾,然后调整,调整也应该是一个连续向上的过程,建树就是一个连续插入的过程
*
* 删除最小:
* 即删除root:
* 用末尾一个代替root,删除末尾,然后siftDown,如果子节点有更小的,每次只需要找到最小的子节点,然后交换即可。
*
* siftDown:
* 如果建树得以保证,那么如果子节点有更小的,每次只需要找到最小的子节点,然后交换即可。
* 如果是一个乱的树,那么就要考虑,比较麻烦, 解决方式:
* i 从 最后一个节点的父节点出开始迭代,直到i = 0;
* 每次检查时,将大的节点交换到末尾——就是要到底,如果大,就要成为叶节点,不是只交换一次(用循环)
*
* 那么就有两种构建方法:
* 1.乱序构建,调整( 一个一个添加(从数组中),添加到最后一个,树的最右最下方的那个,然后siftUp,从下往上调整就可以了 ,O(log2(n)))
* 2.一次一节点,依次调整
*
* <p>
* 思考题: 设计算法检查一个完全二叉树是不是堆,是的话是最大堆还是最小堆。
* 思路:元素1个,同为最大最小堆
* 元素>1个:
* 判断第一二个大小
* 第一个大: 可能为最大堆,然后递归校验,如果每一个节点都比子节点大,那么是最大堆,否则不是堆
* 第二个大: 可能为最小堆,然后递归校验,如果每一个节点都比子节点小,那么是最小堆,否则不是堆
* <p>
*
*时间复杂度分析:
* 建树:两种方式都是 O(nlog2(n))
* 插入: O(log2(n))
* 删除: O(log2(n))
*/ public class Heap {
private int[] data;
private final int maxSize = 128; //预设大小,足够就行
private int heapSize; //实际大小 public Heap(int[] input) {
data = new int[maxSize];
heapSize = input.length;
for (int i = 0; i < heapSize; i++) {//这个地方其实并不好,只是将传入的数组读入我的数组中,一方有不断插入操作,如果没有插入操作则不必要;
data[i] = input[i];
}
} public void build_1() {
/**
* 建树方法1:
* 每次插入一个节点
*/
int a = heapSize;
heapSize = 0;
for (int i = 0; i < a; i++) {
insert(data[i]);
}
} public void build_2() {
/**
* 建树方法2:
* 以原来的乱序进行调整:siftDown
*/
if (heapSize <= 1) return;
for (int i = getParent(heapSize - 1); i >= 0; i--) { // 从末元素的父节点开始,一次一次进行siftDown
siftDown(i);
}
} /**
* 由上而下调整, sift——筛
* @param start
*/
public void siftDown(int start) {
//start至少1子,不用担心溢出问题
while (getLeft(start) < heapSize) { //注意,这里必须是小于,不能等于,如果该节点的左节点是末尾节点则结束,条件是getLeft(start)==heapSize-1
int min = 0;//判别有没有发生交换的条件
//无右子
if (getRight(start) >= heapSize) {
if (data[start] > data[getLeft(start)]) {
min = getLeft(start);
swap(start, min);
}
}
//2子
else {
min = data[getLeft(start)] > data[getRight(start)] ? getRight(start) : getLeft(start);
if (data[start] > data[min]) {
swap(start, min);
}
}
if (min == 0) break;//满足堆条件,退出
start = min; //不满足堆条件,还可以调整,继续循环
}
} /**
* 由下而上调整
* @param start 开始的下标
*/
public void siftUp(int start) {
if (start <= 0) return;
while (data[start] < data[getParent(start)]) { //一直发生交换,直到满足条件
swap(start, getParent(start));
start = getParent(start);
if (start <= 0) break;// root
}
} public void insert(int a) {
/**
* 插入的话会使数组长度加一,比较麻烦,于是我建立一个比较大的树,用一个较大的量maxSize来限定堆的最大容量,用heapSize来声明实际的容量
*/
data[heapSize] = a;
siftUp(heapSize);
heapSize++;
} public int getLeft(int i) {
return 2 * i + 1;
} public int getRight(int i) {
return 2 * i + 2;
} public int getParent(int i) {
if (i == 0) return -1;
return (i - 1) >> 1; //除以2
} public void swap(int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
} public void display() {
for (int i = 0; i < heapSize; i++) {
System.out.print(data[i] + " ");
}
System.out.println();
} public static void main(String[] args) {
int[] a = new int[]{8, 12, 2, 5, 3, 7, -1, 44, 23};
Heap heap = new Heap(a);
heap.display();
// heap.build_1();
heap.build_2();
heap.insert(-4);
heap.display();
}
}
堆(Heap)详解——Java实现的更多相关文章
- 详解Java GC的工作原理+Minor GC、FullGC
详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...
- Protocol Buffer技术详解(Java实例)
Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
- java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的
本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...
- 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)
在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
- 第三节:带你详解Java的操作符,控制流程以及数组
前言 大家好,给大家带来带你详解Java的操作符,控制流程以及数组的概述,希望你们喜欢 操作符 算数操作符 一般的 +,-,*,/,还有两个自增 自减 ,以及一个取模 % 操作符. 这里的操作算法,一 ...
- 第十八节:详解Java抽象类和接口的区别
前言 对于面向对象编程来说,抽象是它的特征之一. 在Java中,实现抽象的机制分两种,一为抽象类,二为接口. 抽象类为abstract class,接口为Interface. 今天来学习一下Java中 ...
- 详解java动态代理机制以及使用场景
详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...
- 【转帖】windows命令行中java和javac、javap使用详解(java编译命令)
windows命令行中java和javac.javap使用详解(java编译命令) 更新时间:2014年03月23日 11:53:15 作者: 我要评论 http://www.jb51.ne ...
- 超全详解Java开发环境搭建
摘自:https://www.cnblogs.com/wangjiming/p/11278577.html 超全详解Java开发环境搭建 在项目产品开发中,开发环境搭建是软件开发的首要阶段,也是必 ...
随机推荐
- pyqt5-QWidget-窗口状态(最大化最小化等)
setWindowState(state) #设置窗口状态 Qt.WindowNoState 无状态-正常状态 Qt.WindowMinimized 最小化 Qt.Wind ...
- Django之CRM项目Day5-跳转页面 跟进记录 报名记录
1 编辑和添加后跳转页面: 思路:写一个参数将路径的条件带上 注意:捋流程的时候从urls里开始 1.在crm文件夹下新建python包:templatetags,在包里新建url.py: from ...
- Python常用模块之time模块
python中的time和datetime模块是时间方面的模块 time模块中时间表现的格式主要有三种: 1.timestamp:时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算 ...
- 使用IDEA新建Web工程启动报404的错误
新换了一个项目组被人吐槽配置文件都能写错,所以打算从头开始一步步搭建一个项目,包含ssm基础框架.mongodb工具类.redis工具类.jsf配置.log配置等 今天先来搭建一个web工程.工程搭建 ...
- okhttp3与旧版本okhttp的区别分析
https://www.jianshu.com/p/4a8c94b239b4 待总结学习
- RedisGeo
redis3.2版本增加了对GEO(地理位置)的支持 操作命令 geoadd(String key, Double longitude, Double latitude, String member) ...
- v2v-VMware/VSphere中虚机离线迁移至openstack平台
先决条件 exsi到openstack的迁移,分为两种,一种是静态迁移,另一种是在线迁移. 静态迁移(offline migration)也叫做常规迁移,离线迁移.在迁移之前将虚拟机暂停,同时拷贝虚拟 ...
- SpringCloud概述
⒈官网说明 SpringCloud是基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现.配置中心.全链路监控.服务网关.负载均衡.熔断器等组件,除了基于Netflix的开源组件做高度 ...
- Linux就该这么学(3)-管道符、重定向与环境变量(学习笔记)
1.Linux命令与文件读写操作有关的重定向技术: 学习目标:主要解决输出信息的保存问题. 标准覆盖输出重定向: 标准追加输出重定向 错误覆盖输出重定向 错误追加输出重定向 输入重定向 标准输入(ST ...
- Kafka管理工具介绍【转】
Kafka内部提供了许多管理脚本,这些脚本都放在$KAFKA_HOME/bin目录下,而这些类的实现都是放在源码的kafka/core/src/main/scala/kafka/tools/路径下. ...