参考自:

  https://www.jianshu.com/p/6b526aa481b1

  堆就是用数组实现的完全二叉树,所以它没有使用父指针或者子指针。它根据“堆属性”来排序,“堆属性”决定了树中节点的位置。

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

  大顶堆:每一个父节点的值都比其子节点要大。

  小顶堆:每一个父节点的值都比其子节点要小。

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

堆和二叉搜索树的比较:

  节点的顺序

  在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。

  但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

  内存占用

  二叉搜索树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额为是我内存。

  堆仅仅使用一个数据来村塾数组,且不使用指针。

  平衡

  二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树。

  但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

  搜索

  在二叉树中搜索会很快,但是在堆中搜索会很慢。

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

堆的操作:

  插入

  

  我们向数组[ 10, 7, 2, 5, 1 ]中添加16。

  插入后,16被添加到最后的位置上,树变成了:

  

  但是这棵树不满足堆的属性,所以交换16和2的位置:

  

  仍旧不满足堆属性,交换16和10的位置,此时插入16成功得到大顶堆:

  

  

  删除根节点

   

  删除这个堆中的根节点10。

  

  新的根节点应该怎么办?

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

  以1位根节点。

  

  不满足大顶堆的属性,交换1和7:

  

  不满足大顶堆的属性,交换1和5:

  

  得到删除根节点后的大顶堆。

  删除任意节点

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

  

  删除7

  因为移除一个元素会破坏最大堆或者最小堆属性,所以我们需要将删除的元素和最后一个元素交换:

  

  最后一个元素就是我们需要返回的元素,然后调用方法把它删除即可。

  

  在对删除后的树修复堆属性,就可得到删除任意节点的堆了。

  

转载请注明地址:https://www.cnblogs.com/fangxiaoqi/

觉得有帮助的话可以点一下推荐,thanks

原文地址:https://www.cnblogs.com/cruelty_angel/p/10505226.html