我一直在使用向量在C ++中实现堆。因为我必须轻松访问节点(2n,2n + 1)的子节点,所以我必须从索引1开始。这是正确的方法吗?根据我的实现,在第零个位置总是有一个虚拟元素。
答案 0 :(得分:4)
你的方式有效。或者,您可以在索引0
处拥有root,并在2n+1
和2n+2
生成子项
答案 1 :(得分:2)
虽然这适用于堆,但最终会为其他树数据结构使用大量冗余内存,而这些结构不一定具有完整且完整的二叉树。例如,这意味着如果你有一个20个节点的深度为5的二进制搜索树,你最终必须使用2 ^ 5 = 32而不是20的数组。现在想象一下你是否需要一个25个节点的树深度为22.您最终使用了大量的4194304,而您可以使用链接表示来存储25个节点。
您仍然可以使用数组而不会产生这样的内存命中。只需将一大块内存分配为数组,并使用数组索引作为指向子代的指针。
因此,你在哪里
node.left = (node.index*2)
node.right = (node.index*2+1)
您只需使用
node.left = <index of left child>
node.right = <index of right child>
或者,如果您的语言支持,您可以只使用指针/引用而不是整数索引。
修改强>
对于每个人来说,完整的二叉搜索树占用O(2 ^ d)内存可能并不明显。有d个级别,每个级别的节点数量是其父级所在级别的两倍(因为除了底部的节点之外的每个节点都有两个子节点 - 从不一个)。 binary heap是binary tree(但不是二进制搜索树),根据定义总是完整的,因此OP概述的基于数组的实现不会产生任何实际的内存开销。对于堆,这是在代码中实现它的最佳方式。 OTOH,大多数其他二叉树(尤其是二进制搜索树)不保证是完整的。因此,尝试使用这种方法需要O(2 ^深度)内存,其中深度可以与n一样大,其中我们在链接实现中只需要O(n)内存。
所以我的回答是:是的,这是堆的最佳方式。只是不要为其他二叉树尝试它(除非你确定它们总是完整的)。