数据结构 | 堆

本文简要总结堆的概念。

更新:2023 / 8 / 20


数据结构 | 堆

    • 概念
    • 方法
      • 插入
        • 步骤
      • 删除
        • 步骤
    • 示例
      • 大根堆
        • 插入
        • 删除
        • 堆排序
  • 代码实现
    • Python
      • 大根堆
        • 1.
        • 2. heapq
      • 小根堆
        • 1.
        • 2. heapq
  • 参考链接


概念

如果谈到堆排序,那么必然要说说什么是 大根堆 max heap小根堆 min heap 1

  • max heap
    若根节点存在左右子节点,那么根节点的值大于或等于左右子节点的值;
    是根结点大于或者等于左右子节点的二叉树;
  • min heap
    若根节点存在左右子节点,那么根节点的值小于或等于左右子节点的值;
    是根结点x小于或者等于左右子节点的二叉树;

那么,我们可以总结出关于 max heapmin heap 的结论:

  1. 堆是一颗完全二叉树;
  2. min heap 的根节点是堆中最小值;
    max heap 的根节点是堆中最大值;
  3. 堆适合采用顺序存储;

方法

堆最重要的两个方法就是 插入删除 方法。


插入

将一个元素插入到堆中,使之依然成为一个堆。


步骤

  1. 将元素插入到堆的尾部;
  2. 查看每个子树是否符合大(小)根堆的特点。若不符合则将节点逐层向上调整根和叶子节点的位置,直至从该节点的父节点出发到根节点是一个有序序列,直到所有节点都满足条件,最终依然构成一个堆。

删除

堆在删除元素时,只可以删除根节点,然后使剩下的节点依然成为一个堆。


步骤

  1. 删除根节点,用堆中最后元素进行填充;
  2. 查看每个子树是否符合大(小)根堆的特点。若不符合则进行调整,直至所有节点都满足条件。

示例

堆的构建过程其实就是构建一个符合大根堆或者小根堆的完全二叉树,那么就可以使用顺序表来进行存储。


大根堆

下面举例说明堆的构建过程:
将无序序列 [49, 38, 65, 97, 76, 13, 27, 40] 构建大根堆。


  1. 插入 49
    在这里插入图片描述

  2. 插入 38
    在这里插入图片描述

  3. 插入 65
    在这里插入图片描述
    因为要建立 max heap4965 不符合大根堆的特点,对其进行调整。调整后,如下所示:在这里插入图片描述

  4. 插入 97
    在这里插入图片描述
    9738 发生冲突,进行调整,
    在这里插入图片描述
    在这里插入图片描述

  5. 插入 76
    在这里插入图片描述
    7665 发生冲突,进行调整,
    在这里插入图片描述

  6. 插入 13在这里插入图片描述

  7. 插入 27
    在这里插入图片描述

  8. 插入 40
    在这里插入图片描述
    4038 发生冲突,进行调整,
    在这里插入图片描述
    至此,max heap 建立完成。可以看出,根节点是最大值。


插入

在上面的基础上,向 max heap 插入节点 99

  1. 插入 99
    在这里插入图片描述
    9940 发生冲突,进行调整,

在这里插入图片描述
9976 发生冲突,再次进行调整,

在这里插入图片描述
99 仍然和 97 存在冲突,再次进行调整,
在这里插入图片描述
至此,所有节点都符合堆的特性,99 被成功插入 max heap


删除

在上面的基础上,因为只能删除根节点,所以删除 max heap99

  1. 找到堆中最后的节点 40
    在这里插入图片描述
    删除根节点 99,根节点被删除后由最后的节点 40 进行补位。
    在这里插入图片描述
    此时的根节点 40 并不大于或等于左右子节点。因此,寻找此时左右子节点中的最大值 97 与此时的根节点 40 互换以进行调整,
    在这里插入图片描述
    此时的节点 40 并不大于或等于左子节点 76。因此,寻找此时节点 4076 进行互换,
    在这里插入图片描述
    至此,所有节点都符合堆的特性,99 被成功从 max heap 删除。

堆排序

堆排序是如何实现的呢?
堆排序其实就是堆的删除过程。每次删除的都是堆的根节点,删除后再进行调整,使得剩下的节点还是堆,然后再删除根节点。重复进行。直至堆中只有一个元素时,便可直接输出。那么删除过程中产生的这个序列即是一个有序序列 2

