Algorithm 遍历以打印使用递归排序的两个BST。不允许使用像数组这样的额外内存
我在一次采访中被问到这个问题。给出了两个BST(二进制搜索树)。我们需要以这样一种方式遍历这两棵树,结果就是合并的排序输出。限制是我们不能像数组那样使用额外的内存。我建议按顺序组合遍历这两棵树。这种方法是正确的,但我陷入了递归,无法编写代码 注意:我们不能将这两棵树合并为一棵 请有人给我引路。 提前感谢。最简单的方法是:Algorithm 遍历以打印使用递归排序的两个BST。不允许使用像数组这样的额外内存,algorithm,data-structures,tree,binary-search-tree,tree-traversal,Algorithm,Data Structures,Tree,Binary Search Tree,Tree Traversal,我在一次采访中被问到这个问题。给出了两个BST(二进制搜索树)。我们需要以这样一种方式遍历这两棵树,结果就是合并的排序输出。限制是我们不能像数组那样使用额外的内存。我建议按顺序组合遍历这两棵树。这种方法是正确的,但我陷入了递归,无法编写代码 注意:我们不能将这两棵树合并为一棵 请有人给我引路。 提前感谢。最简单的方法是: 将树A转换为双链接列表(已排序) 将树B转换为双链接列表(已排序) 遍历排序列表打印最小值(简单) 将列表A转换为树A 将列表B转换为树B 您可以在线找到此步骤的算法。 我认为
我认为并行遍历树是不可能的。您需要额外的信息,例如访问标志,以便在访问时消除左侧子树,即使这样,您也会遇到其他问题。
如果有人知道如何通过并行遍历实现这一点,我很乐意知道 我假设树中没有指向父节点或下一个节点的链接,否则 这将非常简单:您只需按照这些链接迭代您的树,并编写合并算法,就像编写链表一样 如果没有下一个链接或父链接,则无法编写简单的递归。您将需要两个“递归”堆栈。 您可以实现以下结构,它允许您分别迭代每个树
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();
}
}
};
类迭代器
{
斯塔克街;
int项(){
返回st.top()项();
}
作废预付款(){
if(st.top().right!=null)
st.push(st.top().右侧);
//尽量向左走
while(st.top().left!=null)st.push(st.top().left);
否则{
int x=st.top().item();
//我们弹出,直到看到一个值更高的节点
while(st.top().item())
有什么问题吗
(注意,上面是实际运行并执行任务的Haskell代码)。inoorder
对于递归来说是微不足道的。merge
是一个近乎标准的功能,它将两个参数有序(非递减)列表合并,生成一个有序输出列表,保留重复项
由于延迟求值和垃圾收集,列表实际上并没有被创建——每个树最多只保留一个生成的元素,并且在生成下一个元素时被丢弃,实际上为遍历创建迭代器(每个元素都有自己的内部状态)
这里是解决方案(如果您的语言不支持上述,或等效的
屈服
机制,或Scheme的显式延续,允许在每个控制堆栈的深处的两个上下文之间切换(从而使“两个递归”并行成为可能,如上所述)):
它们没有说明任何时间复杂性,因此我们可以对第一棵树进行递归遍历,并为第一棵树的每个节点重新遍历第二棵树,同时在第1棵树上保存
previous
值。因此,我们在第1棵树上有两个连续的值,并在它们之间打印第二棵树的所有值,使用新的递归遍历,重新开始对于第一棵树中的每一对新值,从第二棵树的顶部取g。除了这两棵树之外,还需要一个比较运算符(或函数)合并树。您需要合并树或遍历以打印两个已排序树的元素吗?@Jim:谢谢您的回答。我需要遍历以打印两个已排序树的元素。@Jim:我已更新了问题标题。希望现在更清楚。@user1225752:发布您建议但无法合作的算法方法对于不认识Haskell的我来说,deVery很有趣。但是在一个采访问题中,我不确定这是采访所期望的。@Cratylus如果允许使用Python,这基本上意味着在递归遍历函数中只使用yield
而不是return
,仅此而已。可能你是对的。我不知道w脚本语言,所以也许你可以在Python职位上侥幸逃脱。@Cratylus这个问题上没有特定的语言标记,对吗?如果你的语言中没有yield
,你就必须自己做一些具体化(即,在遍历树时,将递归的隐式调用堆栈转换为指向树的显式指针堆栈,如其他答案所示)或者使用标准迭代器,如果是C++,那么你就回到我原来的注释。你自己用一行代码实现你所写的东西。OP特别要求一个没有额外空间的解决方案。树的任何递归都使用O(log n)。空间。根本没有可能的解决方案使用恒定的额外空间。线性时间运算的对数空间不是什么大问题。我已经用这个解决方案给出了我的答案。你怎么想?顺便问一下,你的解决方案是否可以接受,取决于这个BST中关于Leaf
表示的问题:是叶子被表示吗通过节点
和两个空的子节点指针,就可以了,你可以将它们重新用于DL链接。但是如果叶子是由一个特殊的无链接叶子
结构表示的,那么你必须为叶子的双链接列表中的链接分配新的内存。@WillNess:我不确定并行t的算法是什么raversal.从我的观点来看,并行遍历两棵树是行不通的,因为你不知道你是否已经访问过一棵子树。我已经澄清了我的答案。请回答::)谢谢。这里我提出了另一个要求。对于你的问题:每次遍历都是单独完成的,一个不知道另一个
print $ merge (inorder treeA) (inorder treeB)