5

我昨天问了一个问题,但不是很清楚,所以这是一个更具体的问题。

我将我的 minheap 表示为一个数组。我对我认为的 minheaps 有很好的理解,但我对其中的某个概念很模糊。Minheaps 总是应该有最小的节点作为根。要删除一个值,将根设置为数组表示中的最后一个元素(叶节点),并且数组的大小会递减。然后通过使用 siftDown/PercolateDown 或您想调用的任何名称正确放置根节点。这是超级有效的。例如:

树 1

这里 29 取自最后一个元素, siftDown(1) 将放置它:

  1. 29 与 15 和 38 进行比较。交换 29 和 15。
  2. 29 与 25 和 20 进行比较。交换 29 和 20。
  3. 29 与 30 进行比较,29 < 30 因此我们完成了。

这一切都很好,但是如果在两次删除最小值之间,其他一些数据发生了变化怎么办?例如:

树 2

那么这里:

  1. 29 与 15 和 38 进行比较。交换 29 和 15。
  2. 29 与 30 和 32 进行比较。29 < 30 和 29 < 32 因此我们完成了。

1 是树中的最小值,但尚未设置为最小值,15 已设置。这对我来说是个大问题。我正在尝试实现 Dijkstras 算法,我也在尝试使用我自己的数据结构而不触及 Java 内置类。

因此,与我的问题更相关的示例是:

在此处输入图像描述

对于熟悉 Dijkstras 的人来说,99 代表一个无限远的暂定距离,其他数字代表接下来应该访问的图节点(距离最小的节点,在本例中为 3)。

一个解决方案是每次删除 min 时都重建树,但这意味着 minheap 的功能会丢失,并且任何实现都会慢下来。

抱歉,如果我没有正确理解这一点,但我已经坚持了好几天了,我真的需要一些帮助。

4

1 回答 1

2

您需要了解算法的前提条件。该算法siftDown不适用于任何任意数组。它仅在其左孩子和右孩子是堆时才有效。

在您的第二个示例中,根的左孩子不是最小堆。因此,该算法不会产生最小堆。

如果您最终得到一个违反堆属性的数组,例如图像编号 3,那么您的实现中一定有问题。

于 2016-04-19T13:50:28.887 回答