这是如何在图表中完成的:
- 从任何节点 n 运行 BFS 以找到最远的节点(距该节点)n'
- 从节点 n' 到他最远的节点 n'' 运行 BFS
- 从 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)、leftPart 和rightPart 分别包含左右子树中的最长路径。
只需比较它们的大小,我们就可以知道我们将使用哪一个来构建树上一层的直径。
所以,总结一下:
递归首先一直向下到树并返回该子树中最长的路径,将其向上传递给其父级,一直到根。