数据结构:堆(Heap)

数据结构:堆(Heap)

    <!-- 文章内容 --><div data-note-content="" class="show-content"><div class="show-content-free"><p>堆就是用数组实现的二叉树,所有它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。</p>

堆的常用方法:

  • 构建优先队列
  • 支持堆排序
  • 快速找出一个集合中的最小值(或者最大值)
  • 在朋友面前装逼

堆属性

堆分为两种:最大堆最小堆,两者的差别在于节点的排序方式。

在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。

例子:

这是一个最大堆,,因为每一个父节点的值都比其子节点要大。1072 都大。751都大。

根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常的有用,因为堆常常被当做优先队列使用,因为可以快速的访问到“最重要”的元素。

注意:堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。例如,在一个最大堆中,最大的那一个元素总是位于 index 0 的位置,但是最小的元素则未必是最后一个元素。--唯一能够保证的是最小的元素是一个叶节点,但是不确定是哪一个。

堆和普通树的区别

堆并不能取代二叉搜索树,它们之间有相似之处也有一些不同。我们来看一下两者的主要差别:

节点的顺序。在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用。普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额为是我内存。堆仅仅使用一个数据来村塾数组,且不使用指针。

平衡。二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

搜索。在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。

来自数组的树

用数组来实现树相关的数据结构也许看起来有点古怪,但是它在时间和空间山都是很高效的。

我们准备将上面的例子中的树这样存储:

[ 10, 7, 2, 5, 1 ]

就这多!我们除了一个简单的数组以外,不需要任何额外的空间。

如果我们不允许使用指针,那么我们怎么知道哪一个节点是父节点,哪一个节点是它的子节点呢?问得好!节点在数组中的位置index 和它的父节点已经子节点的索引之间有一个映射关系。

如果 i 是节点的索引,那么下面的公式就给出了它的父节点和子节点在数组中的位置:

parent(i) = floor((i - 1)/2)
left(i)   = 2i + 1
right(i)  = 2i + 2

注意 right(i) 就是简单的 left(i) + 1。左右节点总是处于相邻的位置。

我们将写公式放到前面的例子中验证一下。

NodeArray index (i)Parent indexLeft childRight child
100-112
71034
22056
53178
141910

注意:根节点(10)没有父节点,因为 -1 不是一个有效的数组索引。同样,节点 (2)(5)(1) 没有子节点,因为这些索引已经超过了数组的大小,所以我们在使用这些索引值的时候需要保证是有效的索引值。

复习一下,在最大堆中,父节点的值总是要大于(或者等于)其子节点的值。这意味下面的公式对数组中任意一个索引 i都成立:

array[parent(i)] >= array[i]

可以用上面的例子来验证一下这个堆属性。

如你所见,这些公式允许我们不使用指针就可以找到任何一个节点的父节点或者子节点。事情比简单的去掉指针要复杂,但这就是交易:我们节约了空间,但是要进行更多计算。幸好这些计算很快并且只需要O(1)的时间。

理解数组索引和节点位置之间的关系非常重要。这里有一个更大的堆,它有15个节点被分成了4层:


Array.png

图片中的数字不是节点的值,而是存储这个节点的数组索引!这里是数组索引和树的层级之间的关系:

由上图可以看到,数组中父节点总是在子节点的前面。

注意这个方案与一些限制。你可以在普通二叉树中按照下面的方式组织数据,但是在堆中不可以:

在堆中,在当前层级所有的节点都已经填满之前不允许开是下一层的填充,所以堆总是有这样的形状:

注意:你可以使用普通树来模拟堆,但是那对空间是极大的浪费。

小测验,假设我们有这样一个数组:

[ 10, 14, 25, 33, 81, 82, 99 ]

这是一个有效的堆吗?答案是 yes !一个从低到高有序排列的数组是以有效的最小堆,我们可以将这个堆画出来:

堆属性适用于每一个节点,因为父节点总是比它的字节点小。(你也可以验证一下:一个从高到低有序排列的数组是一个有效的最大堆)

注意:并不是每一个最小堆都是一个有序数组!要将堆转换成有序数组,需要使用堆排序。

更多数学公式

如果你好奇,这里有更多的公式描述了堆的一些确定属性。你不需要知道这些,但它们有时会派上用场。 可以直接跳过此部分!

树的高度是指从树的根节点到最低的叶节点所需要的步数,或者更正式的定义:高度是指节点之间的边的最大值。一个高度为 h 的堆有 h+1 层。

下面这个对的高度是3,所以它有4层:

如果一个堆有 n 个节点,那么它的高度是 h = floor(log2(n))。这是因为我们总是要将这一层完全填满以后才会填充新的一层。上面的例子有 15 个节点,所以它的高度是 floor(log2(15)) = floor(3.91) = 3

