在二叉搜索树中查找高度

Posted

技术标签:

【中文标题】在二叉搜索树中查找高度【英文标题】:Finding height in Binary Search Tree 【发布时间】:2011-02-05 13:25:57 【问题描述】:

我想知道是否有人可以帮助我修改这个方法来找到二叉搜索树的高度。到目前为止,我的代码看起来像这样。但是,我得到的答案比实际高度大 1。但是当我从 return 语句中删除 +1 时,它比实际高度小 1。我仍然试图用递归来解决我的问题这些 BST。任何帮助将不胜感激。

public int findHeight()
    if(this.isEmpty())
        return 0;
    
    else
        TreeNode<T> node = root;
        return findHeight(node);
    

private int findHeight(TreeNode<T> aNode)
    int heightLeft = 0;
    int heightRight = 0;
    if(aNode.left!=null)
        heightLeft = findHeight(aNode.left);
    if(aNode.right!=null)
        heightRight = findHeight(aNode.right);
    if(heightLeft > heightRight)
        return heightLeft+1;
    
    else
        return heightRight+1;
    

【问题讨论】:

好吧,我通过在我的公共方法中返回 findHeight(node)-1 让它返回正确的高度。但是我只是觉得这是草率的代码,有什么改进的建议吗? 这是解决树高的正确方法吗?github.com/joeyajames/Python/issues/1 【参考方案1】:

问题在于您的基本情况。

“树的高度是从根到树中最深节点的路径长度。只有一个节点(根)的(有根)树的高度为零。” - Wikipedia

如果没有节点,你想返回 -1 而不是 0。这是因为你在末尾加了 1。

因此,如果没有节点,则返回 -1 以抵消 +1。

int findHeight(TreeNode<T> aNode) 
    if (aNode == null) 
        return -1;
    

    int lefth = findHeight(aNode.left);
    int righth = findHeight(aNode.right);

    if (lefth > righth) 
        return lefth + 1;
     else 
        return righth + 1;
    

【讨论】:

是的,这可以正常工作,而不必在我的公共方法中减去 1。我仍然对这种方法如何与递归一起工作感到困惑。我在if语句之后左右声明了int,但我不明白它们是如何通过这个方法递增的 此方法通过在基本情况下减 1 来工作,它们像其他所有给定的方法一样递增,当您深入树时,您将高度加 1。 你在哪里找到你的报价The height of a tree is the length of the path from the root to the deepest node in the tree. A (rooted) tree with only a node (the root) has a height of zero?在wiki页面中,没有这样的引用 对于那些对这种递归如何工作感到困惑的人,我制作了一个视频,首先从高层次上解释了这个过程,然后我们用一个例子来运行代码:Find height of binary tree。希望你们中的许多人会发现它很有用,在这种情况下,我们可能应该将它添加到这个答案中。 "树中节点的高度是从节点到叶子的最长简单向下路径上的边数,树的高度是它的根的高度。"来自 p。 1177 的 CLRS(第 3 版)。根据这个定义,由单个(根)节点组成的树的高度为零,这意味着这是唯一正确的答案。【参考方案2】:

二叉搜索树的高度等于number of layers - 1

在http://en.wikipedia.org/wiki/Binary_tree查看图表

你的递归很好,所以只需在根级减去一个。

另外请注意,您可以通过处理空节点来稍微清理一下函数:

int findHeight(node) 
  if (node == null) return 0;
  return 1 + max(findHeight(node.left), findHeight(node.right));

【讨论】:

我第一次尝试这种方法时,我使用了一些类似的东西,但是当我运行我的代码时,由于某种原因,我一直收到 *** 异常?我假设是因为我检查指向 null 的指针? (删除了关于 c++ 的评论,这不适用)。您的“node == null”可能没有正确终止。 Stephen,单节点树不应该是0吗?这将返回 1。 @Matthew:你是对的,但我建议他的公共函数从结果中减去一个。相反,您可以通过在基本情况下返回 -1 来“修复”递归函数。 对于单节点树的高度是0。所以对于一棵空树,高度是-1。这就是为什么当节点为 NULL 时 return -1 起作用而不是 return 0 的原因【参考方案3】:
int getHeight(Node node) 
 if (node == null) return -1;

 return 1 + Math.max(getHeight(node.left), getHeight(node.right));

