C++ 二叉树中的递归函数解释
我正在学习二叉树教程。C++ 二叉树中的递归函数解释,c++,c,binary-tree,C++,C,Binary Tree,我正在学习二叉树教程。 我对递归函数的使用有点拘泥。例如,我需要计算树中的节点数 int countNodes( TreeNode *root ) { // Count the nodes in the binary tree to which // root points, and return the answer. if ( root == NULL ) return 0; // The tree is empt
我对递归函数的使用有点拘泥。例如,我需要计算树中的节点数
int countNodes( TreeNode *root )
{
// Count the nodes in the binary tree to which
// root points, and return the answer.
if ( root == NULL )
return 0; // The tree is empty. It contains no nodes.
else
{
int count = 1; // Start by counting the root.
count += countNodes(root->left); // Add the number of nodes
// in the left subtree.
count += countNodes(root->right); // Add the number of nodes
// in the right subtree.
return count; // Return the total.
}
} // end countNodes()
现在我的疑问是->它如何计数,说根->左->右的左?或者根->右->左->左??
谢谢
更新:
关键是数据结构和程序都是递归的
- 对于数据结构,这意味着:子树也是树
- 对于代码,它意味着:计算树:=计算子树(并添加一个)
- 说你调用了
countNodes(myTree)代码>。假设myTree
不为空,countNodes
最终将执行count+=countNodes(root->left)
,其中root
是myTree
。它重新进入countNodes
函数,整个树的根位于root->left
(即myTree->left
)。然后逻辑会重复;如果没有root->left
,则函数返回0。否则,它最终将调用count+=countNodes(root->left)代码>再次出现,但这次根目录实际上是myTree->left
。这样它将计数myTree->left->left
。稍后,它会对正确的节点执行相同的操作。每个子树都有自己的根,就像实际的树有根一样。计数与每个子树的计数相同。因此,您只需继续运行,直到到达叶节点并停止局部递归,在运行过程中返回并累加节点。这就是递归算法的美妙之处。该函数是在当前节点及其子节点上定义的。只要对左、右子级的递归调用正确,您就只需要确信当前调用是正确的。同样的道理也适用于孩子和他们的孩子,等等。。。这一切都会正常工作。它将从根->左->(子节点->左)等开始,直到该分支返回0,例如,如果它不是实际节点(树中的一个叶)
然后最深的节点将检查root->right并重复相同的过程。试着用一棵小树想象一下:
因此,在本例中,您的函数将转到A->D->B,然后正确的节点都将返回0,您将从C节点得到最后一个+1。递归基本上就是这样做的,每次调用countNodes时,它都会在到达子节点时添加1(int count=1;
)并在尝试转到叶节点的下一个子节点时终止(因为叶节点没有子节点)。每个节点递归地为其左右子节点调用countNodes,计数缓慢增加并冒泡到顶部
试着这样看,每个节点加1,递归停止的不存在节点加0:
1
/ \
1 1
/ \ / \
1 0 0 0
/ \
0 0
每个1加起来,节点的父节点(每个递归级别的调用函数)加上1+left\u size+right\u size并返回结果。因此,每个阶段返回的值为:
4
/ \
2 1
/ \ / \
1 0 0 0
/ \
0 0
我不确定这是否能让它更清晰,但我希望它能做到。您编写的算法实现是详尽的。它参观了整棵树
如果树为空,则计数为零。
如果不是,我们得到左边的节点,我们称它为L,我们在计数上加1
由于证明了树的子树本身就是一棵树,我们在以L为根的树上再次执行相同的算法
现在我们对根节点为root的树执行此操作
现在。。。这确实有效
树的子树是树,也用于空节点或单个节点。
你应该看看树的定义
你可以用数学归纳法证明,并用归纳推理来表述你的问题。
递归算法通常使用非常类似于归纳推理的结构。对于递归函数,您应该递归地思考!下面是我对这个函数的看法:
- 我开始写函数的签名,也就是
int countNodes( TreeNode *root )
- 首先,不是递归的情况。例如,如果给定的树为
NULL
,则没有节点,因此我返回0
- 然后,我观察到树中的节点数是左子树的节点数加上右子树的节点数加上1(根节点)。因此,我基本上为左节点和右节点调用函数,并将值相加1。
- 请注意,我假设函数已经正常工作了李>
我为什么要这样做?很简单,这个函数应该在任何二叉树上工作,对吗?嗯,根节点的左子树,实际上是一棵二叉树!右边的子树也是一棵二叉树。因此,我可以安全地假设,使用相同的countNodes
函数,我可以计算这些树的节点。一旦我有了它们,我只要加上左+右+1,我就得到了结果
递归函数究竟是如何工作的?你可以用笔和纸来遵循算法,但简而言之,它是这样的:
假设您使用以下树调用函数:
a
/ \
b c
/ \
d e
您可以看到根不为null,因此可以调用左子树的函数:
b
NULL
NULL
然后是右子树
c
/ \
d e
d
e
在调用右子树之前,需要对左子树进行求值
因此,您正在使用输入调用函数:
b
您可以看到根不是空的,因此可以调用左子树的函数:
b
NULL
NULL
返回0和右子树:
b
NULL
NULL
它也返回0。计算树的节点数,它是0+0+1=1
现在,原始树的左子树得到1,它是
b
函数被调用
c
/ \
d e
在这里,再次调用左子树的函数
c
/ \
d e
d
e
这与b
的情况类似,返回1,然后返回右子树
c
/ \
d e
d
e
这也是r