向堆中的插入需要以下步骤:
- 将值追加到数组的末尾
- 如果该值小于其父值,则将该值与其父值交换
- 对父级重复交换步骤,直到确认堆属性。
因此,插入的值可能会在从“最后一个”叶子到根的路径中的某个位置结束。
在这种情况下,树是:
15
// \
27 33
// \ / \
39 66 39 47
/ \\
58 51
“最后一个”叶子是 51,到根的路径已用双线标记。所以最后插入的候选者是 15、27、39 和 51。
例如,如果我们假设最后插入了 15,那么在插入之前,树应该是这样的(星号表示插入点):
27
// \
39 33
// \ / \
51 66 39 47
/
58 *
插入的 15 将沿着双标路径交换到根。此操作不涉及其他节点。
结论:最后不能插入的元素有:33、66、39、47、58。
一点警告
我们应该验证树——在插入之前——是一个有效的堆。上面的例子总是如此,但是如果我们对这棵树有疑问(注意底层的变化):
15
// \
27 33
// \ / \
39 66 39 47
/ \\
51 58
...那么最后插入的唯一可能值是 58。这是因为在插入发生之前,58 不可能是 51 的父级。这将违反堆属性。因此它不能被向下交换来向上移动插入的值。
这种情况的特点是路径上的值大于其直接兄弟(在此修改示例中,58 大于 51)。
但是,对于任何值 15、27、39 或 51,此“问题”不会出现在示例树中:它们都小于其兄弟姐妹(如果有的话)。