如果最下面的一层已经填满,那么那一层包含 2^h 个节点。树中这一层以上所有的节点数目为 2^h - 1。同样是上面这个例子,最下面的一层有8个节点,实际上就是 2^3 = 8。前面的三层一共包含7的节点,即:2^3 - 1 = 8 - 1 = 7

所以整个堆中的节点数目为:* 2^(h+1) - 1*。上面的例子中,2^4 - 1 = 16 - 1 = 15

叶节点总是位于数组的 floor(n/2)n-1 之间。

可以用堆做什么?

有两个原始操作用于保证插入或删除节点以后堆是一个有效的最大堆或者最小堆:

  • shiftUp(): 如果一个节点比它的父节点大(最大堆)或者小(最小堆),那么需要将它同父节点交换位置。这样是这个节点在数组的位置上升。
  • shiftDown(): 如果一个节点比它的子节点小(最大堆)或者大(最小堆),那么需要将它向下移动。这个操作也称作“堆化(heapify)”。

shiftUp 或者 shiftDown 是一个递归的过程,所以它的时间复杂度是 O(log n)

基于这两个原始操作还有一些其他的操作:

  • insert(value): 在堆的尾部添加一个新的元素,然后使用 shiftUp 来修复对。
  • remove(): 移除并返回最大值(最大堆)或者最小值(最小堆)。为了将这个节点删除后的空位填补上,需要将最后一个元素移到根节点的位置,然后使用 shiftDown 方法来修复堆。
  • removeAtIndex(index): 和 remove() 一样,差别在于可以移除堆中任意节点,而不仅仅是根节点。当它与子节点比较位置不时无序时使用 shiftDown(),如果与父节点比较发现无序则使用 shiftUp()
  • replace(index, value):将一个更小的值(最小堆)或者更大的值(最大堆)赋值给一个节点。由于这个操作破坏了堆属性,所以需要使用 shiftUp() 来修复堆属性。

上面所有的操作的时间复杂度都是 O(log n),因为 shiftUp 和 shiftDown 都很费时。还有少数一些操作需要更多的时间:

  • search(value):堆不是为快速搜索而建立的,但是 replace()removeAtIndex() 操作需要找到节点在数组中的index,所以你需要先找到这个index。时间复杂度:O(n)
  • buildHeap(array):通过反复调用 insert() 方法将一个(无序)数组转换成一个堆。如果你足够聪明,你可以在 O(n) 时间内完成。
  • 堆排序:由于堆就是一个数组,我们可以使用它独特的属性将数组从低到高排序。时间复杂度:O(n lg n)

堆还有一个 peek() 方法,不用删除节点就返回最大值(最大堆)或者最小值(最小堆)。时间复杂度 O(1)

注意:到目前为止,堆的常用操作还是使用 insert() 插入一个新的元素,和通过 remove()移除最大或者最小值。两者的时间复杂度都是O(log n)。其其他的操作是用于支持更高级的应用,比如说建立一个优先队列。

插入

我们通过一个插入例子来看看插入操作的细节。我们将数字 16 插入到这个堆中:

堆的数组是: [ 10, 7, 2, 5, 1 ]

第一股是将新的元素插入到数组的尾部。数组变成:

[ 10, 7, 2, 5, 1, 16 ]

相应的树变成了:

16 被添加最后一行的第一个空位。

不行的是,现在堆属性不满足,因为 216 的上面,我们需要将大的数字在上面(这是一个最大堆)

为了恢复堆属性,我们需要交换 162

现在还没有完成,因为 10 也比 16 小。我们继续交换我们的插入元素和它的父节点,直到它的父节点比它大或者我们到达树的顶部。这就是所谓的 shift-up,每一次插入操作后都需要进行。它将一个太大或者太小的数字“浮起”到树的顶部。

最后我们得到的堆:

现在每一个父节点都比它的子节点大。

删除根节点

我们将这个树中的 (10) 删除:

现在顶部有一个空的节点,怎么处理?

当插入节点的时候,我们将新的值返给数组的尾部。现在我们来做相反的事情:我们取出数组中的最后一个元素,将它放到树的顶部,然后再修复堆属性。

现在来看怎么 shift-down (1)。为了保持最大堆的堆属性,我们需要树的顶部是最大的数据。现在有两个数字可用于交换 72。我们选择这两者中的较大者称为最大值放在树的顶部,所以交换 71,现在树变成了:

继续堆化直到该节点没有任何子节点或者它比两个子节点都要大为止。对于我们的堆,我们只需要再有一次交换就恢复了堆属性:

删除任意节点

绝大多数时候你需要删除的是堆的根节点,因为这就是堆的设计用途。

但是,删除任意节点也很有用。这是 remove() 的通用版本,它可能会使用到 shiftDownshiftUp

