我已经通过合并实现了delete的迭代版本,但是我很难以递归的方式实现。
这是我的迭代版本:
public void deleteByMerging(T el) {
BSTNode<T> tmp, node, p = root, prev = null;
while (p != null && !p.el.equals(el)) {
prev = p;
if (el.compareTo(p.el) < 0)
p = p.right;
else p = p.left;
}
node = p;
if (p != null && p.el.equals(el)) {
if (node.right == null)
node = node.left;
else if (node.left == null)
node = node.right;
else {
tmp = node.left;
while (tmp.right != null)
tmp = tmp.right;
tmp.right =
node.right;
node = node.left;
}
if (p == root)
root = node;
else if (prev.left == p)
prev.left = node;
else prev.right = node; // 5.
}
else if (root != null)
System.out.println("el " + el + " is not in the tree");
else System.out.println("the tree is empty");
}
现在我需要以这种方式实现递归函数:
public void delete(T info) {
root = delete(root, info);
}
public TreeNode<T> delete(TreeNode<T> node, T info)
{
}
我是递归的新手,我不知道从哪里开始。
答案 0 :(得分:0)
(通过&#34;你的#34;迭代版本,你当然是指Adam Drozdek的。)
这应该有效:
public void delete(T info) {
root = delete (root.info);
}
public TreeNode<T> delete(TreeNode<T> node, T info) {
// if this node is null, we have reached the end of the tree
// so the node is not in the tree.
if (node == null) {
return node; // or handle as required
// if this is not the node to delete;
// recursively call this on the node's correct child
else if (info.compareTo(node.info) <0) {
node.left = delete(node.left, info);
return node;
} else {
node.right = delete(node.right, info);
return node;
}
// if this is the node to delete:
else if (node.info.equals(info)) {
// to delete it, we must return a sub-tree without it.
if (node.left == null)
// this node is a leaf node, or
// node.right contains only child.
// either way, return node.right
return node.right;
if (node.right == null)
// node.left contains only child
return node.left;
// else node has 2 children, so delete by merging:
// first, find its direct predecessor:
TreeNode<T> tmp = node.left;
while (tmp.right != null)
tmp = tmp.right;
// then append the node's right sub-tree
// to its direct predecessor:
tmp.right = node.right;
// lastly, replace the node by its left sub-tree:
return node.left;
}
}
首先我们检查node
是否为空。如果是,那意味着我们要删除的元素不在树中,因为我们已遍历,直到我们用尽了所有节点。
接下来,我们检查元素是否大于或大于当前节点中的元素。如果是,我们需要继续遍历树,向左或向右移动,具体取决于元素的比较方式。请注意,在递归步骤中,我们将删除操作的结果分配给node
个孩子中的一个。我们从第一个函数中获取了这个提示,其中root
被分配了root
上的删除操作的结果。这将递归遍历树,直到node
引用您要删除的节点。我们还在这里返回node
,这样如果没有发生任何更改,例如,对node.right = delete(node.right, info)
的调用将不会更改当前节点。
当我们找到节点时,可能有4种情况:节点可以是叶子节点(没有子节点),或者它可以有1个左子节点或1个右子节点,或者它可以有2个子节点。第3个场景由行
涵盖if (node.left == null)
return node.right;
if (node.right == null)
return node.left;
请注意,如果node
没有孩子,则第一次if
检查将为真,因此将返回node
的右子(null)节点。
为什么返回null删除节点?因为,在上面讨论的遍历步骤中,我们将删除操作的结果分配给node
的孩子。请注意,在此步骤中,前一个递归步骤中的node
是node
的父级,因为删除是在该节点的子级上递归调用的。因此,在此处返回null将导致先前的调用将null分配给父的子节点,从而删除子节点。基本上,每当我们返回除node
以外的任何内容时,我们将用树中返回的任何内容替换当前节点。
在第四种情况下,我们需要通过合并进行简单的删除。您可以通过将node
的右子树附加到其左子树中最右边的节点来实现。首先,我们在左子树中找到最右边的节点,它是node
的直接前身:
TreeNode<T> tmp = node.left;
while (tmp.right != null)
tmp = tmp.right;
所以tmp
现在是node
的直接前任。接下来,我们将node
的右子树锁定到tmp
:
tmp.right = node.right;
最后,要将node
替换为左侧子树,我们只需返回node.left
,因为这会将node
替换为node.left
作为node
的子项1}}在前一个递归调用中的父级。
如果我的解释让您感到困惑,可以试试this one。这更容易用纸上的图片来解释,这就是为什么你应该在实际课程中问我(是的,我设置了这个实践)而不是SO :)希望你在截止日期之前弄清楚它!