数据结构基础-堆

news/2024/11/24 7:00:33/

堆实现

计算机科学中,堆是一种基于树的数据结构,通常用完全二叉树实现。堆的特性如下

  • 在大顶堆中,任意节点 C 与它的父节点 P 符合 P.value \geq C.value
  • 而小顶堆中,任意节点 C 与它的父节点 P 符合 P.value \leq C.value
  • 最顶层的节点(没有父亲)称之为 root 根节点

In computer science, a heap is a specialized tree-based data structure which is essentially an almost complete tree that satisfies the heap property: in a max heap, for any given node C, if P is a parent node of C, then the key (the value) of P is greater than or equal to the key of C. In a min heap, the key of P is less than or equal to the key of C. The node at the “top” of the heap (with no parents) is called the root node

例1 - 满二叉树(Full Binary Tree)特点:每一层都是填满的
在这里插入图片描述

例2 - 完全二叉树(Complete Binary Tree)特点:最后一层可能未填满,靠左对齐
在这里插入图片描述

例3 - 大顶堆
在这里插入图片描述

例4 - 小顶堆
在这里插入图片描述

完全二叉树可以使用数组来表示
在这里插入图片描述

特征

  • 如果从索引 0 开始存储节点数据
    • 节点 i 的父节点为 floor((i-1)/2),当 i>0 时
    • 节点 i 的左子节点为 2i+1,右子节点为 2i+2,当然它们得 < size
  • 如果从索引 1 开始存储节点数据
    • 节点 i 的父节点为 floor(i/2),当 i > 1 时
    • 节点 i 的左子节点为 2i,右子节点为 2i+1,同样得 < size

代码

public class PriorityQueue4<E extends Priority> implements Queue<E> {Priority[] array;int size;public PriorityQueue4(int capacity) {array = new Priority[capacity];}@Overridepublic boolean offer(E offered) {if (isFull()) {return false;}int child = size++;int parent = (child - 1) / 2;while (child > 0 && offered.priority() > array[parent].priority()) {array[child] = array[parent];child = parent;parent = (child - 1) / 2;}array[child] = offered;return true;}private void swap(int i, int j) {Priority t = array[i];array[i] = array[j];array[j] = t;}@Overridepublic E poll() {if (isEmpty()) {return null;}swap(0, size - 1);size--;Priority e = array[size];array[size] = null;shiftDown(0);        return (E) e;}void shiftDown(int parent) {int left = 2 * parent + 1;int right = left + 1;int max = parent;if (left < size && array[left].priority() > array[max].priority()) {max = left;}if (right < size && array[right].priority() > array[max].priority()) {max = right;}if (max != parent) {swap(max, parent);shiftDown(max);}}@Overridepublic E peek() {if (isEmpty()) {return null;}return (E) array[0];}@Overridepublic boolean isEmpty() {return size == 0;}@Overridepublic boolean isFull() {return size == array.length;}
}

以大顶堆为例,相对于之前的优先级队列,增加了堆化等方法

public class MaxHeap {int[] array;int size;public MaxHeap(int capacity) {this.array = new int[capacity];}/*** 获取堆顶元素** @return 堆顶元素*/public int peek() {return array[0];}/*** 删除堆顶元素** @return 堆顶元素*/public int poll() {int top = array[0];swap(0, size - 1);size--;down(0);return top;}/*** 删除指定索引处元素** @param index 索引* @return 被删除元素*/public int poll(int index) {int deleted = array[index];swap(index, size - 1);size--;down(index);return deleted;}/*** 替换堆顶元素* @param replaced 新元素*/public void replace(int replaced) {array[0] = replaced;down(0);}/*** 堆的尾部添加元素** @param offered 新元素* @return 是否添加成功*/public boolean offer(int offered) {if (size == array.length) {return false;}up(offered);size++;return true;}// 将 offered 元素上浮: 直至 offered 小于父元素或到堆顶private void up(int offered) {int child = size;while (child > 0) {int parent = (child - 1) / 2;if (offered > array[parent]) {array[child] = array[parent];} else {break;}child = parent;}array[child] = offered;}public MaxHeap(int[] array) {this.array = array;this.size = array.length;heapify();}// 建堆private void heapify() {// 如何找到最后这个非叶子节点  size / 2 - 1for (int i = size / 2 - 1; i >= 0; i--) {down(i);}}// 将 parent 索引处的元素下潜: 与两个孩子较大者交换, 直至没孩子或孩子没它大private void down(int parent) {int left = parent * 2 + 1;int right = left + 1;int max = parent;if (left < size && array[left] > array[max]) {max = left;}if (right < size && array[right] > array[max]) {max = right;}if (max != parent) { // 找到了更大的孩子swap(max, parent);down(max);}}// 交换两个索引处的元素private void swap(int i, int j) {int t = array[i];array[i] = array[j];array[j] = t;}public static void main(String[] args) {int[] array = {1, 2, 3, 4, 5, 6, 7};MaxHeap maxHeap = new MaxHeap(array);System.out.println(Arrays.toString(maxHeap.array));}
}