【讨论】:

【参考方案4】:

在我看来,您的代码会从稍微简化中受益。与其尝试在 child 指针为空时结束递归,不如仅在 current 指针为空时结束递归空值。这使得代码更容易编写。在伪代码中,它看起来像这样:

if (node = null)
    return 0;
else
    left = height(node->left);
    right = height(node->right);
    return 1 + max(left, right);

【讨论】:

虽然不能调用空对象的方法 :) @jemfinch,他在哪里调用一个空对象,这不是基本情况吗? @jemfinch:我想我不建议这样做是件好事! 为什么返回 0 而不是 -1? @JerryCoffin 我没有做任何作业。是0还是-1?为什么?【参考方案5】:
class Solution
    public static int getHeight(Node root) 
        int height = -1;

        if (root == null) 
            return height;
         else 
            height = 1 + Math.max(getHeight(root.left), getHeight(root.right));
        

        return height;
    

【讨论】:

【参考方案6】:

对于像我这样喜欢单线解决方案的人:

public int getHeight(Node root) 
    return Math.max(root.left != null ? getHeight(root.left) : -1, 
                    root.right != null ? getHeight(root.right) : -1) 
                    + 1;

【讨论】:

【参考方案7】:

这是一种简洁且希望正确的表达方式:

  private int findHeight(TreeNode<T> aNode)
    if(aNode == null || (aNode.left == null && aNode.right == null))
      return 0;
    return Math.max(findHeight(aNode.left), findHeight(aNode.right)) + 1;
  

如果当前节点为空,则没有树。如果两个孩子都是,则只有一层,这意味着高度为 0。这使用高度的定义(斯蒂芬提到)作为层数 - 1

【讨论】:

【参考方案8】:

这是未经测试的,但相当明显是正确的:

private int findHeight(Treenode<T> aNode) 
  if (aNode.left == null && aNode.right == null) 
    return 0; // was 1; apparently a node with no children has a height of 0.
   else if (aNode.left == null) 
    return 1 + findHeight(aNode.right);
   else if (aNode.right == null) 
    return 1 + findHeight(aNode.left);
   else 
    return 1 + max(findHeight(aNode.left), findHeight(aNode.right));
  

通常,简化您的代码比弄清楚它为什么会出错更容易。这段代码很容易理解:四种可能的情况都以明显正确的方式处理得很清楚:

如果左右树都为 null,则返回 0,因为根据定义,单个节点的高度为 0。(原为 1) 如果左树或右树(但不是两者!)为空,则返回非空树的高度,加上 1 以说明当前节点的添加高度。 如果两棵树都不为空,则返回较高子树的高度,再为当前节点加一。

【讨论】:

此代码有效,并且比我所拥有的更清晰,但它仍然返回高度 +1。在我的书中,高度定义为从根到最深叶子的路径长度。因此,据我了解,包含 15、25、30、45(按此顺序)的 BST 的高度只有 3 对吗? 其实只有根节点的树的高度是0而不是1。 奇怪。如果他们真正的意思是“下降的路径”,那么它真的不应该被称为“高度”,但不幸的是,这似乎是标准术语。解决此问题的正确方法是将第一种情况(node.left == null && node.right == null)更改为返回 0。【参考方案9】:
    public void HeightRecursive()
    
        Console.WriteLine( HeightHelper(root) ); 
    

    private int HeightHelper(TreeNode node)
    
        if (node == null)
        
            return -1;
        
        else
        
            return 1 + Math.Max(HeightHelper(node.LeftNode),HeightHelper(node.RightNode));           
        
    

C# 代码。 在您的 BST 类中包含这两种方法。你需要两种方法来计算树的高度。 HeightHelper 计算它,& HeightRecursive 在 main() 中打印它。

