【问题标题】:Find the diameter of a binary tree求二叉树的直径
【发布时间】:2013-02-19 09:26:04
【问题描述】:

我试图在java中找到二叉树的直径(树中任意两个节点之间的路径长度,包含最大节点数。)。

我的代码 sn-p:

public int diametre(Node node, int d)
{
    if(node==null)
        return 0;

    lh=diametre(node.left, d);
    rh=diametre(node.right, d);

    if(lh+rh+1>d)
        d=lh+rh+1;

    return findMax(lh, rh)+1;
}

在主方法中:

 System.out.println( bst.diametre(root,0) );

逻辑: 它实际上是后订单逻辑。变量“d”指的是子树的直径(在那次迭代中)。当发现一些更大的值时,它将被更新。 'lh' 指的是:左子树的高度。 'rh' 指的是:右子树的高度。

但它给出了错误的输出。

考虑的树:

   5
  / \
 /   \
1     8
 \    /\
  \  /  \
  3  6   9

空闲输出:5

但是这段代码给出的是 3。

谁能找出问题出在哪里...

【问题讨论】:

  • 您应该进行一些调试,以找出您的代码行为成功的地方。
  • 首先,想想算法。在您的代码中,不清楚 d 代表什么。请注意,对它的赋值没有任何效果,因为它稍后不会使用。
  • 它实际上是订单后逻辑。 d 是指子树的直径(在该迭代中)。当发现更大的值时,它将更新。
  • @lok​​nath:但更新不会在任何地方引起注意。 Java 总是按值传递参数。
  • 如果你使用类实例变量,应该没问题。你也应该打印出 d 而不是返回值

标签: java tree binary-tree


【解决方案1】:
public int diameter (Node root)
{
    if (root == null) return 0;
    else return Math.max (
        diameter (root.left), 
        Math.max (
            diameter (root.right),
            height (root.left) + height (root.right) + 1));
}

public int height (Node root)
{
    if (root == null) return 0;
    else return 1 + Math.max (height (root.left), height (root.right));
}

【讨论】:

  • 最后一行应该是 root.left 而不是 root.length。
  • 我认为它的运行时间是 O(n*log(n)),因为你需要遍历每个节点,递归地查找直径并找到高度 (log(n))。您应该在节点中检索高度并计算直径
【解决方案2】:

通过从任何节点运行BFS,然后从最远的节点(在第一个 BFS 期间最后访问的节点)运行另一个 BFS,您可以找到树的直径。直径由第一个 BFS 中最后访问的节点和第一个 BFS 中最后访问的节点组成。树是二叉树这一事实并不影响算法。

编辑:在您编写的代码中更改 d 的值不会影响您传递的参数,因为原始类型在 java 中不是通过引用传递的。

【讨论】:

  • 我明白你的意思。如果这段代码是用 C++ 编写的,它会正确运行。(如果我们通过引用传递变量 d)。
  • 这个运行时间是多少?我假设它是 O(n),其中 n = # of nodes?
  • @HenleyChiu 它是线性的 - 你运行两个 BFS,每个 BFS 相对于边数是线性的(按树的节点数顺序)
【解决方案3】:

我建议如下:

public static TreeAttr calcTreeDiameter(Node root) {
    if (root == null)
        return new TreeAttr(0, 0);

    TreeAttr leftAttr = calcTreeDiameter(root.getLeft());
    TreeAttr rightAttr = calcTreeDiameter(root.getRight());

    int maxDepth = Math.max(leftAttr.depth, rightAttr.depth);
    int maxDiam = Math.max(leftAttr.diameter, rightAttr.diameter);
    maxDiam = Math.max(maxDiam, leftAttr.depth + rightAttr.depth + 1);

    return new TreeAttr(maxDiam, maxDepth + 1);
}

TreeAttr 是一个包含子树直径和深度的简单结构。两者都应该在递归中传递,因为最优值可能来自子树之一,或者来自最长路径的串联。

【讨论】:

  • 现在我看到我的解决方案等同于 Mikhail Vladimirov 的解决方案。
  • 是的......它的等价物和米哈伊尔的一个是直截了当的。
【解决方案4】:
int max=0;
public int diameter(Tree root) {
  if(root==null) return 0;
  int l=diameter(root.left);
  int r=diameter(root.right);
  max=Math.max(max,l+r+1);
  return l>r:l+1:r+1;
}

max 是最大直径。

【讨论】:

  • 这个解决方案有问题。例如,它为具有两个叶孩子的根返回错误的结果 (2)。另外,请注意未使用 max 变量。
  • @EyalSchneider 最终结果应该返回 max 作为最大直径而不是这个函数的返回值
  • 我明白了。所以你实际上有一个深度函数,它的副作用存储在最大值中。我会更改函数名称...
【解决方案5】:

算法需要 O(n)。同时计算高度和路径。

