这回答了最初措辞的问题,即在相同结构和元素的意义上树的身份之后。
比较按顺序(或任何其他)顺序将不起作用:不同的树具有相同的遍历。例如,树木
[来源]
有相同的中序遍历a,b,c,d,e
。您可以使用两个(不同的)遍历并分别检查它们是否相同。
然而,经典的解决方案是递归算法:
equal Leaf(x) Leaf(y) => x == y
| equal Node(x,l1,r1) Node(y,l2,r2) => x == y && equal(l1,l2) && equal(r1,r2)
| equal _ _ => false;
它同时在两棵树上执行树遍历,并花费时间 Θ(n),n 是各自节点数的最大值。
关于更新的问题,检查按元素相等的顺序遍历就足够了。请注意,根据定义,BST 的中序遍历是存储元素的排序列表,因此这种方法是正确的。以递归形式,这是算法:
inorder Leaf(x) = [x]
| inorder Node(x,l,r) = (inorder l) ++ [x] ++ (inorder r);
equal [] [] = true
| equal x1::r1 x2::r2 = x1 == x2 && (equal r1 r2)
| equal _ _ = false;
sameElems t1 t2 = let
e1 = inorder t1
e2 = inorder t2
in
equal e1 e2
end;
如果列表连接可以在时间 O(1) 内完成,则在时间 Θ(n) 和空间 Θ(n) 中运行;迭代解决方案当然同样好,并且可能具有更好的常数。
如果您想在 o(n) 时间内执行此检查,您甚至无法查看每个元素。一般来说,两棵树都包含成对的不同元素,因此您不能利用任何范围,因此我每个一般的元素相等检查都需要时间 Ω(n)(假设一个更快的算法并构造两棵它失败的树)。
不过,空间可以做得比 O(n) 更好。如果您巧妙地按顺序实现¹,您只需要 O(1) 额外空间(指向当前元素的指针,一些管理计数器/标志)。
- 请注意,此算法会暂时破坏树,因此不适合并发设置。