堆(Heap) 浅析
目录
- 一、堆的概念
- 二、堆的操作
- 向下调整(以小堆为例)
- 向上调整(以大堆为例)
- 建堆
- 三、堆的应用
- 优先级队列(Priority Queue)
- 入队列操作
- 出队列操作
- 代码实现
一、堆的概念
- 堆逻辑上是一棵完全二叉树
- 堆物理上是保存在数组中
- 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
- 满足任意结点的值都小于其子树中结点的值,则是小堆,或者小根堆,或者最小堆
- 堆的基本作用是,快速找集合中的最值
二、堆的操作
向下调整(以小堆为例)
思路:伪代码分析
public static void 向下调整(int[] array, int size, int index) {1.判断 index 对应的下标是不是叶子结点如果是叶子结点,直接 return2.找到两个孩子中最小的3.最小的孩子的值和 index 对应位置的值比较< 接着进行下一步== > 满足堆的性质,直接 return4.交换最小的孩子的值和 index 的值5.把最小的孩子视为 index,循环回去(从步骤 1,继续往下走)
}
引出的问题:
- 怎么判断 index 对应的位置是不是叶子结点 ?
- 怎么找最小的孩子?
- 小堆是有序的吗?有序的是小堆吗?
小堆不一定是有序的,但有序的一定是小堆。
代码实现:
public class HeapTest {public static void shiftDown(int[] array, int size, int index) {while (true) {//1.判断 index 对应的下标是不是叶子结点int leftIndex = 2 * index + 1;if(leftIndex >= size) {return;}//2.找到两个孩子中最小的int minIndex = leftIndex;int rightIndex = leftIndex + 1;if(rightIndex < size && array[rightIndex] < array[leftIndex]) {minIndex = rightIndex;}//3.最小的孩子的值和 index 对应位置的值比较if(array[index] <= array[minIndex]) {return;}//4.交换最小的孩子的值和 index 的值int temp = array[index];array[index] = array[minIndex];array[minIndex] = temp;//5.把最小的孩子视为 index,循环回去(从步骤 1,继续往下走)index = minIndex;}}
}
向上调整(以大堆为例)
思路:伪代码分析
public static void adjustUp(int[] array,int size,int index) {1.判断 index 是不是树的根,如果是根,调整结束2.找到 index 的父结点3.比较父结点的值和 index 的值4.只要父结点的值 <= index,调整结束5.交换父结点和 index 的值6.把父结点看做 index,继续这个大循环
}
代码实现:
public class HeapTest {public static void adjustUp(int[] array,int size,int index) {while (true) {//1.判断 index 是不是树的根,如果是根,调整结束if(index == 0) {break;}//2.找到 index 的父结点int parentIndex = (index - 1) / 2;//3.比较父结点的值和 index 的值//4.只要父结点的值 <= index,调整结束if(array[parentIndex] <= array[index]) {break;}//5.交换父结点和 index 的值int temp = array[index];array[index] = array[parentIndex];array[parentIndex] = temp;//6.把父结点看做 index,继续这个大循环index = parentIndex;}}
}
建堆
思路:伪代码分析
public static void createHeap(int[] array, int size) {size-1 树最后一个结点的下标((size-1)-1)/2 从[(size-2)/2,0] 不断地进行向下调整
}
代码实现:
public static void createHeap(int[] array, int size) {//找到层序遍历的最后一个结点下标int lastIndex = size - 1;//找到最后一个结点的父节点的下标int lastParentIndex = lastIndex - 1 / 2;//从[(size-2)/2,0] 不断地进行向下调整for(int i = lastParentIndex; i >= 0; i++) {shiftDown(array,size,i);}
}
三、堆的应用
堆的应用有挺多:优先级队列、堆排序、TopK。
堆排序和TopK就先不浅析了,会写博客专门去分析理解,在这里就简要分析一下。
堆排序
分为两个步骤:
- 用当前需要排序的数据构建一个堆
- 不断的弹出当前堆的堆顶元素,因为小顶堆的堆顶元素一定是最小的,即可以用于排序。堆排序的本质就是,把数据构建成堆之后,弹出堆顶元素,然后互换堆顶元素和最后一个元素,不断对当前堆进行自顶向下的堆的调整,然后继续弹出。
TopK
TopK一般解决的是求解前K个最大或者最小的元素,或第K个最大或最小的元素。
拿到这类问题,我们的第一想法肯定是排序求解。但排序还会浪费一定的资源排序前K个元素,为了节省计算资源,我们需要思考的是怎么优化,聪明的你肯定想到了,是不是这最大的k个元素也不需要排序呢?
为此,我们需要构建包含K个元素的小顶堆,这个小顶堆用于存储,当前最大的k个元素。接着我们需要从第 k+1个元素开始扫描,如果被扫描的元素大于堆顶,则替换堆顶的元素,并调整堆,以保证堆内的k个元素,总是当前最大的k个元素。扫描完所有n-k个元素,最终堆中的k个元素,就是优化后求的TopK。
优先级队列(Priority Queue)
入队列操作
过程(以大堆为例):
出队列操作
过程(以大堆为例):
代码实现
public class MyPriorityQueue {private Integer[] array;private int size;public MyPriorityQueue() {array = new Integer[100];size = 0;}public Integer element() {if(size == 0) {throw new RuntimeException("空的");}return array[0];}/*** 入队列*/public void add(Integer e) {array[size] = e;size++;adjustUp(size-1);}public void adjustUp(int index) {while (true) {if(index == 0) {break;}int parentIndex = (index - 1) / 2;if(array[parentIndex] <= array[index]) {break;}int temp = array[index];array[index] = array[parentIndex];array[parentIndex] = temp;index = parentIndex;}}/*** 出队列*/public Integer remove() {if(size == 0) {throw new RuntimeException("空的");}int e = array[0];array[0] = array[size - 1];size--;adjustDown(0);return e;}private void adjustDown(int index) {while (true) {int leftIndex = 2 * index + 1;if(leftIndex >= size) {return;}int minIndex = leftIndex;int rightIndex = leftIndex + 1;if(rightIndex < size && array[rightIndex] < array[leftIndex]) {minIndex = rightIndex;}if(array[index] <= array[minIndex]) {return;}int temp = array[index];array[index] = array[minIndex];array[minIndex] = temp;index = minIndex;}}
}
测试类:
public class PriorityQueueDemo {public static void main(String[] args) {MyPriorityQueue queue = new MyPriorityQueue();queue.add(3);queue.add(5);queue.add(2);queue.add(7);System.out.println(queue.remove());//2System.out.println(queue.remove());//3System.out.println(queue.remove());//5System.out.println(queue.remove());//7}
}
运行结果:
堆(Heap) 浅析相关推荐
- 一文搞懂栈(stack)、堆(heap)、单片机裸机内存管理malloc
大家好,我是无际. 有一周没水文了,俗话说夜路走多了难免遇到鬼. 最近就被一个热心网友喷了. 说我的文章没啥营养,所以今天来一篇烧脑的. 哈哈,开个玩笑,不要脸就没人能把我绑架. 主要是最近研发第二代 ...
- JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )(转发)
这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解JAVA的底层和运行机制有 比较大的帮助. 废话不想讲了.入主题: 先了解具体的概念: JAVA的JVM的内存可分为3个区: ...
- 栈(stack)和堆(heap)
栈(stack)和堆(heap), Java程序在运行时都要开辟空间,任何软件在运行时都要在内存中开辟空间,Java虚拟机运行时也是要开辟空间的.JVM运行时在内存中开辟一片内存区域,启动时在自己的内 ...
- (深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)(C/C++存储类型总结)(内存管理)
文章目录 bss段 data段 text段 堆(heap) 栈(stack) 一个程序本质上都是由 bss段.data段.text段三个组成的. 存储类型总结 bss段 bss段(bss segmen ...
- codeforces 贪心+优先队列_算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)...
堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值:
- Java里的堆(heap)栈(stack)和方法区(method)
http://imiduo.iteye.com/blog/616310 Java里的堆(heap)栈(stack)和方法区(method) <一> 基础数据类型直接在栈空间分配, 方法的 ...
- SQL Server 堆heap 非聚集索引 Nonclustered index 行号键查找RID loopup结合执行计划过程详解
SQL Server 堆型数据与执行计划使用案例 索引的相关术语 1 堆(Heap)是一种没有指定排序的数据结构,通俗的理解堆就像是按照顺序排放的杂物.在数据库里也即是对应没有聚集索引. 2 聚集索引 ...
- java中堆栈(stack)和堆(heap)
http://www.ej38.com/showinfo/java-172156.html 堆栈是一种先进后出的数据结构,只能在一端进行输入或输出数据的操作 Stack类在java.util包中 向 ...
- JVM之堆Heap参数调优入门
JVM之堆Heap参数调优入门 目录: JVM体系结构概览 JVM之堆Heap参数调优入门 2.1 java7和 java8堆结构图 2.2 堆内存调优简介 1. JVM体系结构概览 2. JVM之堆 ...
最新文章
- 【深度学习】基于深度神经网络进行权重剪枝的算法(一)
- git 查看某个文件的历史记录
- 在正确的方向坚持下去,一直坚持下去,直到有成果
- [Jarvis OJ - PWN]——Backdoor
- Rocket - tilelink - Atomics
- win7-64bit 下oracle11g plsql 的正确安装
- Java Date Time 教程-System.currentTimeMillis()
- 电脑常见问题:能打开QQ但不能打开网页(DNS问题)
- 通常网站当中的关键词密度如何控制呢
- springboot+SSM Demo框架搭建
- 【傻瓜教程】Ubuntu18.04LTS安装NVIDIA驱动详细完整过程
- Flea CodeForces - 32C (思维)
- 网络协议分为哪几层---物理层,连接层,网络层,传输层,应用层详解
- 微软DNS服务器默认,Microsoft Windows Server DNS 配置打开地址套接字
- 草根大牛论道“下一代软件研发” 开启软件转型讨论大潮
- 记录一些面试相关的刁难题
- 浙江杭州工程师职称评审论文要求
- 大专前端实习生如何挣到月薪 20k
- 【Linux】Linux中的文件搜索和查看
- 计算机主机不能启动,电脑不启动是什么原因_电脑无法启动怎么办-win7之家
热门文章
- php编程模块英文缩写_php的英文全称是什么
- python 保留浮点数为两位小数
- linux中隐藏得木马程序,Linux远控分析
- 基于canvas实现的多功能画板
- Android开发关键知识点讲解
- CSS/HTML 如何在网页中添加空格(琐碎知识点整理)
- 【BZOJ】2277: [Poi2011]Strongbox
- 以下关于python函数说法错误的是def_以下关于Python函数的描述中,错误的是()
- [BZOJ4668] 冷战
- 数学课本上的9大变态!