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