我们还是用前面的例子,删除 (7):

[图片上传失败...(image-d46ac4-1534077058042)]

对应的数组是

[ 10, 7, 2, 5, 1 ]

你知道,移除一个元素会破坏最大堆或者最小堆属性。我们需要将删除的元素和最后一个元素交换:

[ 10, 1, 2, 5, 7 ]

最后一个元素就是我们需要返回的元素;然后调用 removeLast() 来将它删除。 (1) 比它的子节点小,所以需要 shiftDown() 来修复。

然而,shift down 不是我们要处理的唯一情况。也有可能我们需要 shift up。考虑一下从下面的堆中删除 (5) 会发生什么:

现在 (5)(8) 交换了。因为 (8) 比它的父节点大,我们需要 shiftUp()

原文请戳这里

      </div></div>
</div>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/481253.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BAT机器学习面试1000题系列

1、本文的内容全部来源于七月在线发布的BAT机器学习面试1000题系列&#xff1b; 2、文章中带斜体的文字代表是本人自己增加的内容&#xff0c;如有错误还请批评指正&#xff1b; 3、原文中有部分链接已经失效&#xff0c;故而本人重新加上了新的链接&#xff0c;如有不当&…

拉马努金:“与神对话”的数学天才

来源&#xff1a;微信公众号“图灵教育”撰文&#xff1a;[英] 马库斯杜索托伊翻译&#xff1a;柏华元当哈代和利特尔伍德步履维艰地穿越陌生的黎曼图景时&#xff0c;在5000英里外的印度马德拉斯港务局内&#xff0c;一个名叫斯里尼瓦瑟拉马努金的年轻办事员被素数的神秘莫测吸…

浅入深出被人看扁的逻辑回归!

好像在各种机器学习入门教程中&#xff0c;逻辑回归模型&#xff08;Logistic/Logit Regression&#xff09;经常被拿来作为入门的机器学习模型&#xff0c;比如我家的Andrew Ng就是这样做的。看起来&#xff0c;逻辑回归模型实在太简单&#xff0c;甚至容易被认为是一个拍脑袋…

全球Web3技术产业生态发展报告(2022年)

来源&#xff1a;中国信息通信研究院编辑&#xff1a;蒲蒲Web3不只是互联网应用层的简单创新&#xff0c;可能会带来互联网体系架构整体性演进和系统性升级。党中央、国务院高度关注下一代互联网创新发展&#xff0c;在关键核心技术突破、新型基础设施建设、融合创新应用赋能等…

算法工程师笔试 -剑指offer-习题详细解答

说明 主要编程语言为 C/C涉及字符串的问题可能会使用 Python题目编号以原书为准&#xff0c;如“面试题 3&#xff1a;数组中重复的数字” 因为题目不多&#xff0c;所以就不做分类了 所有代码均通过 OJ 测试 在线 OJ 地址&#xff1a;剑指Offer_编程题 - 牛客网 Reference 《…

深入深出Sigmoid与Softmax的血缘关系

缘起逻辑回归逻辑回归模型是用于二类分类的机器学习模型&#xff08;不要说逻辑回归可以做多类分类啊喂&#xff0c;那是二类分类器的组合策略问题&#xff0c;而与逻辑回归分类器本身的构造没有半毛钱关系啊&#xff09;。我们知道&#xff0c;在逻辑回归中&#xff0c;用于预…

科学家使用机器学习获得前所未有的小分子视图

编辑 | 绿萝数以千计的不同小分子&#xff08;称为代谢物&#xff09;在整个人体中传输能量和传递细胞信息。由于它们非常小&#xff0c;因此很难在血液样本分析中将代谢物彼此区分开来——但识别这些分子对于了解运动、营养、饮酒和代谢紊乱如何影响健康非常重要。尽管在过去十…

【Brain】脑洞从何而来?加州大学最新研究:有创造力的人神经连接会「抄近道」...

来源&#xff1a;量子位为什么有的人更富创造力&#xff1f;总能想到别人不会想到的东西&#xff0c;做别人想不到做的事&#xff1f;最近&#xff0c;这个问题的答案被找到了&#xff1a;有创造力的人&#xff0c;大脑里的神经活动会“抄近道”。加州大学洛杉矶分校的研究人员…

一位老师,一位领导,一个让全体学生考上目标学校的故事

今天&#xff0c;小夕给大家讲一个故事... 从前&#xff0c;有座山...​ 山里&#xff0c;有座学校... 学校里&#xff0c;有一位老师&#xff0c;一位领导&#xff0c;还有五只可爱的小仙(学)女(生)。 这5个学生的名字是&#xff1a;小兔&#xff0c;小青&#xff0c;小路&…

小冰李笛:ChatGPT在向“让你认为它有知识”的方向发展 | MEET 2023