public static int findLongestPath(TreeNode root)
{
  // longest path = max (h1 + h2 + 2, longestpath(left), longestpath(right);

  int[] treeInfo = longestPathHelper(root);

  return treeInfo[0];
}

private static int[] longestPathHelper(TreeNode root)
{
  int[] retVal = new int[2];

  if (root == null)
  {
     //height and longest path are 0
     retVal[0] = 0;
     retVal[1] = 0;
  }

  int[] leftInfo = longestPathHelper(root.getLeft());
  int[] rightInfo = longestPathHelper(root.getRight());

  retVal[0] = Math.max(leftInfo[1] + rightInfo[1] + 2, Math.max(leftInfo[0], rightInfo[0]));
  retVal[1] = Math.max(leftInfo[1], rightInfo[1]) + 1;

  return retVal;
}

【讨论】:

    【解决方案6】:

    您应该使用树的高度来计算直径。创建一个 getHeight() 函数,它将树的根作为参数并返回树的高度。使用这个值并在递归的帮助下,我们可以计算出树的直径。这是它的代码.....

    计算直径的函数:-

    public static int getDiameter(BinaryTreeNode root) {        
      if (root == null)
        return 0;
    
    int rootDiameter = findHeight(root.getLeft()) + findHeight(root.getRight()) + 1;
    int leftDiameter = getDiameter(root.getLeft());
    int rightDiameter = getDiameter(root.getRight());
    
    return Math.max(rootDiameter, Math.max(leftDiameter, rightDiameter));
    }
    

    计算树高的函数:-

    public static int findHeight(BinaryTreeNode node) {
    if(node == null)
        return 0;
    
    else {
        return 1+Math.max(findHeight(node.left), findHeight(node.right));
    }
    }
    

    【讨论】:

      【解决方案7】:

      二叉树的直径,O(n),它会跟踪是否通过根节点的直径,并使用相同的高度函数来跟踪直径。

      DiameterOfTree.class

      import BinaryTree.BinaryTreeNode;
      
      public class DiameterOfBinaryTree {
          private int DIAMETER = 0;
      
          public void getDiameterOfBinaryTree(BinaryTreeNode node) {
              getHeightUtil(node, DIAMETER);
              System.out.print("\n\n Maximum Diameter of the tree is : " + DIAMETER);
          }
      
          private int getHeightUtil(BinaryTreeNode node, Integer maXValue) {
              if (node == null) {
                  return 0;
              }
      
              // Here we get the maximum value returned + 1 for each subtree left or 
              //  right 
              int leftHeight = getHeightUtil(node.getLeft(), maXValue); 
              int rightHeight = getHeightUtil(node.getRight(), maXValue);
      
              //finding the new diameter at a particular node and adding 1 to 
              //include that particular node as well: leftHeight + rightHeight + 1 
              DIAMETER = Math.max(DIAMETER, leftHeight + rightHeight + 1);
      
              return 1 + Math.max(leftHeight, rightHeight);
          }
      }
      

      Main.java

      package BinaryTree;
      
      public class Main {
      
          public static void main(String[] args) {
              //Initialise root
              BinaryTreeNode root = new BinaryTreeNode(40);
      
              //Create a binary Tree
              InitialiseBinaryTree initialiseBinaryTree = new InitialiseBinaryTree();
              initialiseBinaryTree.initialise(root);
      
              // Find the diameter of the binary tree 
              new DiameterOfBinaryTree().getDiameterOfBinaryTree(root);
          }
      
      }
      

      InitialiseBinaryTree.java

      package BinaryTree;
      
      class InitialiseBinaryTree {
          void initialise(BinaryTreeNode root) {
              BinaryTreeOperation bto = new BinaryTreeOperation();
              int[] data = {20, 50, 10, 30, 5,8, 25, 32, 33};
              for (int aData : data) {
                  bto.insertElementInBinaryTree(root, aData);
              }
          }
      }
      

      BinaryTreeOperation.java

      package BinaryTree;
      
      class BinaryTreeOperation {
          private boolean findInBinaryTree(BinaryTreeNode node, int data) {
              return node != null &&
                      (data == node.getData() || (findInBinaryTree(node.getLeft(), data) || findInBinaryTree(node.getRight(), data)));
          }
      
          void insertElementInBinaryTree(BinaryTreeNode node, int data) {
              if (node == null) {
                  new BinaryTreeNode(data);
              } else {
                  insertHelper(node, data);
              }
          }
      
          private void insertHelper(BinaryTreeNode node, int data) {
              if (node.getData() > data) {
                  if (node.getLeft() == null) {
                      node.setLeft(new BinaryTreeNode(data));
                  } else {
                      insertHelper(node.getLeft(), data);
                  }
              } else {
                  if (node.getRight() == null) {
                      node.setRight(new BinaryTreeNode(data));
                  } else {
                      insertHelper(node.getRight(), data);
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多