解释c ++中'int'类型的递归函数的返回值

时间:2017-07-26 23:02:30

标签: c++ recursion binary-search-tree

无法理解如何使用int类型的递归函数找到二叉搜索树的高度的解释。

对于任何二叉搜索树,给定指向树根节点的指针,其中Node按常规定义如下......

struct Node {
    int data;
    Node* left;
    Node* right;
}
Node* root;

我们可以使用以下int类型的递归函数来给我们二叉搜索树的高度...(函数'max'只需要两个整数并返回两者中的较大者)

int findHeight(Node* root){
    if(root == NULL){
        return -1;
    }
    return max(findHeight(root->left),findHeight(root->right)) + 1;
}

int max(int a, int b){
    if (a > b)
        return a;
    else
        return b;
}

我的理解是findHeight(root-> left)找到root的左子树的高度,findHeight(root-> right)找到root的右子树的高度,然后max返回更大的子树,因为这将是树的整体高度,加上一个包含将根连接到该子树的边缘。

我对递归很新,所以我决定解压其中一个递归函数调用并尝试理解它。我用一种伪代码方式写出了findHeight(root-> left),每次函数调用自身时都会出现“PAUSE”这个词来表示堆栈上发生的事情,并将下一个函数调用缩进到显示一个新的堆栈帧...(在我的样本BST中,左子树的高度为2)

int fH(Node* root){
    if(root == NULL)
        return -1;

    fH(root->left);
    PAUSE

    int fH(Node* root){
        if root == NULL)
            return -1;

        fH(root->left);
        PAUSE

        int fHR(Node*root){
            if (root == NULL)
                return -1;

            fH(root->left);
            PAUSE

            int fHR(Node* root){
                if (root == NULL)
                    return -1;

                fH(root->left);
                PAUSE

                int fHR(Node* root){
                if(root==NULL)
                    return -1;
                }
            }
        }
    }
}

该函数正常工作,但我不明白函数的返回值是如何从-1增长的,这是函数的最终执行返回到2.递归int函数为它们的返回加1每当它们返回到前面的堆栈帧时都会产生值?

我在该短函数中没有看到任何增加函数返回值的内容。我唯一看到的是最后一次通话时它是-1。

如果有人可以尝试向我解释这一点,我真的很感激帮助。非常感谢你。

6 个答案:

答案 0 :(得分:2)

函数findHeight返回当前找到的最大高度。

因此,考虑到这一点,最大呼叫是合理的。

enter image description here

在这个动作重演中,我们得到以下函数调用。

  1. 呼叫节点1.我们希望在左侧找到2个更深的深度。还有一个在右边。所以max,希望能在左手边做出决定。 max调用Node2和node3
  2. 第4点讨论了对2的调用。
  3. 对3的调用返回0. max of -1和-1,+ 1。 Max为-1,添加一个。
  4. findHeight to node 2的最大值为(左侧节点(-1)),右侧节点为4)项目5 + 1.
  5. max of -1,-1 +1 = 0.所以这使得Point 4的最大值评估为1。
  6. 所以最后函数findHeight说,这是我当前检查的结束(0高度)。之前的函数调用可以添加他们喜欢的内容。

    在我看来,这个功能可以用更直观的方式编写。

    也许

    int treeHeight(Node* node){
        if (!node) // We are not a node.
            return 0;
        int weAreANode = 1;  // Height 1.
        int heightLeft = treeHeight(node->left);
        int heightRight = treeHeight(node->right);
        int theHighestSubtreeHeight = std::max(heightLeft, heightRight);
    
        return weAreANode + theHighestSubtreeHeight;
    }
    

    我真的只想再画一些东西。

答案 1 :(得分:1)

我对你的问题的理解是,对于findHeight的每次递归调用,身高是如何增加的,请告诉我这是不是很正确。

通常在C ++中,没有特定的语法将函数定义为递归,而是让程序员通过参数递归地使用它们的函数并返回它们函数的值。

