堆(Heap)可以看成近似完全二叉树的数组,树中每个节点对应数组中一个元素。除了最底层之外,该树是完全充满的,最底层是从左到右填充的。

堆包括最大堆和最小堆:最大堆的每一个节点(除了根结点)的值不大于其父节点;最小堆的每一个节点(除了根结点)的值不小于其父节点。

本文以最大堆为例,先直观感受一下堆的样子:

图片来源

最大堆

树中节点内的值表示存储的值,节点旁边的值表示该节点在数组中的下标。

观察上图不难发现,对于一个给定节点的下标i,其父节点、左孩子、右孩子的下标为:

parent(i): (i + 1) // 2 - 1

left(i): i * 2 + 1

right(i): i * 2 + 2

其中“//”表示除法后只取整数部分。

对于一个给定的数组,如何转化为堆呢?

对于一个任意节点,如果该节点大于左孩子和右孩子,则该节点无需移动。否则,和左右孩子中较大的那个交换位置,于是该节点满足大于左右孩子了,但是刚被交换了的孩子节点需要继续比较它的左右孩子......整个过程递归进行下去,我们可以轻松计算出:对于根节点,在进行转化成堆的过程中,最多需要交换h次(h为树的高度),对于树种的每个节点,如果都进行此操作,则整个过程的时间复杂度为:O(nlogn)。(n为节点数,logn≈h)

代码如下:

def heapify(self):

