两个要点:让名称选择和格式成为您的朋友!您需要养成选择简单且富有表现力的变量名称以及保持代码格式整齐的习惯。
让我们从明确的步骤开始:
(1) 有一个词数据源,表示为一棵节点树。避免过多的细节,让我们设置节点类型的重要细节,并使用 getter 使节点树可用。
要提到的一个重要细节是,节点旨在保存在具有不同键值的排序二叉树中,并且任何左节点的值都严格小于该节点的值,并且值任何右节点的值都严格大于该节点的值。这有一个重要的后果,即一个节点的左子树的值都严格小于该节点的值,而右子树的值同样都严格大于该节点的值.
public class Node<K, V> {
public K key;
public V value;
public Node<K, V> left;
public Node<K, V> right;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
public Node<String, Integer> getRootNode() {
// Undetailed ...
}
(2) 需要三个主要操作:将树的节点收集到列表中的操作,对列表进行排序的操作,以及显示排序列表的操作:
public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
// Undetailed ...
}
public void sort(List<Node<String, Integer>> nodes) {
// Undetailed ...
}
public void print(List<Node<String, Integer>> nodes) {
// Undetailed ...
}
(3) 这适合在一起,例如,如下:
public void tester() {
Node<String, Integer> rootNode = getRootNode();
List<Node<String, Integer>> flatNodes = flatten(rootNode);
sort(flatNodes);
print(flatNodes)l
}
(4)剩下的就是详细介绍几种方法。我们从“扁平化”开始。这将作为递归操作来实现。而且,由于为平面列表传递存储更简单,因此该方法将分为两部分,一部分分配存储,另一部分进行递归处理。这种传递存储集合的技术是此类处理的典型。
'flatten' 利用节点的排序属性相对于节点的左节点和节点的右节点:'flatten' 将左子树的所有值添加到平面节点列表中,然后是节点, 后跟右子树的所有值。
public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
List<Node<String, Integer>> flatNodes = new ArrayList<Node<String, Integer>>();
flatten(rootNode, flatNodes);
return flatNodes;
}
public void flatten(Node<String, Integer> node, List<Node<String, Integer>> flatNodes) {
if ( node == null ) {
return;
}
flatten(node.left, flatNodes);
flatNodes.add(node);
flatten(node.right, flatNodes);
}
(5) 以清晰为代价,可以通过移动空检查来提高效率。对于完全平衡的树,这将避免大约 2/3 的递归调用,这是相当不错的减少。这仅在节点数量很高的情况下才重要。无论如何,一个好的编译器很可能会以这种方式转换代码。
public List<Node<String, Integer>> flatten(Node<String, Integer> rootNode) {
List<Node<String, Integer>> flatNodes = new ArrayList<Node<String, Integer>>();
if ( rootNode != null ) {
flatten(rootNode, flatNodes);
}
return flatNodes;
}
public void flatten(Node<String, Integer> node, List<Node<String, Integer>> flatNodes) {
Node<String, Integer> leftNode = node.left;
if ( leftNode != null ) {
flatten(leftNode, flatNodes);
}
flatNodes.add(node);
Node<String, Integer> rightNode = node.right;
if ( rightNode != null ) {
flatten(rightNode, flatNodes);
}
}
(6) 下一位是对平面节点列表进行排序。提出了两种实现,一种使用 lambdas 的更现代的实现,另一种使用显式比较器的旧式实现。编写比较以生成从最小到最大排序的列表。要反转排序顺序,请交换比较顺序。
public void sort(List<Node<String, Integer>> nodes) {
Collections.sort(
nodes,
((Node<String, Integer> n1, Node<String, Integer> n2) -> Integer.compare(n1.value, n2.value)) );
}
public static final Comparator<Node<String, Integer>> NODE_COMPARATOR =
new Comparator<Node<String, Integer>>() {
public int compare(Node<String, Integer> n1, Node<String, Integer> n2) {
return Integer.compare(n1.value, n2.value);
}
};
public void sort(List<Node<String, Integer>> nodes) {
Collections.sort(nodes, NODE_COMPARATOR);
}
(7) 打印生成的排序列表留作练习。