在这里插入图片描述
同样以上面的例子为例,来看看堆排序是如何实现的:

  1. 删除 99
    删除 99 的过程可参考上面的 删除 部分的内容。在删除 99 后,剩下的元素构成的堆如下所示:
    在这里插入图片描述
  2. 删除 97
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  3. 删除 76
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  4. 删除 65
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  5. 删除 49
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  6. 删除 40
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  7. 删除 38
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
  8. 删除 27
    剩下的元素构成的堆如下所示:
    在这里插入图片描述
    至此,堆中仅剩一个元素 13
    所以,最后排序后的序列为 [99, 97, 76, 65, 49, 40, 38, 27, 13],排序完成。

代码实现

Python

大根堆

1.

以无序序列 [49, 38, 65, 97, 76, 13, 27, 40,99] 为例,

def maxheap(arr, end):print('+' * 20 + ' max heapify ')height = int((end+1)/ 2 - 1)print(f"{'height':20}: {height}")for root in range(height, -1, -1):while True:child = root * 2 + 1print(f"{'root':20}: {root}\n{'child':20}: {child}\n{'end':20}: {end}")if child > end:print(f"-" * 20 + f' child {child} > end {end}, exit loop')breakif child+1 <= end and arr[child] < arr[child+1]:print(f"-" * 20 + f' child+1 {child + 1} <= end {end} and arr[child] {arr[child]} < arr[child+1] {arr[child + 1]}')child = child + 1print(f"{'child now':20}: {child}")if arr[root] < arr[child]:print(f"-" * 20 + f' arr[root] {arr[root]} < arr[child] {arr[child]}, root {root} child {child}')arr[root], arr[child] = arr[child], arr[root]root = childprint(f"-" * 20 + f' arr[root] {arr[root]} > arr[child] {arr[child]}, root {root} child {child} now')else:print(f"-" * 20 + f' arr[root] {arr[root]} > arr[child] {arr[child]}, root {root} child {child}, exit loop')breakreturn arrdef sortheap(arr, end):for i in range(end, 0, -1):arr[0], arr[i] = arr[i], arr[0]maxheap(arr, i-1)return arrif __name__ == '__main__':a = [49, 38, 65, 97, 76, 13, 27, 40, 99]print(f"排序前:\n{a}")print('-' * 100 + ' max heapify ')a = maxheap(a, len(a)-1)print(f"大根堆:\n{a}")print('-' * 100 + ' sort heap ')a = sortheap(a, len(a)-1)print(f"堆排序:\n{a}")

输出信息如下所示:

