深入理解堆结构:基础、应用及代码实践

文章目录

      • 第一章:堆的定义和特性
        • 1. 堆的基本定义
        • 2. 完全二叉树
        • 3. 堆的类型和特性
      • 第二章:堆的内部结构
        • 1. 二叉堆的数组表示法
        • 2. 索引关系
      • 第三章:堆的基本操作
        • 1. 插入操作
        • 2. 删除操作
        • 3. 堆化(Heapify)过程
      • 第四章:堆的应用
        • 1. 优先队列的实现
        • 2. 堆排序
        • 3. 堆在图算法中的应用
      • 第五章:高级话题
        • 1. 斐波那契堆
        • 2. 左偏树(左式堆)
        • 3. 斜堆
      • 第六章:实际代码示例
        • 1. 创建和插入元素
        • 2. 删除堆顶元素
        • 3. 堆排序
        • 4. 示例应用:优先队列

堆是一种关键的数据结构,它在许多算法和系统设计中发挥着核心作用。本文深入探讨了堆的定义、内部结构、操作方式及其广泛应用,提供了实际的示例以加深理解。

第一章:堆的定义和特性

堆(Heap)是一种特殊的完全二叉树,通常用数组来实现,它满足堆性质,即在这个数据结构中,每一个父节点的值都与其子节点的值保持一定的大小关系。这种特性使得堆非常适合实现优先队列,其中元素的添加和移除都能保持较高的效率。堆主要分为两类:大根堆和小根堆。

1. 堆的基本定义

堆是一种可以迅速找到最大值或最小值的数据结构。堆通常被视为一种抽象的数据类型,可以视为一种特殊的树形结构。完全二叉树的性质保证了堆的高效性,即堆中每个节点的子树都是完全二叉树。

2. 完全二叉树

在深入堆的类型之前,我们首先理解什么是完全二叉树。完全二叉树是一种二叉树,其中所有的层都被完全填满,除了可能的最后一层。在最后一层,所有的节点都尽可能地向左对齐。这种结构使得堆可以有效地使用数组来存储,每个节点的子节点和父节点位置都可以通过简单的索引计算得出。

在这里插入图片描述

3. 堆的类型和特性
  • 大根堆:在大根堆中,任意节点的值都不小于其子节点的值。这意味着堆顶(根节点)是整个堆中的最大值。大根堆常用于实现优先队列,快速访问和删除最大元素。
  • 小根堆:与大根堆相反,在小根堆中,任意节点的值都不大于其子节点的值。这样,堆顶是整个堆中的最小值。小根堆用于需要快速访问和删除最小元素的场景,如实现升序堆排序。

在这里插入图片描述

第二章:堆的内部结构

堆通常使用数组来表示,这种表示法不仅节省空间,而且能够通过索引快速访问任何节点,特别是在二叉堆中更为常见。二叉堆是实现堆结构的一种简单且高效的方法,特别适合进行插入和删除根节点的操作。

1. 二叉堆的数组表示法

在二叉堆的数组表示中,我们不使用数组的第一个位置(索引0),使得索引计算更直观。这种方法的主要优点是可以直接通过简单的公式计算父节点和子节点的位置,无需额外的指针或链接。

  • 数组的结构:堆可以被视为一个完全二叉树,树中的每一层从左到右填满,只有最底层可能未完全填满,且也是从左到右填入。这使得数组的连续空间可以有效地表示树的结构。
2. 索引关系

在二叉堆的数组表示中,节点之间的父子关系通过数组索引来表示,具体计算方法如下:

  • 父节点到子节点的索引计算

    • 对于任何位于索引 i 的节点,其左子节点的索引为 2*i
    • 右子节点的索引为 2*i + 1

    这样的索引计算保证了无论堆多大,左右子节点的查找都是常数时间的操作。

  • 子节点到父节点的索引计算

    • 对于任何位于索引 i 的节点,其父节点的索引为 i/2(整除)。

    这个计算同样有效快速,使得从子节点访问父节点也是一个常数时间的操作。

