数据结构与算法(6) -- heap
binary heap就是一种complete binary tree(完全二叉树)。也就是说,整棵binary tree除了最底层的叶节点之外,都是满的。而最底层的叶节点由左至右又不得有空隙。

以上是一个对heap的简单介绍。本文将用heap指代此种完全二叉树。那么在实际编写代码的时候怎么组织这种数据呢,其实可以用array来存储这种结构的数据。将数组的第0个元素保留不用,从第一个元素开始存放数据。那么,对于树中的某个位于i的节点,其左子节点必然位于2i处,右子节点必然位于2i+1处,父节点必然位于“i/2”处。当然heap要能动态的改变大小,所以用vector存储数据会更好。
这里还有一个小的细节需要注意一下,heap可以分为max-heap以及min-heap,前者每个节点的键值都大于或等于其子节点键值,后者的每个节点键值都小于或等于其子节点键值。可以推出,max-heap的最大键值在根节点,min-heap的最小键值在根节点。
综上:heap就是一个包含了一组数据(通常可用array/vector来存储)以及一组管理这些数据的算法(插入元素,删除元素,取极值,将一组数据排列成一个heap)。通过这些方法可以保证heap的特性。
heap的算法
因为在c++ stl中并不直接提供heap这样一种数据结构,但它却是很多数据结构的基础:例如优先队列。所以这里我们主要关注的是heap涉及到的一些算法。
push_heap
在很多书籍当中,通常通过一个上浮的操作来完成push_heap。其基本原理可见下图(假设新加入的元素是50):
- 将50插入到数组的末尾。
- 将其于父元素相比较,发现24小于50,交换这两个元素。上浮一次
- 继续上述操作直到找到一个合适的位置,也即其父元素大于50的位置,则上浮结束。

一个简易的c++实现:
template<typename T>
void push_heap(std::vector<T> &vec, T value)
{
vec.push_back(value);
int i = vec.size()-1;
while (i > 1 && vec[i] > vec[i / 2]) {
std::swap(vec[i], vec[i / 2]);
i = i / 2;
}
}
pop_heap
pop操作是类似的:
- 将最后一个元素与第一个元素(根元素)交换。
- 删除最后一个元素。
- 将第一个元素/根元素下沉到一个合适的位置。注意下沉的时候是与子节点较大的那个元素交换。

一个简易的c++实现:
template<typename T>
T pop_heap(std::vector<T> &vec)
{
int i = 1;
//将最后元素与第一个元素(根元素)交换, 然后删除最后一个元素
std::swap(vec[1], vec[vec.size() - 1]);
T v = vec[vec.size() - 1];
vec.pop_back();
//将现在的第一个元素/根元素下沉到一个合适的位置
while (2 * i < vec.size()) {
int j = 2 * i; //左子节点
if (j < vec.size() - 1 && vec[j] < vec[j + 1]) j++;
if (vec[j] < vec[i]) break;
std::swap(vec[i], vec[j]);
i = j;
}
return v;
}
sort_heap
sort_heap是利用heap每次都取出极值(这里是max)的特性进行排序。那么只要进行n次pop_heap即可完成排序。
template<typename T>
void sort_heap(std::vector<T> &vec)
{
std::vector<T> temvec;
int size = vec.size()-1;
while (size != 0) {
temvec.push_back(pop_heap(vec));
size--;
}
for (T value : temvec) {
vec.push_back(value);
}
}
See you next time. Happy Coding!!!
我的github
数据结构与算法(6) -- heap的更多相关文章
- 数据结构与算法---堆排序(Heap sort)
堆排序基本介绍 1.堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序. 2.堆是具有以下性质的完全二叉树:每个 ...
- 数据结构与算法--堆(heap)与栈(stack)的区别
堆和栈的区别 在C.C++编程中,经常需要操作的内存可分为以下几个类别: 栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈. 堆区(heap ...
- 数据结构与算法 Big O 备忘录与现实
不论今天的计算机技术变化,新技术的出现,所有都是来自数据结构与算法基础.我们需要温故而知新. 算法.架构.策略.机器学习之间的关系.在过往和技术人员交流时,很多人对算法和架构之间的关系感 ...
- python 下的数据结构与算法---1:让一切从无关开始
这段时间把<Data Structure and Algorithms with python>以及<Problem Solving with Algorithms and Dat ...
- Java数据结构和算法(十四)——堆
在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...
- Java数据结构和算法 - 堆
堆的介绍 Q: 什么是堆? A: 这里的“堆”是指一种特殊的二叉树,不要和Java.C/C++等编程语言里的“堆”混淆,后者指的是程序员用new能得到的计算机内存的可用部分 A: 堆是有如下特点的二叉 ...
- Java数据结构和算法 - OverView
Q: 为什么要学习数据结构与算法? A: 如果说Java语言是自动档轿车,C语言就是手动档吉普.数据结构呢?是变速箱的工作原理.你完全可以不知道变速箱怎样工作,就把自动档的车子从1档开到4档,而且未必 ...
- Python3-Cookbook总结 - 第一章:数据结构和算法
第一章:数据结构和算法 Python 提供了大量的内置数据结构,包括列表,集合以及字典.大多数情况下使用这些数据结构是很简单的. 但是,我们也会经常碰到到诸如查询,排序和过滤等等这些普遍存在的问题. ...
- Java的数组,集合,数据结构,算法(一)
本人的愚见,博客是自己积累对外的输出,在学习初期或自己没有多少底料的情况下,与其总结写博客不如默默去搞自己的代码,但是学到集合这一块时,数组,集合,数据结构,算法这个概念搞的我比较混淆,所以不得已写这 ...
随机推荐
- ITK Configuring and Building in VisualStudio及hello world程序编译
1. ITK Configuring and Building in VisualStudio With Visual Studio 2010 on Windows 7 (32-bit): Launc ...
- Codeforces Beta Round #67 (Div. 2)C. Modified GCD
C. Modified GCD time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
- 第二章 在Html中使用JavaScript
https://www.jianshu.com/p/8247a9401725 2.1 Script元素 https://developer.mozilla.org/en-US/docs/Web/HTM ...
- Android开发常用框架汇总
作为一名程序猿,好的工具会让你在搬运工的道路上越走越远.以下框架是AC在开发过程中经常会使用到的一些好的框架.列在这里做一个小小的总结,包含但不限于此. 响应式编程 RxJava https://gi ...
- [POI 2007] Zap
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1101 [算法] 首先 , 问题可以转化为求GCD(x,y) = 1,x <= ...
- Black Rock Shooter
在人气动漫 Black Rock shooter 中,当加贺里对麻陶 说出了"滚回去"以后,与此同时,在另一个心灵世界里, BRS 也遭到了敌人的攻击.此时,一共有 n 个攻击排成 ...
- frameset的target属性
使用frameset时的target属性 (2012-09-18 08:19:31) 转载▼ 分类: java技术之路 一般常用的有四个属性 _blank 浏览器总在一个新打开.未命名的窗口中载入 ...
- Android App签名(为apk签名)
最近有朋友问到 android 签名的问题,所以转一篇给大家分享: 这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用. 1.签名的意义 为了保证每个应用程序开 ...
- 诡异之--map clear 之后可能导致size != 0的操作
map<char, int>mp; charMp[; charMp['b'] ++; cout<<charMp['a']<<endl; cout<<ch ...
- Spring Boot (25) RabbitMQ消息队列
MQ全程(Message Queue)又名消息队列,是一种异步通讯的中间件.可以理解为邮局,发送者将消息投递到邮局,然后邮局帮我们发送给具体的接收者,具体发送过程和时间与我们无关,常见的MQ又kafk ...