参考自:
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