【讨论】:

【参考方案10】:

上面给出的高度定义是不正确的。这就是深度的定义。

"一棵树中节点M的深度是从树根到M的路径的长度。一棵树的高度是多一比树中最深节点的深度。深度为 d 的所有节点都在树中的级别 d。根是级别 0 的唯一节点,它的深度为 0。”

引文:“数据结构和算法分析实用介绍” 3.2版(Java版) 克利福德·A·谢弗 计算机科学系 弗吉尼亚理工大学 弗吉尼亚州布莱克斯堡 24061

【讨论】:

【参考方案11】:
public int height()

    if(this.root== null) return 0;

    int leftDepth = nodeDepth(this.root.left, 1);
    int rightDepth = nodeDepth(this.root.right, 1);

    int height = leftDepth > rightDepth? leftDepth: rightDepth;

    return height;



private int nodeDepth(Node node, int startValue)

    int nodeDepth = 0;

    if(node.left == null && node.right == null) return startValue;
    else
        startValue++;
        if(node.left!= null)
            nodeDepth = nodeDepth(node.left, startValue);
        

        if(node.right!= null)
            nodeDepth = nodeDepth(node.right, startValue);
        
    

    return nodeDepth;

【讨论】:

【参考方案12】:

//求BST高度的函数

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

    int sum=0;
    int rheight = height(root->right);
    int lheight = height(root->left);

    if(lheight>rheight)
        sum = lheight +1;
    
    if(rheight > lheight)
        sum = rheight + 1;
    

    return sum;

【讨论】:

【参考方案13】:
int height(Node* root) 
        if(root==NULL) return -1;
        return max(height(root->left),height(root->right))+1;

取左右子树的最大高度并加1。这也处理基本情况(1个节点的树的高度为0)。

【讨论】:

【参考方案14】:

我知道我参加聚会迟到了。在查看了此处提供的精彩答案后,我认为我的答案会为这篇文章增加一些价值。尽管发布的答案令人惊叹且易于理解,但所有答案都是在线性时间内计算到 BST 的高度。我认为这可以改进,并且可以在 constant 时间内检索高度,因此写下这个答案 - 希望你会喜欢它。 让我们从 Node 类开始:

public class Node

    public Node(string key)
    
        Key = key;
        Height = 1;
        

    public int Height  get; set;  
    public string Key  get; set; 
    public Node Left  get; set; 
    public Node Right  get; set; 

    public override string ToString()
    
        return $"Key";
    

BinarySearchTree

所以你可能已经猜到这里的诀窍了……我保留节点实例变量 Height 以在添加时跟踪每个节点。 让我们转到允许我们将节点添加到 BST 中的 BinarySearchTree 类:

public class BinarySearchTree

    public Node RootNode  get; private set; 

    public void Put(string key)
    
        if (ContainsKey(key))
        
            return;
        

        RootNode = Put(RootNode, key);
    

    private Node Put(Node node, string key)
    
        if (node == null) return new Node(key);

        if (node.Key.CompareTo(key) < 0)
        
            node.Right = Put(node.Right, key);
        
        else
        
            node.Left = Put(node.Left, key);
               
        
        // since each node has height property that is maintained through this Put method that creates the binary search tree.
        // calculate the height of this node by getting the max height of its left or right subtree and adding 1 to it.        
        node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;
        return node;
    

    private int GetHeight(Node node)
    
        return node?.Height ?? 0;
    

    public Node Get(Node node, string key)
    
        if (node == null) return null;
        if (node.Key == key) return node;

        if (node.Key.CompareTo(key) < 0)
        
            // node.Key = M, key = P which results in -1
            return Get(node.Right, key);
        

        return Get(node.Left, key);
    

    public bool ContainsKey(string key)
    
        Node node = Get(RootNode, key);
        return node != null;
    

一旦我们在 BST 中添加了键值,我们就可以调用 RootNode 对象的 Height 属性,它将在 constant 时间内返回 RootNode 树的高度。 诀窍是在将新节点添加到树中时保持高度更新。 希望这可以帮助计算机科学爱好者的狂野世界!

单元测试:

[TestCase("SEARCHEXAMPLE", 6)]
[TestCase("SEBAQRCHGEXAMPLE", 6)]
[TestCase("STUVWXYZEBAQRCHGEXAMPLE", 8)]
public void HeightTest(string data, int expectedHeight)

    // Arrange.
    var runner = GetRootNode(data);

    
    //  Assert.
    Assert.AreEqual(expectedHeight, runner.RootNode.Height);


private BinarySearchTree GetRootNode(string data)

    var runner = new BinarySearchTree();
    foreach (char nextKey in data)
    
        runner.Put(nextKey.ToString());
    

    return runner;

注意:在每个 Put 操作中保持树的高度这一想法的灵感来自Algorithm (Fourth Edition) book 的第 3 章(第 399 页)中的 Size of BST 方法。

【讨论】:

【参考方案15】:

我猜这个问题可能意味着两个不同的东西......

    高度是最长分支中的节点数:-

    int calcHeight(node* root) if(root==NULL) return 0; int l=calcHeight(root->left); int r=calcHeight(root->right); if(l>r) return l+1; else return r+1;

    高度是树中节点的总数本身:

    int calcSize(node* root) if(root==NULL) return 0; return(calcSize(root->left)+1+calcSize(root->right));

【讨论】:

【参考方案16】:
public int getHeight(Node node)

    if(node == null)
        return 0;

    int left_val = getHeight(node.left);
    int right_val = getHeight(node.right);
    if(left_val > right_val)
        return left_val+1;
    else
        return right_val+1;

【讨论】:

【参考方案17】:

将 tempHeight 设置为静态变量(最初为 0)。

static void findHeight(Node node, int count)

    if (node == null) 
        return;
    
    if ((node.right == null) && (node.left == null)) 
        if (tempHeight < count) 
            tempHeight = count;

        

    

    findHeight(node.left, ++count);
    count--; //reduce the height while traversing to a different branch
    findHeight(node.right, ++count);


【讨论】:

【参考方案18】:

这是一个用 Java 编写的解决方案,虽然有点冗长但很有效..

public static int getHeight (Node root)
    int lheight = 0, rheight = 0;
    if(root==null) 
        return 0;
    
    else 
        if(root.left != null) 
            lheight = 1 + getHeight(root.left);
            System.out.println("lheight" + " " + lheight);
        
        if (root.right != null) 
            rheight = 1+ getHeight(root.right);
            System.out.println("rheight" + " " + rheight);
        
        if(root != null && root.left == null && root.right == null) 
            lheight += 1; 
            rheight += 1;
        

    
    return Math.max(lheight, rheight);
    

【讨论】:

【参考方案19】:
 int getHeight(Node* root)
 
   if(root == NULL) return -1;
   else             return max(getHeight(root->left), getHeight(root->right)) + 1;
 

【讨论】:

【参考方案20】:

这是 C# 中的解决方案

    private static int heightOfTree(Node root)
    
        if (root == null)
        
            return 0;
        

        int left = 1 + heightOfTree(root.left);
        int right = 1 + heightOfTree(root.right);

        return Math.Max(left, right);
    

【讨论】:

【参考方案21】:

对于其他阅读此内容的人!!!!

HEIGHT 定义为从根节点到叶节点的最长路径中的节点数。因此:只有一个根节点的树的高度为 1 而不是 0。

给定节点的 LEVEL 是到根的距离加 1。因此:根在级别 1,其子节点在级别 2,依此类推。

(信息由 Data Structures: Abstraction and Design Using Java, 2nd Edition,作者 Elliot B. Koffman 和 Paul A. T. Wolfgang 提供)- 我目前在哥伦布州立大学学习的数据结构课程中使用的书籍。

【讨论】:

给任何读到这个的人!!!!这个身高的定义是错误的!树的高度是从根节点到最远叶节点的的数量(如果有许多等距的叶子,则为最远的一个)。由于它是边缘,因此只有根节点的树的高度为零。转到en.wikipedia.org/wiki/Tree_(data_structure)#Definition 并阅读“节点高度”和“树的高度”。此外,Cormen 和 Weiss 算法教科书都支持这一定义。给定的级别定义是正确的。【参考方案22】:

enter image description here

根据 Thomas H. Cormen、Charles E. Leiserson、Ronald L. Rivest 和 Clifford Stein 的“算法简介”,以下是树高的定义:

a中节点的高度 树是从节点到的最长简单向下路径上的边数 一片叶子,一棵树的高度就是它的根的高度。树的高度也是 等于树中任何节点的最大深度。

以下是我的红宝石解决方案。大多数人在他们的实现中忘记了空树或单个节点树的高度。

def height(node, current_height)
  return current_height if node.nil? || (node.left.nil? && node.right.nil?)
  return [height(node.left, current_height + 1), height(node.right, current_height + 1)].max if node.left && node.right
  return height(node.left, current_height + 1) if node.left
  return height(node.right, current_height + 1)
end

【讨论】:

【参考方案23】:
int maxDepth(BinaryTreeNode root) 
    if(root == null || (root.left == null && root.right == null)) 
       return 0;
    

    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));

【讨论】:

嗨,Phat,欢迎来到 ***。您能否在答案中添加一些句子来解释中心点是什么。这样会更有帮助。 顺便说一句,你不需要检查 null root.left 和 root.right【参考方案24】:

二叉树的高度

public static int height(Node root)
    
        // Base case: empty tree has height 0
        if (root == null) 
            return 0;
        

        // recursively for left and right subtree and consider maximum depth
        return 1 + Math.max(height(root.left), height(root.right));
    

【讨论】:

【参考方案25】:

我自己也在为此苦苦挣扎,试图找到一些优雅的东西,但仍能产生正确的价值。这是我使用 Swift 的想法。请注意,height 是一个计算变量,在技术上不是一个函数。

class Node<T: Comparable>: NSObject

    var left: Node<T>? = nil
    var right: Node<T>? = nil
 
    var isLeaf: Bool  left == nil && right == nil 

    var height: Int 
        if isLeaf  return 0 
        return 1 + max(left?.height ?? 0, right?.height ?? 0)
    

此节点定义还有更多内容,但您可以看到 leftright 变量(可能为零)和 isLeaf 变量 trueleftright 都是 nil .可能不是最有效的,但我相信它会产生正确的结果。

BST 定义还有一个计算的 height 变量,当树为空时返回 -1。

class BST<T: Comparable>: NSObject

    var root: Node<T>?
    var height: Int  root != nil ? root!.height : -1 

【讨论】:

【参考方案26】:
HackerRank Day 22: Finding height in Binary Search Tree, in C#.

     static int getHeight(Node root)
        
            //Write your code here
            int countr = 0,countl=0;
            Node Leftsubtree=root.left;
            Node rightsubtree = root.right;
            int data=root.data;
             if(root==null ||(root.left == null && root.right == null))
            
                return 0;
            
             else
            
                while (Leftsubtree != null)
                
                        if(Leftsubtree.data<data)
                        
                        Leftsubtree = Leftsubtree.left==null?Leftsubtree.right:Leftsubtree.left;
                        countl++;
                        
                
                while (rightsubtree != null)
                
                    if (rightsubtree.data > data)
                    
                        rightsubtree = rightsubtree.right == null ? rightsubtree.left : rightsubtree.right;
                        countr++;
                    
    
                
            
    
            return countr >= countl ? countr : countl;
    
    
        

【讨论】:

以上是关于在二叉搜索树中查找高度的主要内容,如果未能解决你的问题,请参考以下文章

在二叉搜索树中查找地板和天花板

在二叉搜索树中查找中位数的错误

在二叉查找树中插入节点

c++ 在二叉搜索树中删除

使用递归 DFS 在二叉树中查找节点

在二叉搜索树中找到一个节点的父节点