使用堆属性按照排序顺序打印树(Cormen)

时间:2011-11-13 10:03:33

标签: algorithm computer-science heap binary-tree theory

我对算法理论很感兴趣(来自Cormen) 本章中有一个关于二进制尝试的练习,请求:

  

可以使用min-heap属性打印出n节点的密钥   在O(n)时间排序的树?展示如何,或解释原因。

我认为是可能的。
在最小堆中,节点中的元素小于其子节点 因此堆的根始终是所有n个元素中较小的元素,并且根的左子节点小于左子树中的所有元素,并且根的右子节点小于所有元素中的所有元素。正确的子树等。

因此,如果我们继续使用root,打印它,然后使用较小的子进程更新root,我们保留min-heap属性,并按排序顺序打印。 (我在考虑一个不基于数组的最小堆)。

所以这可以在O(n)时间内完成,因为更新根,我们只是比较2个子节点并将根指针更新为2中的较小者。

但我在解决方案中检查了这一点:
Cormen Supplement Solutions

1)它谈论max-sheaps 2)它说它不能在O(n)时间内完成:

  

在堆中,节点的密钥是其子密钥。在二进制文件中   搜索树,节点的键是它的左子键,但是它的右键   孩子的钥匙。堆属性,与binary-searth-tree不同   属性,不帮助按排序顺序打印节点,因为它   不会告诉节点的哪个子树包含要打印的元素   在该节点之前。在堆中,最小元素小于节点   可以在任何子树中。请注意,如果堆属性可以   用于在O(n)时间内按排序顺序打印键,我们将有一个   O(n)-time算法用于排序,因为只构建堆   准时。但我们知道(第8章)必须进行比较   (n lg n)时间。

从我的观点来看,我可以理解使用max-heap,无法在O(n)中打印它们。
但是,根据我解释的推理,是不是可以使用min-heap属性来做呢? 另外,为什么解决方案会忽略min-heap。是拼写错误还是错误?

我在这里误会了什么吗?

3 个答案:

答案 0 :(得分:8)

首先,在讨论中遗漏min-sheaps可能不是一个错字,如果我们讨论的是最小堆或最大堆(比较器刚刚反转),这并不重要。

仅提取根然后替换其两个子节点中较小的一个的问题是,不保证左子节点小于右子树中的所有节点(反之亦然)。考虑以下堆

        1
       / \
      4   6
     /\   /\
    5  8 9  7

打印1后,您必须重新合并,也就是说您提取1并将其替换为最后一行中的最后一个元素,在本例中为7。然后,只要您需要将堆返回到正确的状态

,就可以切换
take away root and last node to root
        7
       / \
      4   6
     /\   /
    5  8 9

swap
        4
       / \
      7   6
     /\   /
    5  8 9

swap
        4
       / \
      5   6
     /\   /
    7  8 9

所有这些交换都需要花费log n时间。

如果您改为使用4替换根节点,您仍然必须通过左分支重新定义结构,从而增加提取根节点的线性成本的成本。如果堆看起来像这样

        1
       / \
      4   9
     /\   /\
    5  6 11 15
   /\
  8  7

我看到形成解决方案的页面

1)Wikipedia: binary heap

2)Wolfram MathWorld: heap这里的堆特别有助于理解为什么它不是线性操作。

答案 1 :(得分:2)

考虑最小堆的数组表示。您在根目录中拥有最小值。提取根并将其替换为最后一个数组元素,即最后一个叶子位于叶子的最低不完整“行”中。执行MIN-HEAPIFY操作(与CLRS MAX-HEAPIFY相同,但反向比较)。这需要O(log n),结果是根的第二个最小元素。重复直到堆为空。这给出了一个排序的序列。

因此算法的复杂性

log (n) + log (n-1) + log (n-2) + ... + 1 <= n*log n

即。 O(n * log n)

这是预期的,否则,我们会得到一个基于比较的排序,其复杂度小于O(nlogn),这是不可能的。

答案 2 :(得分:0)

我猜你的想法基本上是一堆(考虑一个最小堆),它的根是最小的元素。现在对于第二个最小元素,左右子树都具有最小堆属性,因此我们可以简单地比较左右子节点以找到第二个最小元素。同样可以继续....所以它的O(n)? 你忽略的一件事是,每个级别要比较的元素数量也在增加...... 最小的 - 0比较(根是最小的) 为第二个最小 - 1比较(左树的根或右树的根) 让我们说左树根小于右树根节点。 为第三小 - 2比较。 (右树的根或左子树的两个子中的任一个)。 在计算渐近时间复杂度时,您忽略了这个比较部分。