我目前正在尝试用C ++实现一个AVL树,到目前为止,我已经完成了除节点删除之外的所有事情。
1)有人可以确认我删除节点的算法是否正确?
我已经完成了这个,但是我不确定的部分是我删除节点的步骤。我是否还必须删除对节点的引用,否则它将被管理? (因为我已经传入参数Node *&,但后继者只是函数中的Node * ...)
我不确定我是否非常清楚,如果您需要更多详细信息,请告诉我。
(我会发布一些代码,但不幸的是我说法语,所以你不会理解它,我猜)
答案 0 :(得分:2)
如果节点是使用'new'创建的,那么绝对需要显式删除。他们的问题将是其中。如果要删除节点(假设其他人不需要节点的内容),那么在完成从树中删除节点后,还应删除节点本身。
现在,对节点的引用是另一回事。如果引用是方法参数定义的工件,则不必对其执行任何操作。在堆栈上创建了引用以帮助进行方法调用。如果我记得我的C ++,引用永远不会为空,这意味着永远不必说你很抱歉(糟糕的笑话),永远不必删除它们。
[编辑] OP说,“因为我已经传入参数Node *&,但后继只是函数中的Node * ...”所以我认为你的意思是:
void removeNode(Node*& node)
然后使用
调用void foo()
{
Node* n = new Node();
// for example
removeNode(n);
}
我的C ++有点生疏,但这里的想法是'n'是指针,但removeNode()的参数类型是对指针的引用。调用者不知道涉及引用,它只是传递'n',期望arg类型是指针到节点(Node *)。编译器正在创建引用作为参数的包装器,因此只有被调用者知道引用。由于引用是在堆栈上创建的,因此当removeNode()返回时,它将被正确“管理”。 “n”指向的节点仍然需要删除,问题是哪些代码应该处理它。
首先想到的是'removeNode()'来做。一个问题是它只有一个引用它,如果删除指针(引用的目标),引用将为null,这是一个坏主意/不允许。只是想到尝试它的语法让我感到畏缩。
所以,请让客户端代码执行此操作,如下所示:
void foo()
{
Node* n = new Node();
// for example
removeNode(n);
delete n;
}
基本上,您需要制定节点指针范围的计划。只要它是一致的,你可以用几种不同的方式来做。如果你想让removeNode()来处理删除,那么将参数类型改为指针而不是引用并记录调用,所以期望它既从树中删除节点又删除内存。
答案 1 :(得分:1)
你问题的棘手部分是“删除对节点的引用”实际上是相当模糊的:取决于你认为“删除引用”的内容,答案可以是“是”或“否”。
在我看来,你将“删除对节点的引用”作为重新链接树的一部分。关键部分是你的方法接收节点指针为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->successor
实际上修改了先前节点的后继字段。如果没有这个赋值,你的树结构就会被破坏,因为前面的节点的后继字段将指向一个现已解除分配的节点。
答案 2 :(得分:0)
我使用标准C ++进行编码,然后就不会为您“管理”任何内容。如果你使用智能指针,那么他们会照顾你的解除分配。
至于你的界面,我建议remove()
函数获取一个指向要删除的节点的指针。然后你就不需要费心去寻找节点了。虽然写了find()
函数,所以客户端可以自己找到节点。
最后,我不确定我是否遵循了第三种情况,即要删除的节点有两个子节点。在AVL树中,当要删除的节点作为两个子节点时,您可以将其与要删除的节点的左子树的最右边的子节点交换。交换后,要删除的节点只有一个或零个子节点,因此您基本上将问题减少到这两种情况。
例如:
20
40 15
60 35 18 10
80 38 30 19 17 13 8
在上面的树中,如果要删除节点20
,则将其与节点30
(节点35
的子节点)交换:
30
40 15
60 35 18 10
80 38 20 19 17 13 8
然后删除节点20
作为无子节点。如果没有节点30
,那么左子树的最右边的子节点将是节点35
,并且您将节点20
与之交换。然后你必须删除一个孩子的节点,你知道该怎么做。
请注意,在完成删除之前,树处于不一致状态。如果你同时工作,这很重要。