在这里插入图片描述

这种索引方法的优点是简单和高效,能够迅速定位到任何节点的父节点或子节点,这对于执行堆操作如插入和删除至关重要。通过这样的结构,插入新节点或删除节点(特别是堆顶节点)时,都能快速调整堆以维持其性质。

第三章:堆的基本操作

堆作为一种高效的数据结构,主要用于优先队列的实现,其效率在很大程度上依赖于几个核心操作的高效执行:插入、删除和堆化。这些操作都必须能够快速调整堆以保持其基本性质,无论是大根堆还是小根堆。

1. 插入操作

在堆中插入新元素通常涉及以下步骤:

  • 步骤1:添加至末尾
    新元素首先被添加到堆的末尾,即数组的最后。这一步保持了完全二叉树的结构。
  • 步骤2:上浮调整(Percolate Up)
    插入元素后,如果它违反了堆的性质(例如,在大根堆中,如果这个新元素比它的父节点大),则需要进行调整。新元素与其父节点比较,如果条件满足(大根堆中比父节点大,小根堆中比父节点小),则与父节点交换位置,这一过程称为“上浮”。这一过程重复进行,直到新元素到达一个位置,它不再违反堆的性质或者已经到达堆的顶部。
2. 删除操作

堆的删除操作通常指删除堆顶元素,这是因为堆主要用于访问和移除其顶部元素(最大或最小)。删除堆顶元素的步骤如下:

  • 步骤1:移除顶部
    移除堆顶元素后,通常将堆中的最后一个元素移至顶部,以保持完全二叉树的结构。
  • 步骤2:下沉调整(Percolate Down)
    将最后一个元素移至顶部后,开始进行“下沉”操作以重新恢复堆的性质。这一过程涉及将新的顶部元素与其子节点比较,并与其中更大(大根堆)或更小(小根堆)的子节点进行交换,直到该元素处于正确的位置或到达叶子节点层。
3. 堆化(Heapify)过程

堆化是创建或重建堆的过程,特别是从一个无序的数组开始构建堆时使用。这个过程关键在于从最后一个非叶子节点开始,逐个向上进行下沉调整:

  • 从最后一个非叶子节点开始
    在数组表示中,最后一个非叶子节点可以通过数组长度直接计算得出。然后,从这个节点开始,向数组的起始位置逐个应用下沉调整。
  • 逐层下沉
    对每个非叶子节点,检查其与子节点的关系,并进行必要的交换,以确保每个考虑的节点都能维持堆的性质。

第四章:堆的应用

堆结构由于其高效的插入和删除最大或最小元素的特性,被广泛应用于多种算法和数据结构中,尤其是在优先队列、排序和图算法中的应用最为突出。下面详细介绍这些应用。

1. 优先队列的实现

优先队列是一种特殊的队列,其中的元素带有优先级,优先级最高的元素最先被移除。堆结构是实现优先队列的理想选择:

  • 特性利用:在优先队列中,插入操作需要将新元素加入到正确的位置以保持队列的有序性。使用堆结构,可以保证插入和删除操作的时间复杂度为 O(log n)。
  • 场景应用:优先队列在多种场景下有广泛应用,如任务调度、带优先级的待处理事件列表等。
2. 堆排序

堆排序是一种利用堆进行排序的算法,它通过堆的特性来实现高效的排序过程:

  • 过程描述
    • 建堆:首先将所有待排序的元素构建成一个堆,确保所有的父节点都大于或小于其子节点(大根堆或小根堆)。
    • 排序:将堆顶元素(最大或最小)与堆的最后一个元素交换,然后减少堆的大小,并对新的堆顶元素进行下沉操作以重新满足堆的条件。重复此过程,直到堆中仅剩下一个元素。
  • 效率:堆排序的时间复杂度为 O(n log n),且不需要额外的存储空间,使其成为一种效率和资源使用都优良的排序方法。
3. 堆在图算法中的应用