排序前:
[23, 15, 30, 38, 65, 97, 40, 99]
---------------------------------------------------------------------------------------------------- max heapify 
++++++++++++++++++++ max heapify 
height              : 3
root                : 3
child               : 7
end                 : 7
-------------------- arr[root] 38 < arr[child] 99, root 3 child 7
-------------------- arr[root] 38 > arr[child] 38, root 7 child 7 now
root                : 7
child               : 15
end                 : 7
-------------------- child 15 > end 7, exit loop
root                : 2
child               : 5
end                 : 7
-------------------- arr[root] 30 < arr[child] 97, root 2 child 5
-------------------- arr[root] 30 > arr[child] 30, root 5 child 5 now
root                : 5
child               : 11
end                 : 7
-------------------- child 11 > end 7, exit loop
root                : 1
child               : 3
end                 : 7
-------------------- arr[root] 15 < arr[child] 99, root 1 child 3
-------------------- arr[root] 15 > arr[child] 15, root 3 child 3 now
root                : 3
child               : 7
end                 : 7
-------------------- arr[root] 15 < arr[child] 38, root 3 child 7
-------------------- arr[root] 15 > arr[child] 15, root 7 child 7 now
root                : 7
child               : 15
end                 : 7
-------------------- child 15 > end 7, exit loop
root                : 0
child               : 1
end                 : 7
-------------------- arr[root] 23 < arr[child] 99, root 0 child 1
-------------------- arr[root] 23 > arr[child] 23, root 1 child 1 now
root                : 1
child               : 3
end                 : 7
-------------------- child+1 4 <= end 7 and arr[child] 38 < arr[child+1] 65
child now           : 4
-------------------- arr[root] 23 < arr[child] 65, root 1 child 4
-------------------- arr[root] 23 > arr[child] 23, root 4 child 4 now
root                : 4
child               : 9
end                 : 7
-------------------- child 9 > end 7, exit loop
大根堆:
[99, 65, 97, 38, 23, 30, 40, 15]
---------------------------------------------------------------------------------------------------- sort heap 
++++++++++++++++++++ max heapify 
height              : 2
root                : 2
child               : 5
end                 : 6
-------------------- child+1 6 <= end 6 and arr[child] 30 < arr[child+1] 40
child now           : 6
-------------------- arr[root] 97 > arr[child] 40, root 2 child 6, exit loop
root                : 1
child               : 3
end                 : 6
-------------------- arr[root] 65 > arr[child] 38, root 1 child 3, exit loop
root                : 0
child               : 1
end                 : 6
-------------------- child+1 2 <= end 6 and arr[child] 65 < arr[child+1] 97
child now           : 2
-------------------- arr[root] 15 < arr[child] 97, root 0 child 2
-------------------- arr[root] 15 > arr[child] 15, root 2 child 2 now
root                : 2
child               : 5
end                 : 6
-------------------- child+1 6 <= end 6 and arr[child] 30 < arr[child+1] 40
child now           : 6
-------------------- arr[root] 15 < arr[child] 40, root 2 child 6
-------------------- arr[root] 15 > arr[child] 15, root 6 child 6 now
root                : 6
child               : 13
end                 : 6
-------------------- child 13 > end 6, exit loop
++++++++++++++++++++ max heapify 
height              : 2
root                : 2
child               : 5
end                 : 5
-------------------- arr[root] 40 > arr[child] 30, root 2 child 5, exit loop
root                : 1
child               : 3
end                 : 5
-------------------- arr[root] 65 > arr[child] 38, root 1 child 3, exit loop
root                : 0
child               : 1
end                 : 5
-------------------- arr[root] 15 < arr[child] 65, root 0 child 1
-------------------- arr[root] 15 > arr[child] 15, root 1 child 1 now
root                : 1
child               : 3
end                 : 5
-------------------- arr[root] 15 < arr[child] 38, root 1 child 3
-------------------- arr[root] 15 > arr[child] 15, root 3 child 3 now
root                : 3
child               : 7
end                 : 5
-------------------- child 7 > end 5, exit loop
++++++++++++++++++++ max heapify 
height              : 1
root                : 1
child               : 3
end                 : 4
-------------------- child+1 4 <= end 4 and arr[child] 15 < arr[child+1] 23
child now           : 4
-------------------- arr[root] 38 > arr[child] 23, root 1 child 4, exit loop
root                : 0
child               : 1
end                 : 4
-------------------- child+1 2 <= end 4 and arr[child] 38 < arr[child+1] 40
child now           : 2
-------------------- arr[root] 30 < arr[child] 40, root 0 child 2
-------------------- arr[root] 30 > arr[child] 30, root 2 child 2 now
root                : 2
child               : 5
end                 : 4
-------------------- child 5 > end 4, exit loop
++++++++++++++++++++ max heapify 
height              : 1
root                : 1
child               : 3
end                 : 3
-------------------- arr[root] 38 > arr[child] 15, root 1 child 3, exit loop
root                : 0
child               : 1
end                 : 3
-------------------- arr[root] 23 < arr[child] 38, root 0 child 1
-------------------- arr[root] 23 > arr[child] 23, root 1 child 1 now
root                : 1
child               : 3
end                 : 3
-------------------- arr[root] 23 > arr[child] 15, root 1 child 3, exit loop
++++++++++++++++++++ max heapify 
height              : 0
root                : 0
child               : 1
end                 : 2
-------------------- child+1 2 <= end 2 and arr[child] 23 < arr[child+1] 30
child now           : 2
-------------------- arr[root] 15 < arr[child] 30, root 0 child 2
-------------------- arr[root] 15 > arr[child] 15, root 2 child 2 now
root                : 2
child               : 5
end                 : 2
-------------------- child 5 > end 2, exit loop
++++++++++++++++++++ max heapify 
height              : 0
root                : 0
child               : 1
end                 : 1
-------------------- arr[root] 15 < arr[child] 23, root 0 child 1
-------------------- arr[root] 15 > arr[child] 15, root 1 child 1 now
root                : 1
child               : 3
end                 : 1
-------------------- child 3 > end 1, exit loop
++++++++++++++++++++ max heapify 
height              : 0
root                : 0
child               : 1
end                 : 0
-------------------- child 1 > end 0, exit loop
堆排序:
[15, 23, 30, 38, 40, 65, 97, 99]

2. heapq

参考这里 3

