Compare trees using canonization approach suggested by @mcdowella. The difference is that my approach doesn't require O(N)
additional memory w.r.t number of nodes in the tree:
# in Python
from collections import namedtuple
from itertools import chain
# Tree is either None or a tuple of its value and left, right trees
Tree = namedtuple('Tree', 'value left right')
def canonorder(a, b):
"""Sort nodes a, b by their values.
`None` goes to the left
"""
if (a and b and a.value > b.value) or b is None:
a, b = b, a # swap
return a, b
def canonwalk(tree, canonorder=canonorder):
"""Yield all tree nodes in a canonical order.
Bottom-up, smaller children first, None is the smallest
"""
if tree is not None:
children = tree[1:]
if all(t is None for t in children): return # cut None leaves
children = canonorder(*children)
for child in chain(*map(canonwalk, children)):
yield child
yield tree
canonwalk()
requires O(N*M)
steps and O(log(N)*M)
memory to yield all nodes in a tree, where N
is total number of nodes, M
number of children each node has (it is 2 for binary trees).
canonorder()
could be easily generalized for any node representation and any number of children. canonwalk()
requires only that a tree can access its immediate children as a sequence.
The comparison function that calls canonwalk()
:
from itertools import imap, izip_longest
unset = object()
def cmptree(*trees):
unequal = False # allow root nodes to be unequal
# traverse in parallel all trees under comparison
for nodes in izip_longest(*imap(canonwalk, trees), fillvalue=unset):
if unequal:
return False # children nodes are not equal
if any(t is unset for t in nodes):
return False # different number of nodes
if all(t is not None for t in nodes):
unequal = any(nodes[-1].value != t.value for t in nodes)
else: # some are None
unequal = any(t is not None for t in nodes)
return True # equal
Example
5 6
/ \ / \ they are equal.
1 2 2 1
/ \ / /
3 4 4 3
tree1 = Tree(5,
Tree(1,
Tree(3, None,None), None),
Tree(2,
None, Tree(4, None, None)))
tree2 = Tree(6,
Tree(2, Tree(4, None, None), None),
Tree(1, Tree(3, None, None), None))
print cmptree(tree1, tree2)
Output
True