Python3实现最小堆建堆算法
今天看Python CookBook中关于“求list中最大(最小)的N个元素”的内容,介绍了直接使用python的heapq模块的nlargest和nsmallest函数的解决方式,记得学习数据结构的时候有个堆排序算法,所以顺便研究了一下“堆”结构(这里特指二叉堆)。
概念
所谓二叉堆(binary heap)实际上就是一颗特殊的完全二叉树,其特殊性在于:
- 二叉树中所有的父节点的值都不大于/不小于其子节点;
- 根节点的值必定是所有节点中最小/最大的。
父节点值不大于子节点且根节点值最小称为最小堆,反之称为最大堆。最大堆和最小堆没有本质上的区别。如下图是一个典型的最小堆:
算法
现在实现一个对给定list完成初始建堆的算法。(以最小堆为例)
假设 list = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
先记录一个自己当时看堆结构时琢磨出来的算法,后来查了查资料发现不是最优的。
渣渣算法
直接根据list中元素的index构建二叉树,这里我们不使用链表,完全以列表实现并以0为基(根节点index为0):
根据完全二叉树的特点(节点如果存在右子节点,则必存在左子节点且如果右子节点存在子节点,则左子节点必存在左右子节点),元素个数为N的完全二叉树的最后一个拥有子节点的节点的index为N//2 -1 。
为了实现二叉树中所有父节点的值不大于其子节点(特性1),只需要从根节点(index = 0)遍历到最后一个拥有子节点的节点(index = N//2 -1),将父节点与其子节点值作比较,必要时进行交换即可。完成一次上述过程后就能完成最底层节点的归位了。元素个数为N的二叉树层数为ceil(log2n),因此一共执行floor(log2n)次上述过程就能实现最小堆的建堆了。算法如下:
#!/usr/bin/env python import os
import sys
import math def heap(list):
n = len(list)
for i in range(0,int(math.log(n,2))): #每循环依次就完成了一层的建堆
for j in range(0,n//2):
k = 2*j+2 if 2*j+2 < n and list[2*j+2] < list[2*j+1] else 2*j+1 #让k成为较小的子节点的index
if list[j] > list[k]:
(list[j],list[k]) = (list[k],list[j]) #交换值 def main(argv):
list = [int(arg) for arg in argv]
heap(list)
print(list)
if __name__ == "__main__":
if len(sys.argv) > 1:
main(sys.argv[1:])
这是自顶向下的遍历方式,还可以自底向上遍历,则首先归位的是根节点。
很明显,这个算法的复杂度为O(nlogn), 但实际上,最优的建堆算法的复杂度是O(n),而且这个算法还使用了数学函数。。。
最优算法
下面贴一个使用递归的最优算法:
思路还是一样,直接根据list构建二叉树,然后从最后一个拥有子节点的节点向上遍历,使用下沉算法将遍历到的每一个子树变成二叉堆。最终整个二叉树就成为一个二叉堆。
#!/usr/bin/env python import os
import sys def sink(list,root):
if 2*root+1 < len(list):
k = 2*root+2 if 2*root+2 < len(list) and list[2*root+2] < list[2*root+1] else 2*root+1 #让k成为较小的子节点的index
if list[root] > list[k]:
(list[root],list[k]) = (list[k],list[root]) #交换值
sink(list,k) #对子节点为根节点的子树建堆 def main(argv):
list = [int(arg) for arg in argv]
for i in range(len(list)//2-1,-1,-1):
sink(list,i)
print(list)
if __name__ == "__main__":
if len(sys.argv) > 1:
main(sys.argv[1:])
两种算法运行截图:
堆排序
最后说一下堆排序,建堆完成后,排序就简单了:
将根节点(即list[0])弹出:list.pop(0),然后将最后一个节点放到根节点位置,对剩下的list再次进行建堆(针对算法1,算法2则是直接调用sink方法即可)。反复此过程就能输出排序结果。
想要直接在list内排序的话,则不弹出根节点,而是直接将根节点和最后一个节点交换位置,反复调用sink方法(但是不能再用len(list),而是给定一个从len(list)依次递减的参数,避免让已排序好的节点继续参与建堆)
Python3实现最小堆建堆算法的更多相关文章
- 堆+建堆、插入、删除、排序+java实现
package testpackage; import java.util.Arrays; public class Heap { //建立大顶堆 public static void buildMa ...
- 建堆复杂度O(n)证明
堆排序中首先需要做的就是建堆,广为人知的是建堆复杂度才O(n),它的证明过程涉及到高等数学中的级数或者概率论,不过证明整体来讲是比较易懂的. 堆排过程 代码如下 void print(vector&l ...
- 配对堆优化Dijkstra算法小记
关于配对堆的一些小姿势: 1.配对堆是一颗多叉树. 2.包含优先队列的所有功能,可用于优化Dijkstra算法. 3.属于可并堆,因此对于集合合并维护最值的问题很实用. 4.速度快于一般的堆结构(左偏 ...
- 建堆是 O(n) 的时间复杂度证明。
建堆的复杂度先考虑满二叉树,和计算完全二叉树的建堆复杂度一样. 对满二叉树而言,第 \(i\) 层(根为第 \(0\) 层)有 \(2^i\) 个节点. 由于建堆过程自底向上,以交换作为主要操作,因此 ...
- PAT-1030 Travel Plan (30 分) 最短路最小边权 堆优化dijkstra+DFS
PAT 1030 最短路最小边权 堆优化dijkstra+DFS 1030 Travel Plan (30 分) A traveler's map gives the distances betwee ...
- 【算法】01-数据结构概述(注意区分jvm堆与堆/jvm栈与栈)
[算法]01-数据结构概述(注意区分jvm堆与堆/jvm栈与栈) 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有 ...
- 【ZZ】堆和堆的应用:堆排序和优先队列
堆和堆的应用:堆排序和优先队列 https://mp.weixin.qq.com/s/dM8IHEN95IvzQaUKH5zVXw 堆和堆的应用:堆排序和优先队列 2018-02-27 算法与数据结构 ...
- Python3标准库:heapq堆排序算法
1. heapq堆排序算法 堆(heap)是一个树形数据结构,其中子节点与父节点有一种有序关系.二叉堆(binary heap)可以使用一个有组织的列表或数组表示,其中元素N的子元素位于2*N+1和2 ...
- C++ 堆 和 堆 分析
[摘要] 堆和栈,即是数据结构,又是分配存储空间的不同方式.在数据结构上.堆是树型层次结构,结点按keyword次序排列,经常使用的堆为二叉堆:栈是一种先进后出的数据结构.在内存分配上的堆和栈,首要差 ...
随机推荐
- JOST数据 日期转换
开发中有时候需要从服务器端返回json格式的数据,在后台代码中如果有DateTime类型的数据使用系统自带的工具类序列化后将得到一个很长的数字表示日期数据,如下所示: 复制代码代码如下: //设置服务 ...
- window 10 用composer安装 基于 Laravel 5.3 的 Coaster CMS Curl错误77解决
安装教程来自 http://laravelacademy.org/post/6547.html 1.系统环境windows 10 nodejs3.9.2 composer1.2.4(国内镜像) Cmd ...
- cocoapods安装及常用命令
如果不是因为我重装了电脑,我大概也不会写这篇博客,网上关于cocoapods的安装可谓是不可胜数. 但是对于新版的系统来说,的确存在很多的坑点,这点不是我一个人遇到的问题 如果是新装的系统,默认是安装 ...
- 阅读Python官方文档心得
我会每天都阅读一些python的官方文档,并每天更新心得体会. -------------------------------------------------2016.12.08--------- ...
- 外网无法访问本地IIS站点
自己申请了个花生壳动态域名,本来是打算在IIs上建个站点测试一下的,路由器上的端口也配置好了,把80端口指向我本机.域名也通过 ping 测试确实指向了我这里的路由器.但是用这个域名老是访问不了我这个 ...
- redis 事务
概述 相信学过MySQL等其他数据库的同学对事务这个词都不陌生,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行.为什么会有这样的需求呢?看看下面的场景: 微博是一个弱关系型社交网络,用户之 ...
- nginx修改配置后不生效的问题
nginx增加了新的server name配置,发现nginx -s reload之后总是不生效. http和https均可以打开页面,但是页面是别的server页面,使用的证书也是别的server的 ...
- hbase hmaster故障分析及解决方案:Timedout 300000ms waiting for namespace table to be assigned
最近生产环境hbase集群出现停掉集群之后hmaster无法启动现象,master日志报异常:Timedout 300000ms waiting for namespace table to be a ...
- Android使用ViewPager做轮播
ViewPager.html div.oembedall-githubrepos { border: 1px solid #DDD; list-style-type: none; margin: 0 ...
- C#判断PC是否支持触摸屏
C#判断PC是否支持触摸屏 添加引用PresentationFrameworkSystem.Windows.SystemParameters.IsTabletPC 使用win32api [csharp ...