我正在编写一个编程任务并编写一堆函数来实现二叉搜索树,并给出了一些函数。我以为我理解了递归,但是如果你愿意,我会一直挂断转换方向。
以下是赋值的函数:
static void deleteAll(BSTNode<Data>* n) {
if (0 == n) return;
deleteAll(n->left);
deleteAll(n->right);
delete n;
}
要删除真正的短树,
root / \ lefty righty
我致电deleteAll(root)
。 n != 0
现在我打电话给deleteAll(lefty)
。 n != 0
所以我致电deleteAll(lefty->left)
。当然没有左节点。当我添加lefty节点时,我的构造函数将left,right和parent指针初始化为0,所以现在n == 0
。所以我退出了这个功能,永远不会删除。我怎么去deleteAll(n->right)
?
正如我所说,提供此功能所以我不应该改变它。我想也许我必须打电话给deleteAll(b.begin())
或b.end()
以从左侧或最右侧的节点开始,但每次我在脑海中经历它都会点击n == 0
。
请帮我理解。
答案 0 :(得分:5)
想象一个箭头指向正在执行的当前行。当我们致电deleteAll(root)
时,首先我们检查root
是否为0:
--> if (0 == root) return;
deleteAll(root->left);
deleteAll(root->right);
delete root;
由于root != 0
,我们会调用deleteAll(root->left)
:
if (0 == root) return;
--> deleteAll(root->left); /*
|-1-> if (0 == lefty) return;
|-2-> deleteAll(lefty->left);
|-3-> deleteAll(lefty->right);
|-4-> delete lefty; */
deleteAll(root->right);
delete root;
}
现在箭头将向上移动到函数的顶部并开始对lefty
执行相同操作,在我的注释中通过第1-4行(在第2行,同样的扩展将再次发生,直到找到一个空节点)。但重要的是它记住函数调用之前的位置,以便以后可以恢复。所以deleteAll(root->left)
会去做它做的事情并最终回归。然后原始呼叫继续:
if (0 == root) return;
deleteAll(root->left);
--> deleteAll(root->right);
delete root;
现在也删除了正确的节点。这种情况发生在递归的每一步。请记住,return
仅返回当前函数,而不是整个递归链。
答案 1 :(得分:2)
返回仅返回调用它的函数。在deleteAll(lefty)
的情况下(如果我理解正确,或者deleteAll(root)
)。 deleteAll(n->right)
返回后会调用deleteAll(n->left)
。 deleteAll的post条件是n,它的所有子节点都将被删除。
想象一下,我们有以下树:
a
/ \
b c
/ \
d e
调用图如下:
deleteAll(a)
deleteAll(a->left)
deleteAll(a->left->left)
deleteAll(a->left->left->left)
deleteAll(a->left->left->right)
deleteAll(a->left->right)
deleteAll(a->right)
deleteAll(a->right->left)
deleteAll(a->right->right)
deleteAll(a->right->right->left)
deleteAll(a->right->right->right)
或者就节点名称而言:
deleteAll(a)
deleteAll(b)
deleteAll(d)
deleteAll(NULL)
deleteAll(NULL)
deleteAll(NULL)
deleteAll(c)
deleteAll(NULL)
deleteAll(e)
deleteAll(NULL)
deleteAll(NULL)