堆(Heaps)

我们想要这样一种数据结构,他可以进行插入和删除,但删除的话,规定每次删除的都是所有元素中最小的那一个元素。这可以利用数组和链表实现,但最好的是利用二叉树实现。如果用二叉搜索树的话删除太麻烦了,下面介绍一种堆的数据结构。

堆需要满足的性质

结构性质

引入完全二叉树的定义

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

完全二叉树可以很好的用数组来表示

含有N个节点的完全二叉树,可以使用一个大小为N+1的数组BT来存储。注意这里BT[0]不用来存储。

用上面这种方法表示有很多很有用的性质:

  1. 下标为 i 的节点的父节点下标为 i/2
  2. 下标为 i 的节点的左儿子下标为 2*i
  3. 下标为 i 的节点的右儿子下标为 2*i+1

BT[0]是用来做什么的?在进行一些堆的操作时有用,后面有说。

堆顺序的性质

最小堆:对于每一个节点,它都比左右两个节点的值小;或者说,节点比左右两个节点的都小,并且左右两棵子树都是堆。
按照这样的定义,我们就可以知道树的根节点一定是最小的元素,每次删除只需要取BT[1]就行了。
类似的我们也可得到一种最大堆,即对于每一个节点,它都比左右两个节点的值都大。这样根节点存的一定是值最大的元素。

堆的操作

插入


我们想向一个堆中插入14,一开始14放在数组的最后面,也就是左图的位置。很显然这里就不满足堆的性质。我们需要对14进行调整。注意,调整的话只需要对从根节点到14节点这一条路径进行调整就可以了。原来这条路径值为 13-21-31-14,我们将14向上调整到合适的位置变为 13-14-21-31,此时便满足了堆的性质。

//i表示14应该放的位置,一开始在++H->Size处
//每次将X与位置i处的父节点的值H->Elements[i/2]做比较
//父节点的值比它大,就将值相应下移,
for ( i = ++H->Size; H->Elements[ i / 2 ] > X; i /= 2 )H->Elements[ i ] = H->Elements[ i / 2 ];
H->Elements[ i ] = X;

我们这里考虑 i = 2 时的情形,
i = 2时,判断 H->Elements[1] > X ? 如果此时H->Element[1]仍然小于X,X应该被放在i=1即根节点位置。但是根据循环还会进行判断H->Elements[0] >X? 这时候就要用到我们前面说的下标0处的元素值了。我们将ELements[0]= MinData.将其预设为一个最小的元素,那么H->Elements[0] >X一定为false,循环就一定会在i=1处跳出。
我们将Element[0]称作标记(sentinel),这样有效避免了每次循环都要判断一次,节省了一些时间
T(N)=O(logN)T (N) = O ( log N )T(N)=O(logN)

删除元素

ElementType DeleteMin( PriorityQueue H )
{int i, Child;ElementType MinElement, LastElement;MinElement = H->Elements[ 1 ]; LastElement = H->Elements[ H->Size-- ]; //存储堆的最后一个元素,并将堆大小减1for ( i = 1; i * 2 <= H->Size; i = Child ) { //i从根节点开始并且i不是叶节点Child = i * 2;if (Child != H->Size && H->Elements[Child+1] < H>Elements[Child])Child++;  //如果有右儿子的话,判断左右儿子哪个小选哪个if ( LastElement > H->Elements[ Child ] ) H->Elements[ i ] = H->Elements[ Child ];//给最后一个元素找一个合适的位置放一下else break; }H->Elements[ i ] = LastElement;return MinElement;
}

PrecolateUp

DecreaseKey(P,▲,H),我们想将堆中位置P的值减小到▲。如果将这个值减小,那么要满足堆的性质就必须将它向上移动。所以有如下的上溯操作

void Heap::PercolateUp(int holeIndex, int adjustValue)
{int i; //记录要上溯到的位置   for (i = holeIndex; Elements[i / 2] > adjustValue; i /= 2)   //i从Size开始,只要ELements[i] > X, 就让i/=2Elements[i] = Elements[i / 2];            //同时将i处的值用i/2处代替,相当于整体下移Elements[i] = adjustValue;   //最后跳出时,找到了第一个Elements[i/2] <= X,
}

