我正在阅读Nicolai M. Josuttis" C ++标准库,教程和参考",ed2。
他解释了堆数据结构和相关的STL函数(第607页):
该程序具有以下输出:
on entry: 3 4 5 6 7 5 6 7 8 9 1 2 3 4
after make_heap(): 9 8 6 7 7 5 5 3 6 4 1 2 3 4
after pop_heap(): 8 7 6 7 4 5 5 3 6 4 1 2 3
after push_heap(): 17 7 8 7 4 5 6 3 6 4 1 2 3 5
after sort_heap(): 1 2 3 3 4 4 5 5 6 6 7 7 8 17
我想知道如何解决这个问题?例如,为什么叶子" 4"在路径9-6-5-4下是节点" 5"的左侧子节点,而不是右侧节点的子节点?在pop_heap
树结构之后呢?在IDE调试模式中,我只能看到向量的内容,有没有办法找出树结构?
答案 0 :(得分:1)
向量中的第一个元素是索引0处的根。它的左子节点位于索引1处,右侧子节点位于索引2处。通常:left_child(i) = 2 * i + 1
和right_child(i) = 2 * i + 2
以及{{1} }
考虑它的另一种方法是堆填充树中从从左到右的每个级别。在向量中的元素之后,第一级是9(1值),第二级是8 6(2个值),第三级是7 7 5 5(4个值),依此类推。这两种方法都可以帮助您在给定向量时在树结构中绘制堆。
答案 1 :(得分:1)
为什么叶子" 4"在路径9-6-5-4下是节点" 5"的左侧子节点,而不是右侧节点的子节点?
因为如果它在右侧,那就意味着底层向量中存在间隙。树结构仅用于说明目的。它不代表堆的实际存储方式。树结构通过简单的数学公式映射到底层矢量。
树的根节点是向量的第一个元素(索引0)。节点的左子节点的索引是通过简单公式i * 2 + 1
从其父节点索引获得的。并且正确孩子的索引是通过i * 2 + 2
获得的。
然后在pop_heap之后是什么树结构呢?
根节点与其两个子节点中的较大节点 1 交换,并重复此节点直到它位于树的底部。然后它与最后一个元素交换。然后,如果必要的话,通过与其父项交换(如果它更大),将该元素向上推。
根节点与堆的最后一个元素交换。然后,通过与其两个子项 1 中的较大者交换,将该元素向下推到堆中。重复这一过程,直到它处于正确的位置(即它不小于其任何一个孩子)。
所以在pop_heap之后,你的树看起来像这样:
----- 8 -----
| |
---7--- ---6---
| | | |
-7- -4- -5- x5
| | | | | | x
3 6 4 1 2 3 9
9实际上不再是堆的一部分,但它仍然是向量的一部分,直到你通过调用pop_back
或类似的方式擦除它。
<子> 1。如果孩子们是平等的,就像在你的例子中树的相邻7的情况一样,它可以是任何一种方式。我相信std::pop_heap
将其发送到右侧,但我不确定这是否是实施定义