当前位置: 首页 > 知识库问答 >
问题:

BST删除节点方法“切断”树的其余部分

郑正文
2023-03-14

我想写一个从二叉搜索树中删除节点的html" target="_blank">方法。

这是我的方法:

public void remove(Node node)
	//Removes a given node and puts one of the nodes below it in its place until it reaches the end
	{
		
		if (node.left != null) //If the node to the left is not empty
		{
			node.value = node.left.value; //Moves up the left node to take its place
			remove(node.left); //Goes to the next node
			if (node.left.right == null && node.left.left == null)
				node.left = null; //Removes the last node at the end of the tree after moving it up
		}
		else if (node.right != null) 
		{
			node.value = node.right.value; //Moves up the left node to take its place
			remove(node.right); //Goes to the next node
			if (node.right.left == null && node.right.right == null)
				node.right = null; //Removes the last node at the end of the tree after moving it up
			
		}	
		
	}

问题是它只在某些情况下有效。

假设我输入60,70,65。(根节点为50)树应该看起来像

   50
  /  \
     60
    /   \
        70
       /  \
      65

假设我选择移除60个。一开始这似乎很管用。然而,如果我运行我信任的搜索方法,返回70在任何一个指针上都没有节点。

我假设70被设置为空,然后65才能被提升。由于65在技术上不再与树相连,搜索方法无法找到它。

所以像这样的事情:

   50
  /  \
     70
    /   \

       /  \
      65

问题是,我不明白这是怎么发生的。尤其是由于if语句,如果节点的两个指针都指向null,那么它应该将节点设置为null

if (node.left.right == null && node.left.left == null)
                node.left = null;

if (node.right.left == null && node.right.right == null)
                node.right = null;

此外,如果第一个if语句不是true(if left!=null),它不应该继续执行所指示的“else”(并删除右边的那一个)吗?

任何建议或提示都非常欢迎。

共有1个答案

邓光赫
2023-03-14

你移除方法的逻辑有很大缺陷。首先,你不是在移动节点,而是在复制值,这已经是不正确的:因为任何节点都可以有两个链接,只复制左边或右边的链接值,然后检查你是否在某个叶上,最终删除它是错误的:如果你不在某个叶上呢?你背后的另一个环节呢?在你的例子中,最后70的右边是65:不再是BST。记住,规则是,对于任何节点n,左子树中的所有节点都必须小于n,右子树中的所有节点都必须大于n。

这也是你找不到65的原因:这不是因为70有两个空指针,像你想象的那样,而是因为你的搜索方法,当它到达70时,因为它比65大,在节点70的左边搜索65,在那里它找到一个空。

这是在BST中删除节点的正确和经典的Hibbard算法:要删除节点x,你必须用它的后继节点替换它。它的继任者是哪一个?因为x有一个右子节点,它的后继节点是其右子树中具有最小键的节点。替换保留了树中的顺序,因为x.key和后继键之间没有键。我们通过四个步骤完成用其后继者替换x的任务:

>

  • 保存到t中要删除的节点的链接

    将x设置为指向其后续的min(右t)。

    将x的右链接(应该指向包含大于x.key的所有键的BST)设置为deleteMin(t.right),删除后指向包含大于x.key的所有键的BST的链接
    。(要删除最小值,我们向左走,直到找到一个左链接为空的节点,然后用右链接替换到该节点的链接)

    将x的左链接(为空)设置为t.left(所有小于已删除键及其后继键的键)。

  •  类似资料:
    • 假设我有一个二元搜索树,其中我应该按照标准输入中给定的顺序插入N个唯一编号的键,然后我要删除所有键间隔为I=[最小,最大]的节点,以及与这些节点相邻的所有连接。这给了我很多较小的树,我要以一种特殊的方式将它们合并在一起。更精确地描述问题: 给定包含不同键的BST和间隔I,间隔删除分两个阶段进行。在第一阶段,它将删除关键帧位于I中的所有节点以及与已删除节点相邻的所有边。让生成的图包含k个连通分量T1

    • 我正在阅读一本书,该书解释了如何从二元搜索树中删除节点,基本上如果我们有这棵树: 我们想删除节点4,书上说我应该: 在其右子树(即6)中找到4的继任者 交换4和6 从右子树中删除6 将4的左侧子树(在本例中仅为1)附加到新节点6 因此我们得到 然而,我想到了另一种方法来做到这一点: 找到4个右子树的最小元素(即6) 将4的左子树附加到6(它不会有左子树) 将父元素(10)附加到4的右侧元素(8)。

    • 当我通过GPS移除一个节点时,当我试图打印二叉树时,会出现堆栈溢出。下面是我的一些代码。我不能理解它将如何工作良好,如果我删除的名称,但不是,如果我删除的坐标,因为我正在使用相同的删除方法。 我得到的确切错误是“Exe:0xC00000FD中0x013214D6处的未处理异常:堆栈溢出(参数:0x00000001,0x00152FFC)”。在按坐标删除后,在打印函数中会出现这种情况,但如果按名称删

    • 本文向大家介绍Javascript removeChild()删除节点及删除子节点的方法,包括了Javascript removeChild()删除节点及删除子节点的方法的使用技巧和注意事项,需要的朋友参考一下 下面给大家介绍Javascript removeChild()删除节点的方法,具体详情如下所示: 在Javascript中,只提供了一种删除节点的方法:removeChild()。 rem

    • 本文向大家介绍删除Javascript树中的节点,包括了删除Javascript树中的节点的使用技巧和注意事项,需要的朋友参考一下 如果从远处看,从树中删除节点非常复杂。删除节点时需要考虑3种情况。这些在以下功能的注释中提到。正如我们之前所做的那样,我们将在类中创建一个方法和一个递归调用的助手。 类方法 辅助方法 您可以使用以下方式进行测试:  示例 输出结果 这将给出输出-

    • 主要内容:src/runoob/binary/BSTRemove.java 文件代码:本小节介绍二分搜索树节点的删除之前,先介绍如何查找最小值和最大值,以及删除最小值和最大值。 以最小值为例(最大值同理): 查找最小 key 值代码逻辑,往左子节点递归查找下去: ... // 返回以node为根的二分搜索树的最小键值所在的节点 private Node minimum (Node node ) {     if ( node. left == null )         retu