在bst的常规递归代码中,树的左右元素在每个递归调用中设置(In t.left =和t.right =)。 这不是再次构建树吗?
存储对前一个节点的引用然后根据值添加新节点向左或向右或者我在这里遗漏了什么不是更好吗?谢谢!
public Elem insert (Elem t, int toInsert)
{
if (t == null)
return new Elem(toInsert,null,null);
else {
if (toInsert < t.value)
t.left = insert(t.left, toInsert);
else
t.right = insert(t.right,toInsert);
return t;
}
}
要插入一个新元素,代码会将每个元素或子树分配为左右。我的问题是,这不是一个开销吗?要在链表中插入,我们只需导航到最后一个节点并在那里执行链接。在这里,我们在每次插入时执行整棵树的链接。有没有其他方法可以避免这种情况?
答案 0 :(得分:2)
它不是重建树,而是通过递归调用遍历树,到达树内的叶子(空点),以便可以在那里添加新元素。例如,考虑一下这个BST,
6
/ \
4 8
让我们说你叫insert(element 6, 5)
(*
表示我们在穿越三个地方时的位置。)
*6
/ \
4 8
该方法将跳过第一个if语句,并继续检查方法参数中当前元素的值5。 5小于6,因此执行以下行t.left = insert(t.left, toInsert)
(将其视为elem6.left = insert(元素4,5))。
6
/ \
*4 8
现在我们正在进行insert
的第二次方法调用,这次是insert(element 4, 5)
。再次跳过第一个if语句,将4与5进行比较.5大于4,因此执行以下行t.right = insert(t.right,toInsert)
(将此视为elem4.right = insert(null,5))
6
/ \
4 8
\
*
现在我们正在进行'insert'的第三个方法调用,这次调用insert(null, 5)
,因此实际执行了第一个if语句,并返回了一个类型为Elem
的新对象。 Aka执行此行,return new Elem(toInsert,null,null)
(将此视为返回新的Elem(5,null,null))。
6
/ \
4 8
\
*
此时调用堆栈在增长到三次调用后开始减少。回到这一行t.right = insert(t.right,toInsert)
,而不是insert(t.right, toInsert)
,它现在是new Elem(5, null, null)
。因此,元素5已分配给元素4的右侧。然后,执行方法的其余部分,以return t
结束。在这种情况下,t
是通过方法传递的Elem
,元素4。
6
/ \
*4 8
\
5
回到这一行(沿调用堆栈向下),t.left = insert(t.left, toInsert)
,而不是insert(t.left, toInsert)
,它现在是元素4.所以元素6的左边已经分配给元素4.然后,执行该方法的其余部分,以return t
结尾。在这种情况下,t
是通过方法传递的Elem
元素6.然后元素5的插入已经结束。
*6
/ \
4 8
\
5