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开发环境搭建 在项目产品开发中,开发环境搭建是软件开发的首要阶段,也是必 ...
随机推荐
-
Nodejs创建客户端
Node 创建 Web 客户端需要引入 http 模块,创建 client.js 文件,代码如下所示: var http = require('http'); //用于请求的选项 var option ...
-
Qt多文档界面应用设计
使用Qt编写多文档界面(MDI)应用相当方便,主要会使用到QMdiArea和QMdiSubWindow两个类.可以查看Qt Asistant中这两个类的说明文档,里面介绍的相当详细.另外,可以搜索例程 ...
-
双系统win7和ubuntu14.04进入了grub rescue>;
可以跳过的废话:最近在学习caffe,需要在linux下安装cuda,sudo apt-get install cuda后,出现了由于根目录/空间不足而失败的情况. 于是想把win7下80G的一个盘格 ...
-
woe_iv原理和python代码建模
python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...
-
性能调优2:CPU
关系型数据库严重依赖底层的硬件资源,CPU是服务器的大脑,当CPU开销很高时,内存和硬盘系统都会产生不必需要的压力.CPU的性能问题,直观来看,就是任务管理器中看到的CPU利用率始终处于100%,而侦 ...
-
Linux安装软件出现 “Unable to locate package xxx”错误
使用新购入的阿里云服务器ECS,预装的Ubuntu,然后想要利用 xrdp 进行远程登陆,但是在输入命令: apt-get install xrdp 出现了 E;Unable to locate pa ...
-
RabbitMQ 内存控制 硬盘控制
RabbitMQ服务器在启动时以及abbitmqctl set_vm_memory_high_watermark fraction 执行时,会检查计算机的RAM总大小. 默认情况下下, 当 Rabbi ...
-
Oracle学习笔记—Db_name、Db_domain、Global_name、Service_name、Instance_name和Oracle_SID(转载)
转载自: Oracle中DB_NAME,SID,DB_DOMAIN,SERVICE_NAME等之间的区别 Db_name:对一个数据库(Oracle database)的唯一标识.这种表示对于单个数据 ...
-
windows 右健添加cmd快捷通道
windows 右健添加cmd快捷 - Windows - geektown极客堂 - Powered by Discuz!. 把横线下面的文本copy保存到一个注册表文件中,比如cmd.reg,然后 ...
-
bzoj 3267: KC采花&;&;3272&;&;3638&;&;3502 线段树
题目大意 给定一个长为n的序列,维护两种操作: 1.单点修改 2.在[l,r]这段区间中取k个互不相交的子段,使子段之和最大. \(n \leq 50000,k \leq 20\) 题解 四倍经验.( ...