这样对于上面的插入操作可以写成
先将元素放在最后 Elements[++Size] = X;
然后进行上溯操作PercolateUp(Size, Elements[Size]);

PercolateDown

IncreaseKey(P,▲,H),将位置P的值增大到▲。如果将一个位置的值增大了,为了满足堆的性质,就要将这个值往下移动。所以我们 有如下的下溯操作

//将holeindex处的数值增大为adjustValue,并进行下溯
void Heap::PercolateDown(int holeIndex, int adjustValue)
{int child, i;    //i就是想要放的位置,满足了条件就跳出,说明找到了ifor (i = holeIndex; i * 2 <= Size; i = child)    //i从根节点开始,直到2*i > Size停止{child = i * 2;     //默认为左节点,偶数一定是左节点//从左右儿子中选择较小的那一个,要保证child+1存在if (child != Size && Elements[child + 1] < Elements[child]){child++;}//开始比较,类似PercolateUpif (adjustValue > Elements[child])Elements[i] = Elements[child];  //相应上移,空出holeelsebreak;    //找到位置就跳出}Elements[i] = adjustValue;
}

那么堆的删除操作可以写为
记录下最后一个元素值,同时Size减1: LastElement = Elements[Size–];
假定已经将LastElement的值放在了root位置,需要对其进行下溯
PercolateDown(1, LastElement);

建堆与调堆

依次读入一串数据,如何将他们建成堆?如何将N个key放入空的堆中?

void Heap::BuildHeap(vector<int> key)
{//将元素一个一个插入到heap中 , 每次的插入都保证是一个heapfor (int i = 0; i < key.size();i++)this->PushHeap(key[i]);
}

这称作自顶向下的建堆方式,第k层的节点个数有2k 个,第k层的一个节点插入后,调堆需要比较k次。n个元素的层数k为log2n那么总的次数为Σk2k =O(nlog2n)

