我在一次采访中被问到这个问题。给出了两个 BST(二叉搜索树)。我们需要以这样一种方式遍历两棵树,以使合并的排序输出成为结果。约束是我们不能像数组那样使用额外的内存。我建议对两棵树进行组合的中序遍历。该方法是正确的,但我陷入了递归,无法编写代码。
注意:我们不能将两棵树合并为一棵。
请有人指导我朝这个方向发展。提前致谢。
我在一次采访中被问到这个问题。给出了两个 BST(二叉搜索树)。我们需要以这样一种方式遍历两棵树,以使合并的排序输出成为结果。约束是我们不能像数组那样使用额外的内存。我建议对两棵树进行组合的中序遍历。该方法是正确的,但我陷入了递归,无法编写代码。
注意:我们不能将两棵树合并为一棵。
请有人指导我朝这个方向发展。提前致谢。
“最简单”的方法是:
您可以在线找到此步骤的算法。
我认为对树进行并行遍历是不可能的。您将需要其他信息,例如访问标志来消除已访问的左子树,即使这样您也会遇到其他问题。
如果有人知道并行遍历如何实现这一点,我将很高兴知道。
print $ merge (inorder treeA) (inorder treeB)
有什么问题?
(注意,上面是实际运行并执行任务的实际 Haskell 代码)。inorder
用递归实现是微不足道的。 merge
是一个近乎标准的功能,合并它的两个参数有序(非递减)列表,生成有序输出列表,保留重复项。
由于惰性求值和垃圾收集,实际上并没有创建列表 - 每棵树最多保留一个生成的元素,并在生成下一个元素时丢弃,实际上为遍历创建迭代器(每个都有自己的内部状态)。
这是解决方案(如果您的语言不支持上述内容,或等效yield
机制,或 Scheme 的显式延续,它允许在每个控制堆栈深处的两个上下文之间切换(因此可以并行进行“两个递归”,如上)):
他们没有说时间复杂度,所以我们可以对第一棵树进行递归遍历,并为第一棵树的每个节点重新遍历第二棵树——同时在第一棵树上保存previous
价值。因此,我们在第一棵树上有两个连续的值,并在它们之间打印第二棵树的所有值,使用新的递归遍历,从第二棵树的顶部重新开始,为第一棵树的每对新值。
我假设树中没有指向父节点或下一个节点的链接,否则这将很容易:您只需按照这些链接迭代您的树并编写您的合并算法,就像您对链表一样。
如果您没有下一个或父链接,则无法编写简单的递归。您将需要两个“递归”堆栈。您可以实现以下结构,它允许您分别迭代每个树。
class Iterator
{
stack<Node> st;
int item(){
return st.top().item();
}
void advance(){
if (st.top().right != null)
st.push(st.top().right);
// Go as far left as possible
while (st.top().left != null) st.push(st.top().left);
else {
int x = st.top().item();
// we pop until we see a node with a higher value
while(st.top().item()<=x) st.pop();
}
}
};
然后使用其中两个迭代器编写合并算法。
您将需要 O(log n) 空间,但渐近地说,这只不过是任何递归迭代。