堆是数组内部的二叉树,因此它不使用父/子指针。根据“堆属性”对堆进行排序,该“堆属性”确定树中节点的顺序。
堆的常见用途:
堆属性
堆有两种:max-heap和min-heap,它们的存储树节点顺序不同。
在最大堆中,父节点的值大于其每个子节点的值。在最小堆中,每个父节点的值都小于其子节点的值。这称为“堆属性”,对于树中的每个节点都是如此。
一个例子:
这是一个最大堆,因为每个父节点都大于其子节点。(10)
大于(7)
和(2)
。(7)
大于(5)
和(1)
。
由于具有此堆属性,因此,max-heap始终将其最大的项存储在树的根目录中。对于最小堆,根始终是树中最小的项。堆属性很有用,因为堆经常被用作优先级队列来快速访问“最重要”元素。
**注意:**堆的根具有最大或最小元素,但是其他元素的排序顺序是不可预测的。例如,最大元素在最大堆中始终位于索引0,但最小元素不一定是最后一个。-您唯一的保证是它是叶子节点之一,但不是哪个。
堆与常规树相比如何?
堆不能代替二叉搜索树,它们之间有相似之处和不同之处。主要区别如下:
**节点顺序。**在二叉搜索树(BST)中,左子级必须小于其父级,而右子级必须更大。对于堆来说不是这样。在最大堆中,两个子项都必须小于父项,而在最小堆中,两个子项都必须更大。
**记忆。**传统的树占用的内存不仅仅是它们存储的数据。您需要为节点对象和指向左/右子节点的指针分配其他存储。堆仅使用普通数组进行存储,并且不使用指针。
**平衡。二叉搜索树必须是“平衡的”,以便大多数操作具有O(log n)性能。您可以按随机顺序插入和删除数据,也可以使用AVL树或红黑树之类的东西,但是使用堆,我们实际上不需要对整个树进行排序。我们只希望能够满足heap属性,因此平衡不是问题。由于堆的结构方式,堆可以保证O(log n)**性能。
**搜索。**在二叉树中搜索速度很快,而在堆中搜索速度却很慢。搜索不是堆中的最高优先级,因为堆的目的是将最大(或最小)节点放在最前面,并允许相对快速的插入和删除。
数组内的树
数组似乎是实现树状结构的一种奇怪方法,但它在时间和空间上都是有效的。
这就是上面示例中存储树的方式:
[ 10, 7, 2, 5, 1 ]
这里的所有都是它的!除了这个简单的数组,我们不需要更多的存储。
因此,如果不允许使用任何指针,我们如何知道哪些节点是父节点,哪些是孩子?好问题!树节点的数组索引与其父节点和子节点的数组索引之间存在明确定义的关系。
如果i
是节点的索引,则以下公式给出其父节点和子节点的数组索引:
parent(i) = floor((i - 1)/2)
left(i) = 2i + 1
right(i) = 2i + 2
请注意,这right(i)
很简单left(i) + 1
。左节点和右节点始终彼此相邻存储。
让我们在示例中使用这些公式。填写数组索引,我们应该获得父节点和子节点在数组中的位置: