【问题标题】:Print all possible diameters of Binary Tree?打印所有可能的二叉树直径?
【发布时间】:2015-02-12 13:05:10
【问题描述】:

我知道如何计算树的diameter,但我想打印所有可能的树直径。举个例子:-

        1
       / \
      2   3
     /   / \
    4   5   6

以上树中所有可能的直径是:-

First:  4 2 1 3 5
Second: 4 2 1 3 6

任何有关方法的帮助都会非常有帮助。

【问题讨论】:

  • 给定直径是给定树的单个数字,所有可能的直径是什么意思?
  • 你得到了直径 5,因为实际直径是 5。
  • 从未听说过有直径的树(数据结构)。 5 是树的深度。我可能会尝试一种寻路算法
  • 不,这里的深度是 3
  • @weston 我的意思是打印那个直径中的所有节点!!!

标签: java data-structures binary-tree


【解决方案1】:

我假设您的意思是从一片叶子到另一片叶子的所有可能的最大长度路径?

递归可能是您最好的选择 - 在伪代码中类似于:

path(startNode, endNode) {
  if startNode = endNode return;
  for each possible next node n {
    add n to your path;
    path(n, endNode);
  }
}

您可以为每对叶子调用它,然后丢弃任何非最大长度的路径,或者以更智能的方式选择哪个叶子来调用它,我会留给你

【讨论】:

  • 如何找到起始节点和结束节点...因为我们只知道树的根。
【解决方案2】:

这是如何在图表中完成的:

  1. 从任何节点 n 运行 BFS 以找到最远的节点(距该节点)n'
  2. 从节点 n' 到他最远的节点 n'' 运行 BFS
  3. 从 n' 到 n'' 的路径就是树的直径

所以,看一棵树(可以展开成图表):

一条直径路径从左子树最低层的任何叶子到右子树最低层的任何叶子。

现在,由于您不会神奇地知道哪两个节点是直径的末端节点,并且您只有父子链接,因此上述算法本身就无法工作。但是,您可以使用类比来构建一个适用于树而不是图形的类。

好的,这里有一些你可以使用的快速代码(它可能不是最佳的,但它有效)

public class BinarySearchTree {
    ...

    public Iterable<T> diameter() {
        if (this.root == null) {
            return null;
        }

        Deque<T> diameterLeftPart = new ArrayDeque<T>();
        Deque<T> diameterRightPart = new ArrayDeque<T>();

        diameter(this.root.left, diameterLeftPart);
        diameter(this.root.right, diameterRightPart);

        Deque<T> diameter = new ArrayDeque<T>();

        for (Iterator<T> it = diameterLeftPart.iterator(); it.hasNext();) {
            diameter.offerLast(it.next());
        }

        diameter.offerLast(this.root.item);

        for (Iterator<T> it = diameterRightPart.descendingIterator(); it.hasNext();) {
            diameter.offerLast(it.next());
        }

        return diameter;
    }

    private void diameter(Node node, Deque<T> diameter) {
        if (node == null)  {
            return;
        }

        Deque<T> leftPart = new ArrayDeque<T>();
        Deque<T> rightPart = new ArrayDeque<T>();

        diameter(node.left, leftPart);
        diameter(node.right, rightPart);

        if (leftPart.size() > rightPart.size()) {
            diameter.addAll(leftPart);
        } else {
            diameter.addAll(rightPart);
        }

        diameter.offerLast(node.item);
    }

    ...
}

还有跑步者类:

public class TreeDiameter {
    public static void main(String[] args) {
        Tree<Integer> tree = new BinarySearchTree<Integer>();
        tree.add(5);
        tree.add(2);
        tree.add(8);
        tree.add(1);
        tree.add(3);
        tree.add(7);
        tree.add(9);
        tree.add(4);
        tree.add(6);

        for (Integer diameterNode : tree.diameter()) {
            System.out.print(diameterNode + " ");
        }
    }
}

输出如下:

4 3 2 5 8 7 6 

快速解释:

我们知道根是直径路径的组成部分。 所以,我们想得到左子树中最长的路径和右子树中最长的路径。
它们粘合在一起,形成一个直径。

使用递归调用diameter(node.left, leftPart)diameter(node.right, rightPart)leftPartrightPart 分别包含左右子树中的最长路径。

只需比较它们的大小,我们就可以知道我们将使用哪一个来构建树上一层的直径。

所以,总结一下:
递归首先一直向下到树并返回该子树中最长的路径,将其向上传递给其父级,一直到根。

【讨论】:

  • 首先它不是在家工作。遥远的意思在这里。我想你在这里谈论最深的节点?
  • 我已经编辑了我的答案。当前版本只会返回 1 个直径,但它可以让您了解如何沿着树移动:D
  • 正如我在上一条评论中所难过的,它只返回 N 个可能的最长直径中的 1 个(但始终是最长的)
  • 直径是树中最大的路径。它可以多于一个,但长度应该相等。!!!在代码中,你是如何计算直径的!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-04
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-13
  • 2019-08-12
相关资源
最近更新 更多