使用此特定功能,看起来增量发生在此行的末尾:

    return findHeight(max(findHeight(root->left),findHeight(root->right)) + 1;

返回函数末尾的+1会显式递增递归调用,除了返回int之外,int函数不会执行任何隐式递增。

答案 2 :(得分:1)

您的伪代码错过了PAUSE之后发生的事情。缺少的是

  • 致电fH(root->right)(即使root->rightnullptr
  • 计算两个递归调用的max
  • 在结果中添加1。

特别是,最后一点对于计算树的高度水平至关重要。

如果将这些点添加到伪代码中,您可能会发现它类似于特定树的结构。

答案 3 :(得分:1)

考虑这棵树,

     5
   /   \
  3     10
 / \   /  
2   4 8

将使用root 5调用该函数。

然后将使用32(左子3)然后4(右子3)来调用它。

2的高度评估为max(-1, -1) + 1 = 0,并在3调用findHeight(root->left)后返回。 4也是如此。

35的{​​{1}})的调用现在评估为findHeight(root->left)

所以max(0, 0) + 1 = 1的左孩子的身高为5

另一个孩子(右孩子)遵循相同的过程,其中对1的左孩子的召唤返回10的高度,而右孩子则返回0的高度。 -1 max(0, -1) + 1 = 1将返回5的{​​{1}}。

现在回到顶部,findHeight(root->right)的身高被评估为5

答案 4 :(得分:1)

所以考虑一下你的例子,让我们说你有根节点作为' A'左边的节点为' B'和正确的节点为' C'。该计划应返回' 1' -

这是堆栈跟踪 -

findHeight(A)       
findHeight(B)       
POP findHeight(NULL)    returns -1

findHeight(NULL)用于B的左侧节点,该节点为NULL并返回-1

现在堆栈有 -

findHeight(A)       
findHeight(B)       max(-1, /*code yet to execute*/) + 1
POP findHeight(NULL)    returns -1 

findHeight(NULL)用于B的右侧节点,该节点为NULL并返回-1。

现在堆栈就像 -

findHeight(A)       
POP findHeight(B)       max(-1, -1) + 1 -> returns 0 

此时控件返回到BST的根节点,即节点' A'在执行右节点(节点C)的左节点后,堆栈就像 -

findHeight(A)       max(0, /*code yet to execute*/) + 1
findHeight(C)
findHeight(NULL)    returns -1

findHeight(NULL)用于C的左侧节点,该节点为NULL并返回-1

现在堆栈有 -

findHeight(A)       max(0, /*code yet to execute*/) + 1       
findHeight(C)       max(-1, /*code yet to execute*/) + 1
POP findHeight(NULL)    returns -1

findHeight(NULL)用于B的右边节点,该节点为NULL并返回-1。

现在堆栈就像 -

findHeight(A)       max(0, /*code yet to execute*/) + 1      
POP findHeight(C)       max(-1, -1) + 1 -> returns 0 

在完成findHeight(C)之后,控件返回到findHeight(A),现在堆栈已经 -

findHeight(A)       max(0, 0) + 1 -> returns 1

你必须添加+ 1,你明确地从你的主要调用函数。

答案 5 :(得分:1)

返回线上发生的事情太多了。让我们重写这样的代码:

int findHeight(Node* root){
    if(root == NULL){
        return -1;
    }
    int left = findHeight(root->left);
    int right = findHeight(root->right);
    int maxval = max(left,right);
    return maxval + 1;
}

int max(int a, int b){
    if (a > b)
        return a;
    else
        return b;
}

现在,如果我们扩展调用,你可以看到在底部的一个叶子上,左边是-1,右边是-1,然后maxval是-1,它将返回0(因为叶子下面没有任何东西)。然后在底部调用返回0之后,下一级别的最大值将为0,返回的值将为1(因为叶子在下面)。

让我们看一下只留下几个孩子深度的孩子:

int findHeight(Node* root){
    if(root == NULL) return -1; // not taken

    int left = findHeight(Node* root->left){
        if(root == NULL) return -1; // not taken

        int left = findHeight(Node* root->left){
            if(root == NULL) return -1; // not taken

            int left = findHeight(Node* root->left){
                if(root == NULL) return -1; // return here, rest of code doesn't happen
            } // left = -1 at this point (no left children below here)

            int right = findHeight(Node* root->right){
                if(root == NULL) return -1; // return here, rest of code doesn't happen
            } // right = -1 at this point (no right children)

            int maxval = max(left,right); // left = -1, right  = -1
            return maxval + 1; // -1 + 1 = 0
        } // left = 0 at this point (1 left child below here)

        int right = findHeight(Node* root->right){
            if(root == NULL) return -1; // return here, rest of code doesn't happen
        } // right = -1 at this point (no right children)

        int maxval = max(left,right); // left = 0, right = -1;
        return maxval + 1; // 0 + 1 = 1
    } // left = 1 at this point (2 left child below here)

    int right = findHeight(Node* root->right){
        if(root == NULL) return -1; // return here, rest of code doesn't happen
    } // right = -1 at this point (no right children)

    int maxval = max(left,right); // left = 1, right = -1
    return maxval + 1; // 1 + 1 = 2
}