堆结构在图算法中尤为重要,特别是在路径查找和最小生成树算法中:

  • Dijkstra 算法:用于找到图中单个源点到其他所有点的最短路径。在这个算法中,使用小根堆来持续追踪未处理的最近顶点。
  • Prim 算法:用于找到图的最小生成树。此算法同样利用小根堆来优化每次选择图中权重最小的边的过程。

在这两种算法中,堆结构的主要作用是快速提取当前考虑的最小(或最大)元素,这是算法效率的关键。

第五章:高级话题

堆的基本形式如二叉堆虽广泛使用,但在某些特定应用场景中,其性能可能不足以满足需求。因此,研究者们开发了更复杂的堆结构,如斐波那契堆、左偏树(左式堆)和斜堆,它们在特定操作上具有更优的性能表现。

1. 斐波那契堆

斐波那契堆是一种优化的堆结构,特别适合于有大量元素插入和少量删除最小元素的需求的应用场景:

  • 性能特点
    • 插入操作:斐波那契堆的插入操作的摊销成本为 O(1),这是因为新元素简单地插入到根列表中,不立即进行合并。
    • 删除最小元素操作:摊销成本为 O(log n),在删除操作后,斐波那契堆需要重新组织堆,以恢复其结构。
    • 其他操作:如减少键值和合并两个堆的操作也具有较低的摊销成本。
  • 应用场景
    • 斐波那契堆在图算法中尤为有用,比如在实现更高效的 Dijkstra 算法和 Prim 算法中。
2. 左偏树(左式堆)

左偏树或左式堆是一种保证树的深度尽可能小的堆结构,主要用于优化堆的合并操作:

  • 特性
    • 左式堆通过一个称为“零路径长度”的额外参数来确保左子树的深度至少与右子树一样深,这使得堆能快速合并。
    • 插入、删除和合并操作的复杂度通常为 O(log n)。
  • 合并操作
    • 合并两个左式堆的操作是通过比较两个堆的根节点,并递归地合并较大根节点的右子树和另一个堆实现的。
3. 斜堆

斜堆是左式堆的一个变种,去除了左式堆中对树形态的严格要求,使其成为一种自调整形式的堆:

  • 性能特点:
    • 斜堆实现了堆的基本操作,如插入、删除和合并,但在执行合并操作时会通过简单的“旋转”来调整树的结构,保证操作的效率。
    • 斜堆的操作大多数情况下也是 O(log n) 的时间复杂度。

这些高级堆结构在处理大规模数据和特定算法优化中显示出其独特的优势。通过选择合适的堆结构,可以显著提高数据处理和算法执行的效率,特别是在动态数据集合管理和图算法优化中。

第六章:实际代码示例

在这一章节中,我们将通过 Python 代码来展示如何实现基本的堆操作,包括创建堆、插入元素、删除堆顶元素以及堆排序。Python 由于其简洁性和广泛的库支持,是展示数据结构算法的理想选择。

1. 创建和插入元素

首先,我们将创建一个最小堆,并展示如何插入新元素:

import heapqdef create_heap():return []def heap_insert(heap, element):heapq.heappush(heap, element)return heap# 创建堆并插入元素
heap = create_heap()
heap = heap_insert(heap, 10)
heap = heap_insert(heap, 5)
heap = heap_insert(heap, 15)
print("Heap after insertions:", heap)
2. 删除堆顶元素

删除堆顶元素,并观察堆的变化:

def remove_min(heap):return heapq.heappop(heap)# 删除堆顶元素
min_element = remove_min(heap)
print("Removed element:", min_element)
print("Heap after removal:", heap)
3. 堆排序

实现堆排序,这里我们将使用最小堆进行示范:

def heap_sort(elements):heap = []sorted_list = []# 构建堆for element in elements:heapq.heappush(heap, element)# 逐个移除元素while heap:sorted_list.append(heapq.heappop(heap))return sorted_list# 测试堆排序
unsorted_elements = [20, 5, 15, 10, 0]
sorted_elements = heap_sort(unsorted_elements)
print("Sorted elements:", sorted_elements)
4. 示例应用:优先队列

