在互联网的某个地方看到这个问题并尝试解决它。我可以解决堆是严格二叉树的情况(通过反复分区前序遍历)但当堆只是一个完整的二叉树时无法找出算法。
例如,如果1, 2, 3, 4, 5, 6, 7
是最小堆的前序遍历,
堆的大小为7
1
是堆中的第一个元素(考虑到,堆表示为数组)
下一个(size - 1) / 2
元素将位于1
2, 3, 4
将位于1
最后(size - 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
我想不出任何可以做同样事情的干净算法。任何解决方案/建议都会有所帮助。
答案 0 :(得分:2)
查看一些示例将使这更容易。随着孩子数量的增加,我们看到以下模式:
当孩子的数量在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)&lt; = childCount&lt; =(2 ^ {k + 1} -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)
答案 1 :(得分:0)
你试图通过仅应用给你的两条信息中的一条来解决这个问题。
您拥有的信息是:
现在,虽然这是真的,你通常需要两个二进制遍历来获得第三个(前,后,有序为三),这里,你有一个额外的信息:二叉树是heap 。
二进制堆总是一个完整的二叉树。 完整二叉树是这样的二叉树,其中树的所有级别都已满,除了最后一级,它总是从左到右填充。换句话说,堆不可能有一个内部节点少于两个子节点。
答案 2 :(得分:0)
将预订遍历转换为标准堆表示应该很简单。预购自我,左,右。对于基于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
答案 3 :(得分:0)
使用前序遍历,以排序顺序生成其元素的堆就是这样 它由矢量(1,2,5,3,4,6,7)表示。没有堆 inorder遍历以排序顺序生成密钥。这是因为 在一个堆中,父级总是少于它的所有子级或大于它的所有子级 儿童。由(7,3,6,1,2,4,5)表示的堆是其中一个的示例 在后序遍历期间按排序顺序生成其键。