建堆

Floyd 建堆算法作者(也是之前龟兔赛跑判环作者):
在这里插入图片描述

  1. 找到最后一个非叶子节点
  2. 从后向前,对每个节点执行下潜

一些规律

  • 一棵满二叉树节点个数为 2^h-1,如下例中高度 h=3 节点数是 2^3-1=7
  • 非叶子节点范围为 [0, size/2-1]

算法时间复杂度分析
在这里插入图片描述

下面看交换次数的推导:设节点高度为 3

本层节点数高度下潜最多交换次数(高度-1)
4567 这层410
23这层221
1这层132

每一层的交换次数为:节点个数*此节点交换次数,总的交换次数为

\begin{aligned}
& 4 * 0 + 2 * 1 + 1 * 2 \

& \frac{8}{2}*0 + \frac{8}{4}*1 + \frac{8}{8}*2 \

& \frac{8}{2^1}*0 + \frac{8}{2^2}*1 + \frac{8}{2^3}*2\

\end{aligned}

\sum_{i=1}{h}(\frac{2h}{2^i}*(i-1))

在 https://www.wolframalpha.com/ 输入

Sum[\(40)Divide[Power[2,x],Power[2,i]]*\(40)i-1\(41)\(41),{i,1,x}]

推导出

2^h -h -1

其中 2^h \approx n,h \approx \log_2{n},因此有时间复杂度 O(n)


http://www.ppmy.cn/news/244262.html

相关文章

41 管理虚拟机可维护性-虚拟机NMI Watchdog

文章目录 41 管理虚拟机可维护性-虚拟机NMI Watchdog41.1 概述41.2 注意事项41.3 操作步骤 41 管理虚拟机可维护性-虚拟机NMI Watchdog 41.1 概述 NMI Watchdog是一种用来检测Linux出现hardlockup&#xff08;硬死锁&#xff09;的机制。通过产生NMI不可屏蔽中断&#xff0c;…

常用模拟低通滤波器的设计——契比雪夫I型滤波器

常用模拟低通滤波器的设计——契比雪夫I型滤波器 巴特沃斯滤波器的频率特性曲线在通带和阻带内&#xff0c;幅度特性是单调下降的&#xff0c;如果阶次一定&#xff0c;则在靠近截止处&#xff0c;幅度下降很多&#xff0c;或者说&#xff0c;为了使通带内衰减足够小&#xff0…

【软件开发】MyBatis 理论篇

MyBatis 理论篇 1.MyBatis 是什么&#xff1f; MyBatis 是一个半 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了 JDBC&#xff0c;开发时只需要关注 SQL 语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。…

【新日语】第6課 5歳の園児のクラスは一つしかありません

基本句型 1. スーツケースの中にワイシャツが3枚あります。 手提箱的里面那三件衬衫存在呢。or 有3件衬衫呢。 この学校に先生が36人います。 这所学校里教师36名存在呢。or 有36名教师呢。 2. 冷蔵庫の中に 食べ物は 何もありません。 冷箱的里面食物呀什么都没有呢。 …

python-常用的内置函数

文章目录 一、函数的引入二、变量的作用域三、参数传递四、常见的4类形参1. 必选参数:必须要传递的参数2. 默认参数:可传可不传的参数3. 可变参数: 参数的个数会变化&#xff0c;可以传0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;......n4. 关键字参数:可以传递key和…

【23JavaScript 类型转换】探索JavaScript类型转换:从隐式到显式,轻松掌握数据类型转换的关键概念与技巧

JavaScript 类型转换 在JavaScript中&#xff0c;类型转换是将一个数据类型的值转换为另一个数据类型的过程。了解类型转换的原理和方法对于处理数据和编写有效的代码至关重要。 隐式类型转换 JavaScript中经常会发生隐式类型转换&#xff0c;即在操作中自动进行的类型转换。…

总结6种服务限流的实现方式

服务限流&#xff0c;是指通过控制请求的速率或次数来达到保护服务的目的&#xff0c;在微服务中&#xff0c;我们通常会将它和熔断、降级搭配在一起使用&#xff0c;来避免瞬时的大量请求对系统造成负荷&#xff0c;来达到保护服务平稳运行的目的。下面就来看一看常见的6种限流…

九、(补充文章四)Arcgis实现深度学习训练样本数据的批量制作——只靠原图+shp如何批量制作样本图片

之前写了一些个深度学习系列文 其中先是单张样本的制作方法 最后通过构造模型批量处理 大大提高了生成样本的速度 四、Arcgis实现深度学习河流训练样本数据的制作(使用软件批量获取样本图片)——对已经获取到的完整面状样本数据进行处理 但是这个方法不仅仅需要shp和原图 还需要…