最后,我们用一个实际的例子来展示如何使用堆作为优先队列:

import heapqclass PriorityQueue:def __init__(self):self.heap = []def push(self, priority, item):# 堆元素为元组,包含优先级和项目heapq.heappush(self.heap, (priority, item))def pop(self):return heapq.heappop(self.heap)[1]  # 返回项目# 创建和使用优先队列
pq = PriorityQueue()
pq.push(1, "task1")
pq.push(3, "task3")
pq.push(2, "task2")print("Tasks by priority:")
while pq.heap:print(pq.pop())

这些示例提供了使用 Python 的 heapq 模块来实现堆的基本操作和应用的一个简单介绍。heapq 模块内部实现了二叉堆,并提供了堆操作的各种方法,使得堆的使用变得简单方便。


参考:

  • Complete Binary Tree
  • Heap Data Structure
  • Heaps/Priority Queues

推荐:

  • python 错误记录
  • python 笔记

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2999126.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

黑客常用的PHP漏洞利用技术

黑客常用的PHP漏洞利用技术 随着互联网的普及和发展,网络安全问题也成为了一个全球性的难题。而黑客作为网络安全的"敌人",其手法也是不断创新和进化的。而在黑客攻击中,基于PHP的网站往往成为主要目标之一。PHP是一种功能强大且广…

鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的

精读内核源码就绕不过汇编语言,鸿蒙内核有6个汇编文件,读不懂它们就真的很难理解以下问题. 1.系统调用是如何实现的? 2.CPU是如何切换任务和进程上下文的? 3.硬件中断是如何处理的? 4.main函数到底是怎么来的? 5.开机最开始发生了什么? 6.关机…

iOS 17上如何恢复数据?iOS 17 数据恢复软件

“您好,我正在为我的 iPhone 寻找一款iOS 17 数据恢复软件。升级到 iOS 17 后,我丢失了 iPhone 上的所有照片、联系人和消息。有什么建议吗?” ——丹尼 iOS 17数据恢复软件下载 升级到iOS 17后如何恢复丢失的数据?由于在 iPhone…

B端界面:美不胜收,第二弹12张。

上次分享第一期受到了大家欢迎,第二期来了,老规矩12张,欢迎大家来捧场。

JAVA同城服务美容美发到店服务上门服务系统源码微信小程序+微信公众号+H5+APP

随着科技的飞速发展,互联网和移动互联网已经渗透到我们生活的方方面面,同城服务美容美发到店服务上门服务系统应运而生,为整个行业带来了巨大的变革和无限的可能。该系统的重要性和优势不言而喻,对于行业发展和用户需求的影响深远…

C语言----链表

大家好,今天我们来看看C语言中的一个重要知识,链表。当然大家可以先从名字中看出来。就是一些表格用链子连接。那么大家是否想到了我们以前学的数组,因为数组也是相连的呀。是吧。但是链表与数组还是有区别的,那么链表是什么有什么…

Centos7安装K8S集群环境

一、系统设置 1、关闭swap 临时关闭swap swapoff -a 永久关闭 注释掉 /etc/fstab 中的下面配置 #/dev/mapper/centos-swap swap swap defaults 0 0 2、 关闭SELinux kubelet不支持SELinux, 这里需要将SELinux设置为permissive模式 setenforce 0 sed -i s/^SELINUXenfo…

使用 LooperPrinter 监控 Android 应用的卡顿

在 Android 开发中,主线程(UI线程)的卡顿直接影响用户体验。LooperPrinter 是一种有效的工具,可以帮助我们监测和识别这些卡顿。下面是如何实现 LooperPrinter 监控的详细步骤和相应的 Kotlin 代码示例。 步骤 1: 创建自定义的 P…

时序分解 | Matlab实现RLMD鲁棒性局部均值分解

