如何合并满足堆顺序的两棵树?
Posted
技术标签:
【中文标题】如何合并满足堆顺序的两棵树?【英文标题】:How can I merge two trees which satisfy the heap order? 【发布时间】:2021-12-26 01:19:18 【问题描述】:是否可以在时间 O(m+n+1) 内合并两棵满足堆顺序的树?而 m 和 n 是输入树的高度。
Example
Input:
10 8
\
9
Output: (Can be any one of them)
10 10 10 10
\ / \ / \ /
9 9 8 8 9 9
/ /
8 8
【问题讨论】:
请注意,并非所有输入/输出树都是堆。我想这是故意的。 是的,树不都是堆,但值满足堆顺序属性 【参考方案1】:是的,这可以在 O(? + ?) 内完成,条件是允许输出树与输入树共享节点。
算法
给定两个根节点a
和b
:
-
如果
a
和b
都为null,则返回null(基本情况)
如果其中一个为空,则选择另一个。否则选择具有较大值的节点。假设a
是该选定节点。
使用与a
相同的值创建一个新节点x
。
执行递归合并a.left
和b
。将合并结果附加到x.left
将未更改的a.right
引用分配给x.right
返回x
由于我们在递归的每一级都降低了主题中的一棵树的高度,因此递归深度最多为两棵输入树的高度之和,由此遵循给定的时间复杂度。
在步骤 3 中合并 a.left
或 a.right
的选择是任意的。你可以随意设置。
示例实现
这是一个粗略的 javascript 实现。当你运行这个 sn-p 时,会合并以下两棵树:
10 8
/ \ / \
4 9 7 6
/ \ / \ \
3 1 2 5 0
class Node
constructor(value, left=null, right=null)
this.value = value;
this.left = left;
this.right = right;
toString()
return (this.right ? this.right.toString().replace(/^/gm, " ") + "\n" : "")
+ this.value
+ (this.left ? "\n" + this.left.toString().replace(/^/gm, " ") : "");
function merge(a, b)
if (a == null && b == null) return null;
if (a == null || (b != null && b.value > a.value))
return new Node(b.value, merge(a, b.left), b.right);
return new Node(a.value, a.left, merge(b, a.right));
// Example
let a = new Node(10,
new Node(4,
new Node(3),
new Node(1)
),
new Node(9,
new Node(2),
new Node(5)
)
);
let b = new Node(8,
new Node(7),
new Node(6,
null,
new Node(0)
)
);
console.log("a:");
console.log(a.toString());
console.log("b:");
console.log(b.toString());
console.log("merged:");
console.log(merge(a, b).toString());
这个 sn-p 有一个非常基本的打印功能——它打印旋转 90° 且根在左侧的树。没有连接节点的线(你必须想象它们),只是缩进。
该示例将生成此树:
10
/ \
4 9
/ \ / \
3 1 8 5
/ \
7 6
/ \
2 0
注意:您提到了 O(? + ? + 1),但那个附加常数无关紧要:O(? + ? + 1) = O(? + ?)。
【讨论】:
这看起来是一个很好的解决方案,但请注意,OP 将 m 和 n 定义为输入树的*高度,而不是它们的节点数大小,我认为这就是为什么它们正在询问 O(n+m) 是否可能(因为 O(N+M) 与 N 和 M 是节点数是微不足道的 - 只需将两棵树中的所有节点放在一个数组中并构建一个新堆)。但无论如何,你展示了他们的要求! 哦,是的,错过了!相应地更新了我对 ? 和 ? 的使用。以上是关于如何合并满足堆顺序的两棵树?的主要内容,如果未能解决你的问题,请参考以下文章