import heapqa = [49, 38, 65, 97, 76, 13, 27, 40, 99]
print(f"{'排序前':20}: {a}")print('-' * 50 + ' min heapify ')
heapq.heapify(a)
print(f"{'小根堆':20}: {a}")print('-' * 50 + ' max heapify ')
newa = [(-i, a[i]) for i in range(len(a))]
heapq.heapify(newa)
print(f"{'新小根堆':20}: {newa}")
maxheap = list()
while newa:_, s = heapq.heappop(newa)print(f"_, s: {_}, {s}")maxheap.append(s)
print(f"{'大根堆':20}: {maxheap}")

输出信息如下所示:

排序前                 : [49, 38, 65, 97, 76, 13, 27, 40, 99]
-------------------------------------------------- min heapify 
小根堆                 : [13, 38, 27, 40, 76, 65, 49, 97, 99]
-------------------------------------------------- max heapify 
新小根堆                : [(-8, 99), (-7, 97), (-6, 49), (-3, 40), (-4, 76), (-5, 65), (-2, 27), (-1, 38), (0, 13)]
_, s: -8, 99
_, s: -7, 97
_, s: -6, 49
_, s: -5, 65
_, s: -4, 76
_, s: -3, 40
_, s: -2, 27
_, s: -1, 38
_, s: 0, 13
大根堆                 : [99, 97, 49, 65, 76, 40, 27, 38, 13]

小根堆

1.

以无序序列 [49, 38, 65, 97, 76, 13, 27, 40,99] 为例,

def minheap(arr, start, end):height = int((end+1)/ 2 - 1)for root in range(height, -1, -1):while True:child = root * 2 + 1if child > end:breakif child-1 >= start and arr[child] > arr[child-1]:child = child-1if arr[root] > arr[child]:arr[root], arr[child] = arr[child], arr[root]root = childelse:breakreturn arrdef sortheap(arr, start, end):for i in range(end, 0, -1):arr[0], arr[i] = arr[i], arr[0]minheap(arr, 0, i-1)return arrif __name__ == '__main__':a = [49, 38, 65, 97, 76, 13, 27, 40, 99]print(f"排序前:\n{a}")print('-' * 50 + ' min heapify ')a = minheap(a, 0, len(a)-1)print(f"小根堆:\n{a}")print('-' * 50 + ' sort heap ')arr = sortheap(a, 0, len(a)-1)print(f"堆排序:\n{a}")

输出信息如下所示:

排序前:
[49, 38, 65, 97, 76, 13, 27, 40, 99]
-------------------------------------------------- min heapify 
小根堆:
[13, 27, 38, 40, 76, 65, 97, 49, 99]
-------------------------------------------------- sort heap 
堆排序:
[99, 97, 76, 65, 49, 40, 38, 27, 13]

2. heapq

参考这里 3

import heapqa = [49, 38, 65, 97, 76, 13, 27, 40, 99]
print(f"{'排序前':20}: {a}")print('-' * 50 + ' min heapify ')
heapq.heapify(a)
print(f"{'小根堆':20}: {a}")print('-' * 50 + ' min heapify ')
newa = [(i, a[i]) for i in range(len(a))]
heapq.heapify(newa)
print(f"{'新小根堆':20}: {newa}")
minheap = list()
while newa:_, s = heapq.heappop(newa)print(f"_, s: {_}, {s}")minheap.append(s)
print(f"{'小根堆':20}: {minheap}")

输出信息如下所示:

排序前                 : [49, 38, 65, 97, 76, 13, 27, 40, 99]
-------------------------------------------------- min heapify 
小根堆                 : [13, 38, 27, 40, 76, 65, 49, 97, 99]
-------------------------------------------------- min heapify 
新小根堆                : [(0, 13), (1, 38), (2, 27), (3, 40), (4, 76), (5, 65), (6, 49), (7, 97), (8, 99)]
_, s: 0, 13
_, s: 1, 38
_, s: 2, 27
_, s: 3, 40
_, s: 4, 76
_, s: 5, 65
_, s: 6, 49
_, s: 7, 97
_, s: 8, 99
小根堆                 : [13, 38, 27, 40, 76, 65, 49, 97, 99]

参考链接

#todo:
关于 Python 标准库 heapq 的 大根堆/最大堆的 API~


  1. 浅谈大根堆,小根堆,以及堆排序(python)实现 ↩︎

  2. Python 堆排序 ↩︎

  3. python用heapq模块构建大根堆 ↩︎ ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UVM Heartbeat机制

