我仍然习惯于数据结构,我很熟悉以各种方式遍历二叉树,但我现在提出的情况是我有一个普通的二叉树,由只知道的节点构成拥有data
,left
和right
属性。
但我希望将其转换为“更智能”的二叉树。该树将知道其父节点,其总子节点以及它所在的总树中的级别。
我真的很挣扎着如何将一个“笨”树转移到更智能的版本中。我的第一直觉是递归遍历,但我不确定我如何能够区分父级和级别。
答案 0 :(得分:1)
使用常规递归方法遍历原始树,将旧树复制到新树。
由于您要向节点添加新属性,我认为您需要构建包含新属性字段的新节点。
定义递归函数以复制以给定节点为根的(子)树。它需要作为输入的深度和父母。 (当然,父对象必须是新树中的父对象。)让它返回新(子)树的根。
function copy_node (old_node, new_parent, depth) -> returns new_node {
new_node = new node
new_node.data = old_root.data // whatever that data might be
new_node.depth = depth
new_node.parent = parent
new_node.left = copy_node (old_node.left, new_node, depth + 1)
new_node.right = copy_node (old_node.right, new_node, depth + 1)
return new_node }
使用
复制整个树new_tree = copy_node (old_tree, nil, 0)
如果您使用的语言可以将字段添加到现有对象中,那么您甚至不必进行额外复制:
function adorn_node (node, parent, depth) {
node.parent = parent
node.depth = depth
adorn_node (node.left, node, depth + 1)
adorn_node (node.right, node, depth + 1) }
用
开始滚球adorn_node (root, nil, 0)
话虽如此,您可能会发现大多数二叉树实现都不包含这些额外字段的原因非常充分。在你希望在树上执行的许多不同操作中维护它们需要做很多工作。 深度,尤其是当您需要重新平衡树时,很难保持正确。
田地通常不会给你买任何东西。大多数使用递归函数在树上运行的算法都可以使用递归函数,正如您从上面的示例中看到的那样,重新计算父和深度非常容易当你走在树上的时候。它们不需要存储在节点本身中。
树平衡通常需要知道左右子树高度的差异。 ("深度"是到根的距离;"高度"是到子树中最远的叶子节点的距离。)高度并不那么容易从根部开始计算,但幸运的是,您通常只对哪个子树具有最大高度感兴趣,并且为此它通常仅足以存储每个节点中的值为-1,0,+。