【问题标题】:Print a tree in sorted order using heap properties (Cormen)使用堆属性按排序顺序打印树 (Cormen)
【发布时间】:2011-12-27 23:48:32
【问题描述】:

我正在刷新算法理论(来自 Cormen)。
在二进制尝试的章节中有一个练习要求:

最小堆属性可以用来打印n节点的键吗 在 O(n) 时间内按排序顺序排列的树?展示如何做,或解释为什么不这样做。

我认为是的,这是可能的。
在最小堆中,节点中的元素小于其两个子节点。
所以堆的根总是所有n个元素中较小的元素,根的左孩子小于左子树中的所有元素,根的右孩子小于堆中所有元素右子树等。

所以如果我们继续提取根,打印它,然后用它的较小的孩子更新根,我们保留最小堆属性并按排序顺序打印。 (我正在考虑一个不基于数组的最小堆)。

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

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

而且 1)它谈到了最大堆 2)它说它不能在 O(n) 时间内完成:

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

从我的角度来看,我可以理解使用最大堆,不可能在 O(n) 中打印它们。
但是根据我解释的原因,是否可以使用 min-heap 属性来做到这一点?
还有为什么解决方案会忽略最小堆。是错字还是错误?

我在这里误解了什么吗?

【问题讨论】:

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


    【解决方案1】:

    首先,讨论中省略最小堆可能不是错字,我们谈论的是最小堆还是最大堆并不重要(比较器只是颠倒了)。

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

            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 这里的堆对于理解为什么它不是线性操作特别有帮助。

    【讨论】:

    • 那么最小可能的渐近时间是 O (n * log (n))?
    【解决方案2】:

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

    因此算法的复杂度为

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

    即O(n*log n)

    这是意料之中的,否则,我们将获得一个复杂度小于 O(nlogn) 的基于比较的排序,这是不可能的。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-01
        相关资源
        最近更新 更多