C++;-删除AVL树中的节点 我现在尝试在C++中实现一个AVL树,到目前为止,我做了很多其他的事情,除了节点删除。

C++;-删除AVL树中的节点 我现在尝试在C++中实现一个AVL树,到目前为止,我做了很多其他的事情,除了节点删除。,c++,pointers,reference,C++,Pointers,Reference,1) 有人能确认我删除节点的算法是正确的吗 在树中查找要删除的节点 如果节点有0个子节点:删除节点 否则,如果节点有一个子节点:删除该节点,然后重新链接其子节点 else(2个子节点):找到其后续节点,并将要删除的节点与其后续节点交换。然后重复这些步骤删除节点(现在是其后续节点所在的位置) 插入后重新平衡树(它将递归地重新平衡树…) 我已经这样做了,但我不确定的部分是删除节点的步骤。我是否也必须删除对节点的引用,否则它将被管理?(因为我传入了一个Node*&参数,但后继者只是函数中的一个No

1) 有人能确认我删除节点的算法是正确的吗

  • 在树中查找要删除的节点
  • 如果节点有0个子节点:删除节点
  • 否则,如果节点有一个子节点:删除该节点,然后重新链接其子节点
  • else(2个子节点):找到其后续节点,并将要删除的节点与其后续节点交换。然后重复这些步骤删除节点(现在是其后续节点所在的位置)
  • 插入后重新平衡树(它将递归地重新平衡树…)
我已经这样做了,但我不确定的部分是删除节点的步骤。我是否也必须删除对节点的引用,否则它将被管理?(因为我传入了一个Node*&参数,但后继者只是函数中的一个Node*)

我不确定我是否说得非常清楚,如果你需要更多细节,请告诉我


(我会发布一些代码,但不幸的是我会讲法语,所以我想你不会从中了解太多)

如果节点是使用“new”创建的,那么它绝对需要被显式删除。他们的问题是在哪里。如果要删除节点(假设没有其他人需要节点的内容),那么在完成从树中删除节点后,还应该删除节点本身

现在,对节点的引用是另一回事。如果引用是方法参数定义的工件,则不必对其进行任何处理。在堆栈上创建引用是为了帮助方法调用。如果我记得我的C++,引用永远不会是空的,这意味着永远不必说抱歉(坏笑话),呃永远不必删除它们。 [编辑] OP说,“因为我传入了一个参数Node*&,但后继者只是函数中的一个Node*”,所以我假设您的意思是:

void removeNode(Node*& node) 
这就叫使用

void foo()
{
    Node* n = new Node();
    // for example
    removeNode(n);
}
<>我的C++有点生疏,但是这里的想法是‘n’是一个指针,但是ReaveNoDeE()的参数类型是指针的引用。调用方不知道涉及引用,它只是传递“n”,期望arg类型是指向节点(node*)的指针。编译器正在创建引用作为参数的包装,因此只有被调用方知道该引用。由于引用是在堆栈上创建的,因此当removeNode()返回时,它将被正确地“管理”。“n”指向的节点仍然需要删除,问题是哪个代码应该处理它

首先想到的是“removeNode()”来完成它。一个问题是,它只有一个对它的引用,如果删除指针(引用的目标),引用将为null,这是一个坏主意/不允许的。一想到尝试它的语法就让我畏缩

因此,请使用客户端代码来执行此操作,如下所示:

void foo()
{
    Node* n = new Node();
    // for example
    removeNode(n);
    delete n;
}

基本上,您需要为节点指针的范围制定计划。只要它是一致的,你可以用几种不同的方法来做。如果希望removeNode()处理删除操作,则将参数类型更改为指针,而不是引用,并记录调用,这样做的目的是:从树中删除节点,同时删除内存。

问题的棘手部分是“删除对节点的引用”实际上是相当模糊的:根据你所考虑的“删除引用”,答案可以是“是”或“否”。 在我看来,作为重新链接树的一部分,您将“删除对节点的引用”。关键的一点是,您的方法将节点指针作为
node*&
接收:这样一来,您的方法不仅获取指向正在检查的节点的指针,还接收指向该指针在父节点中存储位置的引用。必须修改此引用才能保持树链接的完整性

因此,如果您的方法执行以下操作:

void deleteNode (Node*& node) {
    if (node is the right one to delete) {
        Node * tmp = node;
        node = node->successor;
        delete node;
    }
    else
        deleteNode(node->successor);
}

赋值
node=node->successiver
实际上修改了先前节点的successiver字段。没有这个分配,树结构会被破坏,因为以前的节点的后继字段将指向现在已释放的节点。

< P>你在标准C++中编码,那么没有任何东西会被“管理”。如果你使用智能指针,那么他们会为你处理交易

对于您的界面,我建议
remove()
函数使用指向要删除的节点的指针。这样,您就不必费心查找节点了,因为它是给定的。不过,一定要编写一个
find()
函数,这样客户端就可以自己找到节点

最后,我不确定是否遵循第三种情况,即要删除的节点有两个子节点。在AVL树中,当一个要删除的节点作为两个子节点时,可以将其与要删除的节点的左子树的最右边的子节点交换。交换后,要删除的节点正好有一个或零个子节点,因此基本上将问题归结为这两种情况

例如:

            20
     40            15
  60    35     18       10
80    38  30 19  17   13   8
在上面的树中,如果要删除节点
20
,请将其与节点
30
(节点
35
的子节点)交换:

然后将节点
20
作为无子节点删除。如果没有节点
30
,则左子树最右边的子节点将是节点
35
,您可以用它交换节点
20
。然后你必须删除一个只有一个子节点的节点,你知道怎么做


请注意,在完成删除之前,树处于不一致的状态。如果您同时工作,这一点很重要。

您能进一步解释一下吗如果引用是一个方法的工件,那么感谢您的解释。:-)那正是我在做的是的,那正是我在做的。。。我的问题更多的是关于如何删除裁判
            30
     40            15
  60    35     18       10
80    38  20 19  17   13   8