当前位置: 首页 > 知识库问答 >
问题:

给定堆的预序遍历,构造堆

罗祺
2023-03-14

在互联网上看到这个问题并试图解决它。我可以解决堆是严格二叉树的情况(通过重复分区前序遍历),但当堆只是一棵完整的二叉树时,我无法找出算法。

例如,如果 1, 2, 3, 4, 5, 6, 7 是最小堆的预序遍历,

堆的大小为7

1 是堆中的第一个元素(考虑到堆表示为数组)

下一个(大小-1)/2元素将位于1的左子树中

2、3、4 将位于 1 的左侧子树中

最后一个(大小 - 1)/ 2 个元素将位于 1 的右子树中

5、6、7 将位于 1 的右侧子树中

可以通过递归地应用这个逻辑来构造完整的堆。

该解决方案将适用于此类堆是严格二叉树的情况

       1
    2     3
  4   5  6  7

但显然,这在非叶元素有一个子元素或没有子元素的堆的情况下不起作用。例如,

          1                1
       2     3         2     3
     4   5  6        4     5

我想不出任何干净的算法可以做到这一点。任何解决方案/建议都会很有帮助。

共有3个答案

淳于博文
2023-03-14

将前序遍历转换为标准堆表示应该很简单。预订单访问自己,左,右。对于基于1的数组中的堆,节点N的左子节点位于2N,右子节点位于2N-1。这直接导致了这个算法:

def constructHeap(preorder, pidx, heap, hidx)  
    return pidx if (hidx>=heap.size)         #no more children
    heap[hidx] = preorder[pidx]              #self
    pidx = constructHeap(preorder, pidx+1, heap, hidx*2) #left
    return constructHeap(preorder, pidx, heap, hidx*2+1) #right
end

preorder = [1,2,3,4,5,6,7]
heap = Array.new(preorder.size+1)            #create storage
constructHeap(preorder, 0, heap, 1)
puts heap
云隐水
2023-03-14

你试图通过应用给你的两条信息中的一条来解决这个问题。

你掌握的信息是:

  • 你有一个二叉树
  • 对所述树进行堆排序

现在,虽然您通常需要两次二进制遍历才能获得第三次遍历(前、后,依次为三次),但这里有一个额外的信息:二进制树是一个堆。

二叉堆总是一棵完整的二叉树。完整的二叉树是这样一棵二叉树,树的所有级别都满了,也许除了最后一个级别,它总是从左到右填充。换句话说,堆不可能有一个小于两个子节点的内部节点。

高晋
2023-03-14

看几个例子会让这变得更容易。随着孩子数量的增加,我们看到以下模式:

    < li >如果子代数量为2,则拆分为:(1,1) < li >如果子代数为3,则拆分为:(2,1)

继续这样,当孩子的数量在2到6之间时,我们会得到以下分割:

(1, 1), (2, 1), (3, 1), (3, 2), (3, 3)

当孩子的数量在6到14之间时,我们得到:

(3, 3), (4, 3), (5, 3), (6, 3), (7, 3), (7,4), (7, 5), (7, 6), (7, 7)

所以当孩子的数量在(2^k-2)和(2^{k 1}-2)之间时,我们得到:

 either a split of the form (2^{k-1}-1+l, 2^{k-1}-1) where   0 <= l <= 2^{k-1} or
                            (2^k-1, 2^{k-1}-1+l)     where   0 <= l <= 2^{k-1}

逻辑是找到一个k,这样(2^k-2)

Let l = childCount - (2^k-2)
If  l <= 2^{k-1} 
    split with (2^{k-1}-1+l, remaining)
Else 
    split with (2^k-1, remaining)
 类似资料:
  • 我知道有一些方法可以从预序遍历(作为数组)构造树。更常见的问题是构造它,给定顺序和顺序遍历。在这种情况下,虽然inorder遍历是多余的,但它肯定会使事情变得更容易。有谁能给我一个关于后命令遍历的想法吗?迭代和递归都是需要的。 我试着用堆栈迭代地做,但根本无法得到正确的逻辑,所以得到了一个可怕的乱七八糟的树。递归也是如此。

  • 我已经实现了一种方法来对一棵树(不是二叉树)进行预排序遍历。此树的每个父节点都有一个子节点数组,因此我使用的方法是: 将子节点链接到父节点“tnAA”的示例 但它只输出根节点,这种方法有什么问题? 解决方案:将children数组链接到每个parent:tnaa . setchildern(AA _ childern);

  • 我仍然是Java的初学者。我刚刚学习了二分搜索法树和前序遍历的概念,以及如何使用递归来实现二叉树的前序遍历。大概是这样的: 但是,如何为 N 元树实现相同的递归模型呢?其中每个节点的子节点数不一定为 2?因为.left和.right将不适用,不是吗?如果需要提供更多代码,请lmk,谢谢。

  • 下面是将二叉查找树的前序遍历转换为原始树的代码。 下面的代码采用整数数组,表示二进制搜索树的预序遍历。返回构造树的根。 来源:http://www . geeks forgeeks . org/construct-BST-from-given-preorder-traversal-set-2/ 我无法理解此代码。有人能帮我理解以下内容吗 > 在任何给定的迭代中,堆栈中存储的值与指出的当前值相关 从

  • 我需要执行一个三元树的预购遍历。我很熟悉二叉树上的这种遍历,比如: 它按根、左、右顺序遍历。我很困惑如何在添加了中间子节点的情况下做到这一点。如果有人能解释这个,那就太好了。谢谢

  • 本文向大家介绍用C ++中的给定操作构造最大堆栈的程序,包括了用C ++中的给定操作构造最大堆栈的程序的使用技巧和注意事项,需要的朋友参考一下 假设我们要制作一个最大的堆栈,它支持以下操作- MaxStk() 这将构造一个最大堆栈的新实例 push(val) 将val插入堆栈 top() 从堆栈中获取最高的元素 max() 从堆栈中获取最大元素 pop() 从堆栈中删除并返回最上面的元素 popm