我正在寻找一种顺序算法(如果存在的话),以
您可以这样做:进行两次同步的中序遍历,以便比较两个BST的第
O(n)
的时间复杂度和O(1)
的内存使用量来测试两个二叉搜索树是否具有相同的键,递归是允许的。您可以这样做:进行两次同步的中序遍历,以便比较两个BST的第
ith
个元素。O(n)
的时间复杂度和O(1)
的内存使用量来测试两个二叉搜索树是否具有相同的键,递归是允许的。ith
个元素。yield
编写BST即可。这将创建一个保留少量状态的生成器。(根据数据结构和算法,这种情况下应该是O(1)
或O(log(n))
。而正如我们所知,在现实世界中,log(n)
是一个常数。尽管对于像Google这样的公司来说,它是一个稍微大一些的常数……)yield
的语言中,你需要安排创建一个带有搜索状态的对象,并使用可以调用的方法返回当前元素(或告诉你已完成),然后继续到下一个元素。保存状态并在进入方法时恢复它确实很麻烦,但在幕后,这就是Python为您完成的工作。class Inorder
{
Node * curr = nullptr; // node currentrly beeing visited
Stack<Node*> s; // stack for storing the ancestors
Node * advance_to_min(Node * r) // compute the leftmost node in r and stack the path
{
while (LLINK(r) != Node::NullPtr)
{
s.push(r);
r = LLINK(r);
}
return r;
}
public:
Inorder(Node * root) : curr(advance_to_min(root)) {}
bool has_curr() const noexcept { return curr != nullptr; }
Node * get_curr() const { return curr; }
void next() // get the next node inorder sense
{
curr = RLINK(curr);
if (curr != nullptr)
{
curr = advance_to_min(curr);
return;
}
if (s.is_empty())
curr = nullptr;
else
curr = s.pop();
}
};
LLINK
,RLINK
和KEY
分别是访问左链接、右链接和键的访问器。bool same_keys(Node * t1, Node * t2)
{
Inorder it1(t1), it2(t2);
for (; it1.has_curr() and it2.has_curr(); it1.next(), it2.next())
if (KEY(it1.get_curr()) != KEY(it2.get_curr()))
return false;
return not (it1.has_curr() or it2.has_curr());
}
O(1)
的方法。这个方法将基于“线程”,暂时将正确的空指针放在祖先中以便恢复。在现代架构中,您可以使用指针的最低有效位来标记它是否为线程; 因此您不需要额外的空间。O(log(n))
的解决方案。之后,我很快意识到我的方法可以修改为迭代而无需堆栈。因此,在接下来的内容中,我将提供一种O(1)
空间复杂度的解决方案,该解决方案使用“线程”存储按顺序意义上的后继节点。Inorder
类中添加以下辅助方法:static bool is_thread(Node * p)
{
return (Node*) (((long) p) & 1);
}
static Node * make_thread(Node * p)
{
return (Node*) (((long)p) | 1);
}
static Node * make_pointer(Node * p)
{
return (Node*) (((long) p) & -2);
}
1
的指针是无效的。因此,需要使用is_thread()
来测试指针是否为线程。当然,堆栈并不是必需的。advance_to_min()
方法:static Node * advance_to_min(Node * r) // find the leftmost node respect to r
{
Node * p = r;
while (LLINK(p) != nullptr)
{
p = LLINK(p);
Node * q = p; // searches predecessor of r inorder
while (RLINK(q) != nullptr)
q = RLINK(q);
// q is the predecessor of r
RLINK(q) = make_thread(r); // here is put the thread
r = p;
}
return r;
}
方法next()
必须重构以将线程恢复为null指针。可以通过以下方式完成:
void next() // get the next node inorder sense
{
if (is_thread(RLINK(curr)))
{
Node * p = curr;
curr = make_pointer(RLINK(p));
RLINK(p) = nullptr; // here is deleted the thread
return;
}
curr = RLINK(curr);
if (curr != nullptr)
curr = advance_to_min(curr);
}
班级的其余部分相同,完成后!您拥有一种在空间上检查两个BST是否具有相同密钥的O(1)
方法。
当然,完全遍历树非常重要,否则,树将处于不一致状态。如果树不同,则肯定会发生这种情况。我给您留下了一个清理程序,确保两棵树都清除了它们的线程。