STL——heap结构及算法
heap(隐式表述,implicit representation)
1. heap概述 : vector + heap算法
heap并不归属于STL容器组件,它是个幕后英雄,扮演priority queue的助手。顾名思义,priority queue允许用户以任何次序将任何元素推入容器内,但取出时一定是从优先权最高(也就是数值最高)的元素开始取。binary max heap 正是具有这样的特性,适合作为priority queue 的底层机制。
让我们做一点分析。如果使用list 作为priority queue的底层机制,元素出入操作可享常数时间。但是要找到list中的极值,却需要对整个list进行线性扫描。我们也可以改变做法,让元素插入前先经过排序,使得list的元素值总是由小到大(或由大到小),但这么一来,收之东隅却失之桑榆:虽然取得极值以及元素删除操作达到最高效率,可元素的插入却只有线性表现。
比较好的做法是以binary search tree 作为priority queue的底层机制。这么一来,元素的插入和极值的取得就有O(logN) 的表现。但杀鸡用牛刀,未免小题大做,一来binary search tree 的输入需要足够的随机性,二来binary search tree并不容易实现。priority queue 的复杂度,最好介于queue 和 binary search tree 之间,才算适得其所。bianry heap便是这种条件下的适当候选人。
所谓binary heap 就是一种complete binary tree(完全二叉树),也就是说,整棵binary tree 除了最底层的叶节点之外,是填满的,而最底层的叶节点(s)由左至右又不得有空隙。
complete binary tree 整棵树内没有任何节点漏洞,这带来一个极大的好处:我们可以利用array来存储所有节点。假设动用一个小技巧,将array的#0元素保留(或设为无限大或无限小),那么当complete binary tree中的某个节点位于array的i处时,其左子节点必位于array的2i处,其右子节点比位于array的2i+1处,其父节点必位于“i/2”处。通过这么简单的位置规则,array可以轻易实现出complete binary tree。这种以array表述tree的方式,我们称为隐式表述法。
这么一来,我们需要的工具就很简单了:一个array 和 一组 heap算法(用来进行元素操作,并将某一整组数据排列成一个heap)。array的缺点是无法动态改变大小,而heap却需要这项功能,因此,以vector代替array是更好的选择。
根据元素的排列方式,heap可分为max-heap 和 min-heap两种,前者每个节点的键值(key)都大于或等于其子节点键值,后者的每个节点键值都小于或等于其子节点键值。STL提供的是max-heap。
2. heap算法
2.1 push_heap算法:上溯
percolate_up(上溯)程序:将新节点拿来与其父节点比较,如果其键值(key)比父节点大,就父子对换位置。如此一直上溯,直到不需对换或直到根节点为止。
push_heap算法的实现细节参见相关源码。
注意:
(1)为了满足complete binary tree的条件,新加入的元素一定要放在最下一层作为叶节点,便填补在由左至右的第一个空格,也就是把新元素插入在底层vector的end()处。
(2)当push_heap函数被调用时,新元素应已置于底部容器的最尾端。
另: array无法动态改变大小,因此如果heap底层采用array,便不可以对满载的array进行push_heap操作,因为那得先在array尾端增加一个元素。如果对一个满载的array执行push_heap,该函数会将最后一个元素视为新增元素,并将其余元素视为一个完整的heap结构(实际上它们的确是),因此执行后的结果等于原先的heap。
2.2 pop_heap算法:下溯+上溯
下图是 pop_heap算法的实际操演情况。既然身为max-heap,最大值必然在根节点。pop操作取走根节点(其实是设至底部容器vector的尾端节点)后,为了满足complete binary tree的条件,必须割舍最下层最右边的叶节点,并将其值重新安插至max-heap(因此有必要重新调整heap结构)。
为了满足max-heap次序特性(每个节点的键值都大于或等于其子节点键值),我们执行所谓的percolate down(下溯)程序:将空间节点和其较大子节点“对调”,并持续下放,直至叶节点为止。然后将前述被割舍之元素值设给这个“已到达叶层的空间节点”,再对它执行一次percolate up(上溯)程序。
pop_heap算法的实现细节参见相关源码。
注意:
pop_heap之后,最大元素只是被置于底部容器的最尾端,尚未被取走。
2.3 sort_heap算法
既然每次pop_heap可获得heap中键值最大的元素,如果持续对整个heap做pop_heap操作,每次将操作范围从后向前缩减一个元素(因为pop_heap会把键值最大的元素放在底部容器的最尾端),当整个程序执行完毕时,我们便有了一个递增序列。
2.4 make_heap算法
这个算法用来将一段现有的数据转化为一个heap。
make_heap算法实现参见相关源码
3. heap没有迭代器 heap的所有元素都必须遵循特别的(complete binary tree)排列规则,所以heap不提供遍历功能,也不提供迭代器。
STL——heap结构及算法的更多相关文章
- STL -- heap结构及算法
STL -- heap结构及算法 heap(隐式表述,implicit representation) 1. heap概述 : vector + heap算法 heap并不归属于STL容器组件,它是个 ...
- STL六大组件之——算法小小小小的解析
参考自侯捷的<stl源码剖析> stl算法主要分为非可变序列算法(指不直接修改其所操作的容器内容的算法),可变序列算法(指可以修改它们所操作的容器内容的算法),排序算法(包括对序列进行排序 ...
- STL源码剖析(算法)
STL中算法是基于迭代器来实现的. 有了容器中迭代器的实现(对operator*.operator++等的重载),STL中大部分算法实现就显得很简单了. 先看一例关于find算法的实现: templa ...
- java结构与算法之选择排序
一 .java结构与算法之选择排序(冒择路兮快归堆) 什么事选择排序:从一组无序数据中选择出中小的的值,将该值与无序区的最左边的的值进行交换. 简单的解释:假设有这样一组数据 12,4,23,5,找到 ...
- STL中的所有算法(70个)
STL中的所有算法(70个)----9种类型(略有修改by crazyhacking) 参考自: http://www.cppblog.com/mzty/archive/2007/03/14/1981 ...
- Data01-数据结构和算法绪论
Data01-数据结构和算法绪论 一.数据结构和算法绪论 1.1 什么是数据结构? 数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及它们之间的关系和操作等相关问题的学科. 程序设计=数据结 ...
- C++ STL 常用算术和生成算法
C++ STL 常用算术和生成算法 accumulate() accumulate: 对指定范围内的元素求和,然后结果再加上一个由val指定的初始值. #include<numeric> ...
- STL中的排序算法
本文转自:STL中的排序算法 1. 所有STL sort算法函数的名字列表: 函数名 功能描述 sort 对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 ...
- 【算法学习】老算法,新姿势,STL——Heap
“堆”是一个大家很熟悉的数据结构,它可以在\(O(log\;n)\)的时间内维护集合的极值. 这都是老套路了,具体的内部实现我也就不谈了. 我一般来说,都是用queue库中的priority_queu ...
随机推荐
- Tomcat server.xml 配置虚拟目录
对于Tomcat,打开..\Tomcat 6.0\conf\server.xml文件,找到下面的一行代码(Host)然后在这一行之间下面添加配置代码:<Context path="&q ...
- 【Html】Clipboard.js 实现点击复制,剪切板操作
可以使用cdn 或者直接下载 设置好引用路径(百度云下载) <script type="text/javascript" src="./dist/clipboard ...
- JDBC删除数据库实例
在本教程将演示如何在JDBC应用程序中删除一个指定的数据库. 在执行以下示例之前,请确保您已经准备好以下操作: 具有数据库管理员权限,以在给定模式中创建数据库. 要执行以下示例,需要用实际用户名和密码 ...
- Spring JDBC多批次操作
以下示例将演示如何使用spring jdbc在单个调用中进行多批次更新. 我们将在批量大小为1的多批次操作中更新student表中的记录. student表的结果如下 - CREATE TABLE s ...
- 多媒体开发之rtmp---rtmp client 编译
静态库连接编译问题: assert 原来在c编译器下没定义 ceill 没连接没加 -lm http://blog.chinaunix.net/uid-20681545-id-3786786.html ...
- Scala学习笔记——安装
安装scala,不要使用sudo apt-get install scala来安装 1.从下面网址来下载Scala文件 http://www.scala-lang.org/download/2.11. ...
- css 手机适配
手淘H5移动端适配方案flexible源码分析 移动端适配一直是一个值得探讨的问题,在业余时间我找了一些页面,查看了一些厂商对于移动端H5页面的适配方案,看到了几个典型的例子,今天就来记录一下我看 ...
- hive 1.2 配置
参考链接 http://www.cnblogs.com/yjmyzz/p/how-to-install-hive-1-2-0-on-mac.html
- 如何通过SSH及其Client 批量分发文件和执行管理命令
一.前提:已经配置好root和hadoop用户的无密码的SSH访问 二.直接上代码 ##复制单个文件[hadoop@nn1 hadoop]$ for ip in 102 103 104 111 112 ...
- glibc中fork系统调用传参
因为想跟踪下在新建进程时,如何处理新建进程的vruntime,所以跟踪了下fork. 以glic-2.17中ARM为例(unicore架构的没找到),实际上通过寄存器向系统调用传递的参数为: r7: ...