如果一个数组中有N个key,如何将这个数组调整成堆?这里是调整成堆与上一个不同,或者可以叫自底向上的建堆。
方法是:从下标Size/2处开始对节点进行下溯操作,直到根节点1.为什么从Size/2开始,因为叶节点已经在最下面了,不用进行下溯。
同时注意 i 不能从1变大到size/2,必须从Size/2 减小到1。因为是从叶节点往上使每一路的顺序正确。

    for (int i = this->Size / 2; i > 0;i--){this->PercolateDown(i, Elements[i]);  //由于是对每个节点进行下溯调整,所以叶节点值不用调整的,只需调整 i<Size/2的部分}

这种方式,第i层最坏情况下有2i 个节点(满二叉树),第i层的节点最坏情况要移动n-i次(n表示总层数)。所以所需时间为T=Σ(2k *(n-k)) k from 1 to n ;如何计算这个等式,发现这个等式相当于计算高度为h的完全二叉树的所有节点的高度和
高度为h的完全二叉树有2h+1-1个节点,所有节点的高度的和为2h+1-1-(h+1),所以时间按复杂度约为O(N)。

自底向上建堆,由于底部节点多,所需比较次数反而少,所以所需时间更少为O(N),

堆的应用

找出N个元素中第K大的元素。
将N个元素调成最大堆,时间复杂度为O(N),然后,进行k次删除,获得的就是第K大的元素,总的时间复杂度为O(N+K).比排序好再取快多了。

d-Heaps

All nodes have d children

  • 不能将d设的很大,因为删除时,寻找最小或最大儿子要比较的次数将增多
  • DeleteMin will take d - 1 comparisons to find the smallest child. Hence the total time complexity would be O(dlogdN)O(d log_d N)O(dlogd​N).

数据结构 3优先队列(堆)相关推荐

  1. 数据结构之优先队列--二叉堆(Java实现)

    前言 数据结构队列的学习中,我们知道队列是先进先出的.任务被提交到队列中,按照先进先出的原则 对各个任务进行处理.不过在现实的情况下,任务通常有着优先级的概念,例如短任务.管理员的操作 应该优先执行. ...

  2. c语言将数组的列项向左移动,【数据结构与算法分析——C语言描述】第六章:优先队列(堆)...

    第六章:优先队列(堆) [TOC] 思考如下场景,老师布置了很多作业,现在你需要将作业打印出来,你将作业文件依照队列的形式放入待打印列表中,但此时,你希望最重要(或者是马上就要上交)的作业优先打印出来 ...

  3. 数据结构之优先队列:最小索引优先队列,Python代码实现——15

    最小索引优先队列(Min index priority queue) 在之前实现的最大优先队列和最小优先队列,他们可以分别快速访问到队列中最大元索和最小元素,但是他们有一 个缺点,就是没有办法通过索引 ...

  4. [算法系列]优先队列,堆与堆排序

    优先队列,堆与堆排序 1 优先队列 有时我们在处理有序元素时,并不一定要求他们全部有序. 很多情况下我们会收集一些元素, 处理当前最大的元素, 然后再收集更多元素, 再处理当前最大元素 - 这种情况下 ...

  5. 数据结构与算法---堆的基本操作

    堆的定义 堆可以看做是一种特殊的树,堆结构满足两个条件: 1.堆是一个完全二叉树. 2.堆的每一个节点的值都大于等于(或小于等于)其子节点的值. 大于等于子节点的值我们叫它:大顶堆 小于等于子节点的值 ...

  6. 0x17.基础数据结构 - 二叉堆

    目录 一.二叉堆 二.例题 0.AcWing 145. 超市 AcWing 146. 序列(POJ 2442) 三.HuffmanHuffmanHuffman树 1.AcWing 148. 合并果子 ...

  7. 数据结构之优先队列:优先队列的介绍与基础操作实现,Python代码实现——14

    优先队列(Priority queue)的介绍 优先队列是计算机中一种抽象的数据结构类,它有着一个类似和队列或者堆的结构,但是其中每个元素额外有一个优先级别 在一个优先队列中,一个高优先顺序的元素会先 ...

  8. 数据结构与算法 / 堆结构

    一.基本信息 1.本质 一颗特殊的树. 2.特性 完全二叉树. 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值. 3.分类 对于每一个节点的值都大于等于子节点的值的情况,该堆被称为 ...

  9. 数据结构与算法 | 堆

    二叉树的顺序结构 堆的概念及结构 堆的实现 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费.而完全二叉树更适合使用顺序结构存储.现实中我们通常把堆(一种二叉树)使用 ...

最新文章

  1. vSphere开发指南1——vSphere Automation API
  2. mysql 插入数据时,出现\xF0\x5F\x6F\x70问题
  3. linux下的精确wait
  4. MANIFEST.MF
  5. 论文笔记_CV_AD_Visual Perception for Autonomous Driving
  6. python字符串的删除操作_学习快人一步|python中常见的27个字符串操作
  7. 初始MySQL数据库
  8. @property python知乎_【python】__slots__与@property
  9. 阻止计算机病毒入侵系统,入侵预防系统
  10. 单片机模拟iic从设备-主要代码(2)
  11. css涟漪光圈扩散_CSS3动画之:水波涟漪般的定位样式
  12. js 匹配正确手机号
  13. 51单片机倒计时计时器(计时结束闹钟)
  14. 浅谈单元测试之(一):单元测试的意义
  15. 13 MATLAB判别分析
  16. 花式玩转Linux集群免密登录
  17. wxpy 微信聊天机器人的实现
  18. node_modules\fibers\bin\win32-x64-83\fibers.node` is missing 报错解决方案
  19. 2021最新高端HTML前端网站模板下载
  20. 微信公众号二次开发之消息回复

热门文章

  1. layUI日期格式转换
  2. 2021 MetaCamp程序设计大赛线上资格赛 7-2 心情故事
  3. 黑苹果mac未能安装在你的电脑上_mac电脑上全新视频剪辑软件安装包分享,让你剪辑视频从此无忧!...
  4. android room数据库embed,Android room数据库基操
  5. 前向声明 智能指针_C++ 指针类中实现 -gt;*
  6. 数据结构—B树(思维导图)
  7. 缓存淘汰算法 LRU
  8. 2019蓝桥杯C++B组 年号字串;完全二叉树的权值
  9. python应用系列教程——python使用smtp协议发送邮件:html文本邮件、图片邮件、文件附件邮件
  10. LaTex建立参考文献链接