使用@mcdowella建议的规范化方法来比较树。不同之处在于,我的方法不需要与树中节点数量成比例的O(N)
额外内存:
from collections import namedtuple
from itertools import chain
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
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
children = canonorder(*children)
for child in chain(*map(canonwalk, children)):
yield child
yield tree
canonwalk()
需要执行O(N*M)
步骤和使用O(log(N)*M)
内存来返回树中的所有节点,其中N
是节点总数,M
是每个节点拥有的子节点数量(对于二叉树,它为2)。
canonorder()
可以轻松地推广到任何节点表示和任意子节点数量。 canonwalk()
仅需要一棵树可以访问其直接子节点作为序列。
调用canonwalk()
的比较函数:
from itertools import imap, izip_longest
unset = object()
def cmptree(*trees):
unequal = False
for nodes in izip_longest(*imap(canonwalk, trees), fillvalue=unset):
if unequal:
return False
if any(t is unset for t in nodes):
return False
if all(t is not None for t in nodes):
unequal = any(nodes[-1].value != t.value for t in nodes)
else:
unequal = any(t is not None for t in nodes)
return True
例子
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)
输出
True
你给的链接
是重复的,在我的问题中,一棵树的左/右子节点可以交换
,然后与另一棵树相等进行比较。 - Alcott