来源&#xff1a;量子位衡宇 整理自 MEET2023ChatGPT技惊四座&#xff0c;甚至不少人认为它已经能“取代搜索引擎”。然而就在MEET2023智能未来大会上&#xff0c;却出现了这样一种迥然相异的观点&#xff1a;未来5年里&#xff0c;大家想要获取知识&#xff0c;最好的方法还是…

从前,有只小仙女叫...

从前&#xff0c;有只小仙女叫小音✧٩(ˊωˋ*)و✧这一篇真的不是小夕萌的技术文啦(&#xffe3;∇&#xffe3;)今天小夕给大家推送一点好玩的东西~毕竟高中老师说过&#xff0c;不能只学不玩嘛(&#xffe3;∇&#xffe3;)虽然小夕以萌著称\(//∇//)\&#xff0c;但是在da…

DeepMind新研究:AI也懂合纵连横

摘要人类文明的成功&#xff0c;植根于我们通过沟通和制定共同计划进行合作的能力。人工智能主体面临着与人类类似的问题。最近&#xff0c;人工智能公司 DeepMind 展示了AI如何利用沟通在桌游“强权外交”中更好地合作。研究发现&#xff0c;沟通主体容易受到背叛协议者的负面…

从逻辑回归到神经网络

回顾小夕在文章《逻辑回归》中详细讲解了逻辑回归模型&#xff0c;又在《Sigmoid与Softmax》中详细讲解了Sigmoid的实际意义&#xff08;代表二类分类问题中&#xff0c;其中一个类别的后验概率&#xff09;。至此&#xff0c;我们已经比较透彻的理解了逻辑回归模型假设函数(也…

华为2019年校招(20届实习)机考题python版解答与思路(2019-3-13软件题)

试题为今天考试时记下&#xff0c;记于此仅做学习分享。侵删。 答案思路仅供参考&#xff0c;肯定有更优的办法&#xff01;第三题没解出来&#xff0c;欢迎大家评论提点&#xff01; 第一题&#xff1a; 这道题对输入做切分&#xff08;调用split()方法&#xff09;后&#xf…

语言模型生成了自然界不存在的蛋白质,图灵奖得主LeCun:蛋白质编程来了

来源&#xff1a;药学前沿进展Meta&#xff1a;设计蛋白质这件事&#xff0c;语言模型就能干。用机器学习去研究蛋白质结构预测&#xff0c;吸引了众多科技大厂、科研机构的目光纷纷投入其中&#xff0c;这期间&#xff0c;他们也产出了重要成果。如在 2021 年 《Science》的十…

神经网络中的偏置项b到底是什么?

前言很多人不明白为什么要在神经网络、逻辑回归中要在样本X的最前面加一个1&#xff0c;使得 X[x1,x2,…,xn] 变成 X[1,x1,x2,…,xn] 。因此可能会犯各种错误&#xff0c;比如漏了这个1&#xff0c;或者错误的将这个1加到WX的结果上&#xff0c;导致模型出各种bug甚至无法收敛。…

【重版】朴素贝叶斯与拣鱼的故事

重版公告由于小夕之后要讲的好几篇文章要基于这一篇的知识&#xff0c;但是以前写的的这篇文章对朴素贝叶斯的讨论不够深入&#xff0c;又不值得再额外写一篇朴素贝叶斯啦&#xff0c;因此本文重版了以前的文章《朴素贝叶斯》。与旧版相比&#xff0c;新版对基础知识的讲解进行…

2022,这些国之重器让人眼前一亮!

来源&#xff1a;新华社2022即将收官这一年我们有许多难忘的回忆回顾&#xff0c;是为了更好出发我们将这一年各领域走过的壮阔征程制作成了精美的系列海报第一期让我们来看看那些让人眼前一亮的国之重器它们——上天入海&#xff01;乘风破浪&#xff01;贯通聚能&#xff01;…

逻辑回归与朴素贝叶斯的战争

0一起走过的首先&#xff0c;小夕带领大家回顾一下文章《逻辑回归》、《Sigmoid与Softmax》、《朴素贝叶斯》中的几点内容&#xff0c;这几点内容也是本文的前置知识&#xff1a;1. 逻辑回归模型的表达式(假设函数)&#xff1a;&#xff0c;其中。2. 逻辑回归模型本质上是二类分…

OpenAI年底上新,单卡1分钟生成3D点云,text-to 3D告别高算力消耗时代

来源&#xff1a;大数据文摘授权转载自HyperAI超神经作者&#xff1a;三羊OpenAI 年底冲业绩&#xff0c;半个多月前发布的 ChatGPT 广大网友还没玩明白&#xff0c;近日又悄么发布了另一利器--可以依据文本提示&#xff0c;直接生成 3D 点云的 PointE。text-to-3D&#xff1a;…