1. 前言 在硬件电路中&#xff0c;为了使系统在异常情况下能自动复位&#xff0c;一般都需要引入看门狗(Watchdog)。看门狗其实就是一个定时器电路。当看门狗启动后&#xff0c;计数器开始自动计数&#xff0c;经过一定时间&#xff0c;如果没有被清零&#xff0c;计数器溢出就…

投影标杆,旗舰实力,极米投影仪Z7X为用户创造影院级体验

2023年&#xff0c;在彩电消费市场复苏疲软的背景下&#xff0c;智能投影这个显示新品类却持续走红。今年第一季度&#xff0c;极米科技推出Z系列全新一代产品极米Z7X&#xff0c;和极米Z6相比&#xff0c;在保持轻薄体积不变的情况下将亮度提升了83%&#xff0c;达到600CCB 流…

MAC电脑外放没有声音解决方案

烦人呐&#xff0c;我的mac外接显示屏幕&#xff0c;显示器没有音频输出&#xff0c;需要mac笔记本的音频输出&#xff0c;但是经常打开后&#xff0c;mac没有声音输出&#xff0c;需要重启电脑才能生效。亲测一下方法有效&#xff0c;请参考&#xff1a; 文章目录 一、短期方案…

THINKPHP 微联云投票系统源码独立版 + 支持刷礼物

THINKPHP 微联云投票系统源码独立版 支持刷礼物 nginxphp7.2以上 mysql5.6以上 简单测试后台基本没什么问题&#xff0c;暂时发现H5前端有bug,自行修复。

Echarts图表坐标轴文字太长,省略显示,鼠标放上显示全部(vue)

注意&#xff1a;记得加上这个&#xff0c;触发事件&#xff0c; triggerEvent: true,重点&#xff1a;下面就是处理函数&#xff0c;在实例化图表的时候使用&#xff0c;传入参数是echarts的实例 // 渲染echartsfirstBarChart() {const that thislet columnar echarts.init…

[ MySQL ] — 常见函数的使用

目录 日期函数 current_date — 获取当前日期 current_time — 获取当前时间 current_timestamp — 获取当前时间戳 date — 获取参数的日期部分 ​编辑 date_add — 在日期或时间的基础上进行增加 date_sub — 在日期或时间的基础上进行减少 datediff — 计算两个日期相差…

C# 观察者模式

一、概述 观察者模式是一种常用的设计模式&#xff0c;它属于行为型模式。在C#中&#xff0c;观察者模式通过定义一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。这种模式可以实现松耦合&#xff0c;…

解决,worldGeo.db中有geom数据的x1表无法在QGIS中成图像

原因:缺少geom数据对应的坐标geometry_columns文件,如下图所示&#xff1a; STEP: 1,在navicat_for_SQLite中将目标表x1中字段geom中blob改成,POINT,或者MULTIPOLYGON等对应的格式 2,在可以成像的其它数据库中找到POINT或MULTIPOLYGON对应表x2的坐标geometry_columns文件&…

3d max插件CG MAGIC中的蜂窝材质功能可提升效率吗?

工作中能提升效率也都是大家所想的&#xff0c;对于设计师的一个设计过程中&#xff0c;可能想怎么样可以更快呀&#xff0c;是哪个步骤慢了呢&#xff1f; 这样的结果只能说会很多&#xff0c;但是建模这个步骤&#xff0c;肯定是有多无少的。 为了让模型更加逼真&#xff0c…

macbook 加载模型报错:failed to load model

环境&#xff1a;macbook m1 conda python3.9 加载模型链接为&#xff1a;ggml-model-q4_0.bin 加载方式&#xff1a; from langchain.embeddings import LlamaCppEmbeddings embeddings LlamaCppEmbeddings(model_pathllama_path) 在linux上加载是正常的&#xff0c;但是…

[Linux]进程概念

[Linux]进程概念 文章目录 [Linux]进程概念进程的定义进程和程序的关系Linux下查看进程Linux下通过系统调用获取进程标示符Linux下通过系统调用创建进程-fork函数使用 进程的定义 进程是程序的一个执行实例&#xff0c;是担当分配系统资源&#xff08;CPU时间&#xff0c;内存…

系统架构师---软件重用、基于架构的软件设计、软件模型

目录 软件重用 构件技术 基于架构的软件设计 ABSD方法与生命周期 抽象功能需求 用例 抽象的质量和业务需求 架构选项 质量场景 约束 基于架构的软件开发模型 架构需求 需求获取 标识构件 需求评审 架构设计 架构文档 架构复审 架构实现 架构演化 前言&…