时序分解 | Matlab实现RLMD鲁棒性局部均值分解 目录 时序分解 | Matlab实现RLMD鲁棒性局部均值分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现RLMD鲁棒性局部均值分解,可直接替换 Matlab语言 1.算法新颖小众,用的人很少,包含分解图…

公考学习平台|基于SprinBoot+vue的公考学习平台(源码+数据库+文档)

公考学习平台目录 目录 基于SprinBootvue的公考学习平台 一、前言 二、系统设计 三、系统功能设计 5.1用户信息管理 5.2 视频信息管理 5.3公告信息管理 5.1论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

万万没想到,原来这些维生素对帕金森有好处!

亲爱的读者朋友们,今天我们要聊一个特别的群体——帕金森病患者。在面对这一神经系统退行性疾病时,除了遵循医嘱进行药物治疗和康复锻炼,合理的饮食和营养补充也显得尤为重要。那么,究竟哪些维生素是他们不可或缺的呢?…

小剧场短剧影视小程序源码_后端PHP

项目运行截图 源码贡献 https://githubs.xyz/boot?app42 部署说明 linux/win任选 PHP版本:7.3/7.2(测试时我用的7.2要安装sg扩展 ) 批量替换域名http://video.owoii.com更换为你的 批量替换域名http://120.79.77.163:1更换为你的 这两个…

基于python的舞蹈经验分享交流网站django+vue

1.运行环境:python3.7/python3.8。 2.IDE环境:pycharmmysql5.7/8.0; 3.数据库工具:Navicat11 4.硬件环境:windows11/10 8G内存以上 5.数据库:MySql 5.7/8.0版本; 运行成功后,在浏览器中输入&am…

使用JNI机制加载本地方法的小案例

JNI 最近在学习Android,其中需要使用到c的库,这个时候就要使用到JNI机制了,简单来说,就是可以通过这个机制,让java代码可以调用本地c语言编写的代码,将c语言编写的代码打包成动态库,然后&#…

新华三李玉涛:智算网络是解决AI算力需求的关键

近年来,人工智能领域呈现爆发式增长,尤其在OpenAI、文心一言等大模型的不断推出,参数规模实现了飞跃式增长。同时,Character AI、谷歌Bard等应用已经逐渐渗透至日常生活和工作当中,越来越多的人开始借助AIGC工具来提升…

大气污染扩散模型Calpuff技术应用

目前,大气污染仍为我国亟待解决的环境问题。为了弄清大气污染物排放后对周围环境的影响,需要了解污染物的扩散规律。Calpuff模型是一种三维非稳态拉格朗日扩散模型,可有效地处理非稳态(如,熏烟、环流、地形和海岸等&am…

(06)vite与ts的结合

文章目录 系列全集package.json在根目录创建 tsconfig.json 文件在根目录创建 vite.config.ts 文件index.html额外的类型声明 系列全集 (01)vite 从启动服务器开始 (02)vite环境变量配置 (03)vite 处理 c…

PyQt5如何在Qtdesigner里修改按钮形状、大小、按钮颜色、字体颜色等参数,尤其是如何将按钮修改成圆形。

步骤如下: 1、右键选中你要修改的按钮,此处以Pushbutton为例,选择“改变样式表”,打开编辑样式表对话框,如下图所示 2、在编辑样式表对话框中输入如下代码: QPushButton{ border:1px solid red; /*边框…

扭蛋机小程序体验:线上扭蛋的无限魅力

随着科技的发展和互联网的普及,传统娱乐方式正逐渐与线上平台相结合,为用户带来全新的体验。扭蛋机小程序,作为这一趋势下的产物,凭借其独特的玩法和无限的魅力,正逐渐成为线上娱乐的新宠。 一、线上扭蛋机小程序的魅力…

使用MATLAB/Simulink的PID控制系统设计和自动调整

书籍:Pid Control System Design and Automatic Tuning Using Matlab/Simulink 作者:Liuping Wang 出版:Wiley-IEEE Press 书籍下载-《使用MATLAB/Simulink的PID控制系统设计和自动调整》本书涵盖了具有操作约束的PID控制系统的设计、实施…