假设我输入以下表格:
(11,LL)(7,LLL)(8,R)(5,)(4,L)(13,RL)(2,LLR)(1,RRR)(4,RR)()< / p>
其中第二个字段表示来自根节点的路径,空字段表示根节点,()表示数据的结束。
输出将是 levelorder:5 4 8 11 13 4 7 2 1
如何重建二叉树?请注意,可能存在节点丢失的可能性。例如,存在LLL和L,但没有节点连接它们,对于这种情况,应该创建值为-1的节点来连接它们。
到目前为止我想到的是创建一个存储数据和路径的NodePath类,例如NodePath(11,LL)都是字符串值。接下来,我遍历每个字符串标记。在迭代期间,我比较路径长度并将它们存储在LinkedList中。 例如。 11,LL - &gt; 7,LLL,当8到达时,它变为8,R - > 11,LL - &gt; 7,LLL
现在,这就是我被困住的地方,因为我不知道如何区分LLL和LLR以及如何相应地构造二叉树。我担心我会把LLL和LLR放在相反的位置。
答案 0 :(得分:1)
您可以使用键值对构建Map
- 键是您的路径(“LLL”)并为数字(“7”)赋值。
在第二步中迭代Map
的EntrySet并自上而下构建每个路径,创建默认值为“-1”的新节点,其中没有任何节点,并且尽可能使用现有节点。
答案 1 :(得分:1)
这是一个有趣的问题。我建议让树节点能够跟踪构建节点的路径。我将忽略解码字符串的所有代码并跳转到构建的核心:
class Node {
public enum Direction {
L, R;
}
private int value = -1;
private EnumMap<Direction, Node> children = new EnumMap<>(Direction.class);
public Node nodeWithPath(List<Direction> path) {
if (path.isEmpty()) {
return this;
} else {
Direction direction = path.remove(0);
if (!children.containsKey(direction))
children.put(direction, new Node());
return children.get(direction).nodeWithPath(path);
}
}
}
当您解码以下指令时,这很简单:
root.nodeWithPath(path).setValue(value);
作为(可能的)帮助的另一部分,通过使用&#39; L&#39;和&#39; R&#39;作为枚举常量,您可以从字符串中简单地在Java 8中创建路径:
public void addValue(Node root, String pathString, int value) {
List<Direction> path = Arrays.stream(pathString.toCharArray())
.map(Character::toString)
.map(Node.Direction::valueOf)
.collect(Collectors.toList());
root.nodeWithPath(path).setValue(value);
}
然而,如果您在学习Java的过程中处于早期状态,那么我刚刚编写的代码可能会比帮助更加混乱,因此可以随意忽略它并使用传统迭代或通过标记化解析: - )
答案 2 :(得分:0)
以下是基于grappa的解决方案。
首先,节点的基本类:
public final class BinaryTreeNode
{
private int value = -1;
private BinaryTreeNode left = null;
private BinaryTreeNode right = null;
public int getValue()
{
return value;
}
public BinaryTreeNode getLeft()
{
return left;
}
public BinaryTreeNode getRight()
{
return right;
}
public void setValue(final int value)
{
this.value = value;
}
public void setLeft(final BinaryTreeNode left)
{
this.left = left;
}
public void setRight(final BinaryTreeNode right)
{
this.right = right;
}
}
现在是构建器类:
public final class BinaryTreeBuilder
{
private final BinaryTreeNode root = new BinaryTreeNode();
private BinaryTreeNode current = root;
private int nodeValue;
public BinaryTreeNode getRoot()
{
return root;
}
public boolean setValue(final String match)
{
nodeValue = Integer.parseInt(match);
return true;
}
public boolean moveLeft()
{
BinaryTreeNode node = current.getLeft();
if (left == null) {
node = new BinaryTreeNode();
current.setLeft(node);
}
current = node;
return true;
}
public boolean moveRight()
{
BinaryTreeNode node = current.getRight();
if (right == null) {
node = new BinaryTreeNode();
current.setRight(node);
}
current = node;
return true;
}
public boolean commitNode()
{
current.setValue(nodeValue);
current = root;
return true;
}
}
最后是解析器:
public class BinaryTreeParser
extends BaseParser<BinaryTreeNode>
{
protected final BinaryTreeBuilder = new BinaryTreeBuilder();
Rule endOfData()
{
return sequence("()", EOI);
}
Rule moves()
{
return firstOf(
sequence('L', builder.moveLeft()),
sequence('R', builder.moveRight())
);
}
Rule oneNode()
{
return sequence(
'(',
sequence(oneOrMore(digit()), builder.setValue(match())),
',',
zeroOrMore(moves()),
')', builder.commitNode();
);
}
Rule allNodes()
{
return join(sequence(testNot(endOfData()), oneNode())
.using(' ')
.min(0);
}
public Rule fullTree()
{
return sequence(allNodes(), endOfData(), push(builder.getRoot());
}
}
现在你只需要运行解析器并收集结果:
final BinaryTreeParser parser = Parboiled.createParser(BinaryTreeParser.class);
final ParseRunner<BinaryTreeNode> runner = new BasicParseRunner<>(parser.fullTree());
final ParsingResult<BinaryTreeNode> result = runner.run(yourInput);
if (result.isSuccess())
tree = result.getTopStackValue();
由于格拉巴依赖于番石榴而Guave提供BinaryTreeTraverser
,您可以使用它来显示结果。
当然,这种方法相当复杂&#34 ;;这是一个更简单的问题:
Comparator<String>
,其比较如下:如果字符串更长,则字符串大于另一个字符串;如果它们的长度相等,则适用规范排序; TreeMap<String, Integer>
,路径为键,节点值为值,上面的比较器为关键比较器; 但是请注意,您需要在显示之前检查您是否有根条目,即空字符串。