【问题标题】:Binary tree depth二叉树深度
【发布时间】:2017-05-04 21:34:36
【问题描述】:

试图找到二叉搜索树的深度。做了一些谷歌搜索,但我的代码崩溃了:

int treeDepth(int depth) const
        {
            int l = this->left->treeDepth(depth);
            int d = this->right->treeDepth(depth);

            return depth + std::max(l, d);
        }

调用这个函数:root->treeDepth(1);

【问题讨论】:

  • 如果leftright 为空?
  • 还没有添加,但在这种情况下我知道它不是
  • 那么树是怎么结束的......
  • 这棵树是圆形的吗,所有的叶子都重新回到树的根部?
  • 哦,好吧,我明白你的意思了

标签: c++ recursion binary-tree


【解决方案1】:

首先,我认为您可能将树的深度与树的高度混淆了。说明请参考What is the difference between tree depth and height?

例如,以下是此(二叉)树中节点的深度和高度('0' 为根):

    0     -- depth 0, height 2
   / \
  1   2   -- depth 1, height 1 and 2, respectively, for nodes 1 and 2
 / \
3   4     -- depth 2, height 0

如您所见,树根的深度为“0”,即 O(1) 计算。然而,就递归而言,树的高度更有趣,可以使用以下公式计算:

struct TreeNode {
    T _value;
    typedef TreeNode* node_ptr;    
    node_ptr _left, _right;
};
...
int treeHeight(Node* node)
{
    return std::max(node->_left? 1 + height(node->_left) : 0,
                    node->_right? 1 + height(node->_right) : 0);
}
...
std::cout << treeHeight(root);
...

基本思想是这样的: 在递归(深度优先)遍历期间,如果到达叶节点,则返回值“0”(即每个叶节点的高度)。否则,计算以非叶节点为根的树的高度(即该节点的左子树和右子树的高度的最大值 + 节点本身的 1)。从树的开始。

我想在您的问题中解决的第二个方面是关于我从您的函数签名中收集到的内容:

int treeDepth(int depth) const

以及你的称呼方式:

root->treeDepth(1);

树的深度有助于成为的属性。相反,它是树的一个属性,它由树节点组成,其中一个是 root 节点。因此,我将定义类(此处显示的 C++ 结构)如下:

template<class T>
struct BinaryTree {
    struct TreeNode {
        T _value;
        typedef TreeNode* node_ptr;    
        node_ptr _left, _right;
    };
    TreeNode _root_node;
    typedef typename TreeNode::node_ptr node_ptr;
    node_ptr _root;
    ...
    int height(node_ptr node) const;
    ...
};

最后,在树中找到给定节点深度

int depth(node_ptr node) const;
// returns depth of node if it is in the tree, else -1

是一个可以应用递归的问题。但是,递归方法并不自然,广度优先(或级别顺序)遍历将更适合于此。

【讨论】:

  • 根节点深度可以是0也可以是1,取决于你指的是沿路径的边数或节点数。
【解决方案2】:

其实你的代码有很多问题。

您需要实现递归终止,这是阻止您的函数永远调用其自身所需的条件 在您的情况下,您需要编写类似 if(left==nullptr && rigth==nullptr) return depth;

递归终止非常重要!编写递归函数时总是需要它。如果没有你 100% 进入一个永无止境的循环(在最好的情况下)。

然后,当您重新调用您的函数时,您需要更改深度值 我的意思是,如果你在树的另一个节点上向下,这意味着树至少“深度+1”高,所以你需要传递深度+1而不仅仅是深度, 在函数的 and 处写

return std::max(l,d);

另外,你正在使用指针,总是写一个条件来检查你是否真的试图访问一个明确定义的地址,也就是说,在你尝试访问一个地址之前(例如 this->left)你需要写一个像if( this-&gt;left!=nullptr)这样的条件(nullptr来自c ++ 11,否则NULL也会完成工作)

【讨论】:

    【解决方案3】:

    你需要阅读一些关于递归的知识。

    递归的基本原则之一是必须有一个“停止条件”,它会在某个时候终止递归。

    否则,您将遇到所谓的“失控递归”,堆栈被填满,您的程序崩溃和烧毁。

    在您的情况下,“停止条件”将达到 this-&gt;leftthis-&gt;right,恰好为 NULL。

    所以,对于未来的读者(正如 Barmar 在评论中建议的那样)

    int l = left == NULL? 0 : left->treeDepth(depth);
    int d = right == NULL? 0 : right->treeDepth(depth);
    

    【讨论】:

    • 您应该展示如何将此检查合并到他的代码中。
    • @Barmar 不,我不应该。如果他不能做到这一点,他的作业就不配获得及格分数。
    • 所有未来的读者呢?这应该是一种通用资源。
    • @Barmar 也许下周,在他的任务到期之后。如果问题还在这里。否则,我将成为代表 wh_oring。
    • 感谢您的回答!我成功了。
    【解决方案4】:

    试试这样的:

    int treeDepth() const
            {
                int l = left == NULL? 0 : left->treeDepth();
                int d = right== NULL? 0 : right->treeDepth();
                return 1 + std::max(l, d);
            }
    

    在这种情况下,您不需要额外的参数“深度”

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-09
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 2016-01-24
      • 2012-10-12
      • 2014-08-07
      相关资源
      最近更新 更多