这个双递归调用如何显示数据c ++

时间:2016-11-21 04:38:25

标签: c++

我不确定以下代码如何显示rChild和lChild中的数据。在到达显示代码之前,调用该函数并传递参数ptr-rChild。因此,显示代码永远不会有机会执行,因为在显示代码之前总是有一个函数调用。此外,当再次调用该函数时,但这次参数是lChild,当第一次使用参数rChild进行函数调用时,它如何在lChild中显示数据。

void CTree::DisplayTree(PersonRec * ptr)
{
    if (ptr != NULL)
    {
        DisplayTree(ptr->rChild);
        cout << "Name: " << ptr->name << "\t" << "Bribe Offered: " << ptr->bribe << endl;
        DisplayTree(ptr->lChild);
    }

}

4 个答案:

答案 0 :(得分:2)

以下面的树为例,其中Node0是传递给PersonRec*的第一个DisplayTree(右侧是访问节点以供参考的顺序):

           Node0                       1st
          /     \                     /   \
     Node2       Node1             5th     2nd
    /    |       |    \           /  |     |  \
NULL  NULL       NULL  NULL    7th 6th     4th 3rd
  • 第一个调用进入if语句并将Node1传递给DisplayTree(作为rChild
  • 第二个调用进入if语句并将NULL传递给DisplayTree(作为rChild
  • 第三个调用未输入if语句,因为参数为NULL并返回第二个调用(Node1
  • 第二个电话现在打印Node1 ,然后将NULL传递给DisplayTree(作为lChild
  • 第四个调用不会进入if语句并返回第二个调用(Node1
  • 第二个电话已完成并返回第一个电话(Node0
  • 第一个电话现在打印Node0 ,然后将Node2传递给DisplayTree(作为lChild
  • 第五个调用进入if语句并将NULL传递给DisplayTree(作为rChild
  • 第六个调用不会进入if语句并返回第五个调用(Node2
  • 第五个电话现在打印Node2 ,然后将NULL传递给DisplayTree(作为lChild
  • 第七个调用不会进入if语句并返回第五个调用(Node2
  • 第五个电话已完成并返回第一个电话
  • 第一个电话已完成

修改:使用较小的示例来处理您的评论。考虑一个只有一个节点没有子节点的树,这次让我们更多地关注代码。树看起来像这样:

     Node0
    /     \
NULL       NULL

第一次调用代码时,会传入Node0if (ptr != NULL)true,因此执行会输入if语句。下一行DisplayTree(ptr->rChild);使用NULL调用该函数。在该调用期间,if (ptr != NULL)false,因此执行不会进入if语句。结果,执行返回到上一个调用,下一行代码是cout << "Name: " << ptr->name...,它打印Node0的信息,这就是输出的原因。该行之后的调用DisplayTree(ptr->lChild);也无效,因为它传递了NULL,然后所有递归都已完成

答案 1 :(得分:0)

它将始终首先遍历左边的孩子。当它离开左侧时,它将开始穿越右侧。

这称为“按顺序”递归。

https://en.wikipedia.org/wiki/Tree_traversal

答案 2 :(得分:0)

&#39;递归函数的概念&#39;很简单,但在第一次遇到它时可能有点吓人。有很多很好的资源,我个人非常喜欢以下几个:

http://www.cplusplus.com/articles/D2N36Up4/

http://www.cprogramming.com/tutorial/lesson16.html

正如您所知,函数调用放在堆栈内存中,由于此内存有限,一旦调用太多而没有结束,程序将崩溃。因此,递归定义的一个重要部分是停止标准,它指定何时以及在什么情况下,函数将停止调用自身并打破递归循环。在您的代码中,行if (ptr != NULL)是停止条件。因此,你的问题的答案

  

所以显示代码永远不会有机会执行,因为在显示代码之前总是有一个函数调用。

DisplayTree的递归调用将在到达rChildlChildNULL的树的叶子时结束。也就是说,DisplayTree(ptr->rChild);将立即为叶节点返回,cout << "Name: " << ptr->name << "\t" << "Bribe Offered: " << ptr->bribe << endl;代码行有机会执行并打印数据。当然,这完全取决于你的树是否定义明确。从您的代码可以假设该函数期望叶节点具有rChild和lChild的NULL值。因此,如果树是按照此规范构造的,则将满足停止条件并显示数据。另一方面,如果树构造不正确,程序将因堆栈溢出而崩溃(请参阅en.wikipedia.org/wiki/Stack_overflow

答案 3 :(得分:0)

每当看到递归函数调用时,都知道函数在某个时刻返回,并且将执行下一个语句。但是怎么样?好吧,DisplayTree(ptr->rChild)将继续调用自身,并在收到空指针时停止。这就是为什么你的if (ptr != NULL)检查如此重要 - 它可以防止无限递归,而且逻辑上你也不想取消引用空指针。

当接收到空指针的函数返回时,编译器将调用堆栈下移到进行调用的最后一帧。在那里它将继续下一个声明。这将是它将在树中打印最右边的节点。然后它将以ptr->lChild递归调用自身,它将在 树中找到最右边的节点,然后重新开始该过程。

这是一个inorder遍历的示例。当我看到这样的函数时,我想对自己说&#34;这个函数首先为右子树,当前节点,然后是它的左子树&#34;执行中间语句。这让它变得更加易于理解。