for i in range((len(self.heap) + 1) // 2 - 1, -1, -1):

self.max_heapify_top(i)

def max_heapify_top(self, i):

"""

从上到下

O(logn)

"""

left = i * 2 + 1

right = i * 2 + 2

if left < len(self.heap) and self.heap[left] > self.heap[i]:

largest = left

else:

largest = i

if right < len(self.heap) and self.heap[right] > self.heap[largest]:

largest = right

if largest != i:

self.heap[largest], self.heap[i] = self.heap[i], self.heap[largest]

self.max_heapify_top(largest)

以上代码中heapify函数从(len(self.heap) + 1) // 2 - 1到0进行遍历,是因为树中的叶子节点没有孩子,因此可以看成满足堆的性质,所以无需进行heapify,所以从非叶子节点开始遍历,节约时间。

如何从堆中弹出和插入元素呢?

先说弹出。由于是最大堆,因此每次弹出需要弹出最大的元素,那就是根节点,如何弹出后还保持堆的性质呢。具体做法是:先将树中根节点和最后一个节点交换位置,对应数组中就是第一个元素和最后一个元素交换位置,然后弹出最后一个元素,在对交换位置后的根节点进行heapify,这样弹出了最大元素,同时也保持了堆的性质。

代码如下:

def pop(self):

"""

O(logn)

"""

self.heap[0], self.heap[len(self.heap) - 1] = self.heap[len(self.heap) - 1], self.heap[0]

value = self.heap.pop()

self.max_heapify_top(0)

return value

插入元素。

先将元素放在树的末尾,也是数组的末尾,再按照自下而上的顺序依次比较与父节点的大小关系,自下而上进行heapify。

代码如下:

def push(self, value):

"""

O(logn)

"""

self.heap.append(value)

self.max_heapify_button(len(self.heap) - 1)

def max_heapify_button(self, i):

"""

从下到上

O(logn)

"""

parent = (i + 1) // 2 - 1

if parent >= 0 and self.heap[parent] < self.heap[i]:

smallest = parent

else:

smallest = i

if smallest != i:

self.heap[smallest], self.heap[i] = self.heap[i], self.heap[smallest]

self.max_heapify_button(smallest)

整个堆的实现代码为:

class Heap:

def __init__(self, heap=[]):

self.heap = heap

def heapify(self):

for i in range((len(self.heap) + 1) // 2 - 1, -1, -1):

self.max_heapify_top(i)

def max_heapify_top(self, i):

"""

从上到下

O(logn)

"""

left = i * 2 + 1

right = i * 2 + 2

if left < len(self.heap) and self.heap[left] > self.heap[i]:

largest = left

else:

largest = i

if right < len(self.heap) and self.heap[right] > self.heap[largest]:

largest = right

if largest != i:

self.heap[largest], self.heap[i] = self.heap[i], self.heap[largest]

self.max_heapify_top(largest)

def max_heapify_button(self, i):

"""

从下到上

O(logn)

"""

parent = (i + 1) // 2 - 1

if parent >= 0 and self.heap[parent] < self.heap[i]:

smallest = parent

else:

smallest = i

if smallest != i:

self.heap[smallest], self.heap[i] = self.heap[i], self.heap[smallest]

self.max_heapify_button(smallest)

def pop(self):

"""

O(logn)

"""

self.heap[0], self.heap[len(self.heap) - 1] = self.heap[len(self.heap) - 1], self.heap[0]

value = self.heap.pop()

self.max_heapify_top(0)

return value

def push(self, value):

"""

O(logn)

"""

self.heap.append(value)

self.max_heapify_button(len(self.heap) - 1)

再说堆排序呢?对于一个任意的数组,进行构建堆之后,再按照顺序依次弹出堆中的元素,便得到了有序的数组。更神奇的是,在数组末尾添加一个指针,便可实现数组的原地排序(不需要额外空间)。堆排序的时间复杂度为:O(nlogn),空间复杂度为:O(1)

heap python_数据结构-堆(Heap) Python实现相关推荐

  1. 数据结构-堆(Heap)

    数据结构-堆(Heap) 我认识的堆: 1.建立在完全二叉树的基础上 2.排序算法的一种,也是稳定效率最高的一种 3.可用于实现STL中的优先队列(priority_queue)  优先队列:一种特殊 ...

  2. 数据结构--堆(Heap)

    堆(Heap) 本文主要介绍以下内容: Heap的实现 HeapSort(堆排序) 完善各种堆的函数接口 TopK经典问题 堆就是一棵完全二叉树.因为它的某些性质,我们可以用数组存储. 堆的性质 1 ...

  3. 数据结构--堆Heap

    数据结构:堆(Heap) 堆就是用数组实现的二叉树,所以它没有使用父指针或者子指针.堆根据"堆属性"来排序,"堆属性"决定了树中节点的位置. 堆的常用方法: 构 ...

  4. 数据结构--堆 Heap

    文章目录 1. 概念 2. 操作和存储 2.1 插入一个元素 2.2 删除堆顶元素 3. 堆排序(不稳定排序) 3.1 建堆 3.2 排序 3.3 思考:为什么快速排序要比堆排序性能好?两者都是O(n ...

  5. 数据结构 堆 heap

    一种二叉树的结构  →  完全二叉树 每个节点 ≥   or   ≤ 孩子节点 最大堆                     最小堆 特点 最大堆:最大值  就是  堆顶元素 最小堆: 最小值  就 ...

  6. 数据结构堆Heap实现思路

    文章目录 一.了解堆 介绍 数组存放 实现思路 二.实现堆(大顶堆为例,即书中所说) 向下调整函数 构建和删除操作 向上调整函数和添加操作 实现堆排序 三.PriorityQueue 四.练习 参见& ...

  7. Python入门篇-数据结构堆排序Heap Sort

    Python入门篇-数据结构堆排序Heap Sort 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.堆Heap 堆是一个完全二叉树每个非叶子结点都要大于或者等于其左右孩子结点的 ...

  8. codeforces 贪心+优先队列_算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)...

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值:

  9. 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...

最新文章

  1. java学习--第50天讲到jquery
  2. Nature Methods:微生物来源分析包SourceTracker——结果解读和使用教程
  3. php auth和rbac区别,php中比rbac更好的权限认证的方式auth类认证
  4. 安卓手机安装并使用自动化应用Tasker
  5. MQTT 控制报文 - PINGREQ心跳报文,PINGRESP - 第4章
  6. jzoj3771. 【NOI2015模拟8.15】小 Z 的烦恼
  7. [书目20080630]人一生要养成的50个习惯
  8. 模型描述的关系模式_图解各种管理模型大全--管理模型大全
  9. 【Python123】汽车迷
  10. fw325r虚拟服务器连接失败,fw325r重置后不能联网怎么办?
  11. linux、docker容器缺少tailf命令,解决方案。
  12. Revit 和 ArchiCAD 在软件设计理念方面的对比
  13. 【CPRI】(1)CPRI基本概念和相关术语
  14. word2010中设置页码起始页从任意一页开始
  15. 揭露数据不一致的利器 —— 实时核对系统
  16. unity3d四元数和旋转矩阵
  17. 怎么恢复计算机隐藏的桌面图标,怎么把桌面图标隐藏 win10桌面怎么找回我的文档图标?...
  18. 微积分基本定理:微分符号与积分符号是逆运算
  19. windows11 版本 business editions consumer editions 区别介绍
  20. win10有自带测试软件吗,Win10体检自带诊断工具在哪里打开 Win10关闭开机检测硬盘步骤...

热门文章

  1. Android Studio 详细安装教程
  2. java 汇总_java基础汇总
  3. vc6.0mfc中单选按钮如何分组_按钮系列02-搞定按钮和选框的14个秘诀
  4. python变量的使用_python – 如何在变量中使用冒号(:)
  5. 华为仿苹果字体_华为mate40系列再次霸榜DXO,网友:无敌是多么寂寞
  6. mysql数据库(4): 创建并选择数据库
  7. 改变php二维数组的值_php如何修改二维数组中的值?
  8. jmu-python-函数-找钱_python函数题 - osc_wv1mxwu2的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. TensorFlow5-监督式机器学习基础知识
  10. 多个excel文件内容合并到一个excel文件的多个sheet的小程序