堆(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开发环境搭建 在项目产品开发中,开发环境搭建是软件开发的首要阶段,也是必 ...
随机推荐
- SSH整合方案二(不带hibernate.cfg.xml)
整体结构: 1.引入相关jar包 2.编写实体类和映射文件 package cn.zqr.domain; public class Customer { private Long cust_id; p ...
- 大规模数据导入和导出(oracle)
请期待... http://www.cnblogs.com/xwdreamer/archive/2012/06/08/2541678.html Oracle sqlldr的用法 (这个最完整) htt ...
- C++ 函数的重载和参数默认值
函数的重载和参数默认值视频教程 函数的重载注意事项: 只会根据三项内容进行重载:参数的个数.参数的类型.参数的顺序 参数默认值: 参数的默认值可以在函数的定义中也可以在函数的声明中,但不能同时有 从第 ...
- mysql案例~mysql主从复制延迟概总
浅谈mysql主从复制延迟 1 概念解读 需要知道以下几点 1 mysql的主从同步上是异步复制,从库是串行化执行 2 mysql 5.7的并行复制能加速从库重做的速度,进一步缓解 主从同步的延迟问题 ...
- ARM核心板_迅为imx6工控核心板_核心板中的小新潮
ARM核心板_迅为imx6工控核心板_核心板中的小新潮核心板参数 尺寸 51mm*61mm CPU Freescale Cortex-A9 四核 i.MX6Q,主频 1.2 GHz 内存 2GB DD ...
- Navicat for Mysql连接mysql数据库时出现 2003-Can't connect to MySql server on 'localhost'(10061)
一.环境:linux服务器下 二.问题:在windows7下使用Navicat for Mysql连接mysql数据库时出现 2003-Can't connect to MySql server on ...
- 20165337岳源 预备作业3:Linux安装及命令入门
安装虚拟机 按照基于VirtualBox虚拟机安装Ubuntu图文教程的步骤安装虚拟机,遇到的问题通过同学的帮助也得到了解决.例如:虚拟机无法选择64位系统. 常用的Linux命令 Tab 补全命令. ...
- pythonの递归锁
首先看一个例子,让我们lock = threading.Lock() 时(代码第33行),程序会卡死在这里 #!/usr/bin/env python import threading,time de ...
- SpringSecurityOAuth使用JWT Token
⒈JWT? JWT(Json Web Token),是Json的一个开放的Token标准. 1,自包含,SpringSecurityOAuth的默认Token是UUID的一个随机的无意义的字符串,并不 ...
- BIM 开发商 --广州
BIM 开发或咨询商 --广州: 1.广州君和信息技术有限公司(与二公司有合作,推荐!) 艾三维软件 www.i3vsoft.com 广州市越秀区东风中路445号越秀城市广场北塔2007 是一家为 ...