Java 如何从路径编码重构二叉树?
假设我有以下形式的输入: (11,LL)(7,LLL)(8,R)(5,)(4,L)(13,RL)(2,LLR)(1,RRR)(4,RR)() 其中,第二个字段表示来自根节点的路径,空字段表示根节点,()表示数据结束 输出将是 级别顺序:54813134721 如何重建二叉树?请注意,有可能缺少节点。例如,LLL和L存在,但没有节点连接它们,在这种情况下,应该创建一个值为-1的节点来连接它们 到目前为止,我发现的是创建一个NodePath类,该类存储数据和路径,例如NodePath(11,LL)和字符串值。接下来,我遍历每个字符串标记。在迭代过程中,我比较路径长度并将它们存储在LinkedList中。 例如,11,LL-->7,LLL,当8出现时,它变为8,R-->11,LL-->7,LLLJava 如何从路径编码重构二叉树?,java,encoding,path,binary-search-tree,Java,Encoding,Path,Binary Search Tree,假设我有以下形式的输入: (11,LL)(7,LLL)(8,R)(5,)(4,L)(13,RL)(2,LLR)(1,RRR)(4,RR)() 其中,第二个字段表示来自根节点的路径,空字段表示根节点,()表示数据结束 输出将是 级别顺序:54813134721 如何重建二叉树?请注意,有可能缺少节点。例如,LLL和L存在,但没有节点连接它们,在这种情况下,应该创建一个值为-1的节点来连接它们 到目前为止,我发现的是创建一个NodePath类,该类存储数据和路径,例如NodePath(11,LL)和
现在,我陷入了困境,因为我不知道如何区分LLL和LLR,以及如何相应地构造二叉树。恐怕我会把LLL和LLR放在相反的位置。你可以用键值对构建一个
映射图-键值是你的路径(“LLL”)和数值(“7”)
在第二步中,迭代映射
的入口集,自上而下构建每个路径,在没有默认值“-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);
}
}
}
作为额外的(可能的)帮助,通过使用'L'和'R'作为枚举常量,您可以在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);
}
public void addValue(节点根、字符串路径字符串、int值){
列表路径=Arrays.stream(pathString.toCharArray())
.map(字符::toString)
.map(Node.Direction::valueOf)
.collect(Collectors.toList());
root.nodeWithPath(路径).setValue(值);
}
但是,如果您在学习Java的早期阶段,那么我刚刚编写的代码可能会让您感到困惑,而不是有帮助,因此请忽略它,使用传统的迭代或通过标记化进行解析:-)这里有一个基于标记的解决方案 首先,节点的基本类:
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());
}
}
公共类二进制树解析器
扩展BaseParser
{
受保护的最终BinaryTreeBuilder=新BinaryTreeBuilder();
规则endOfData()
{
返回序列(“()”,EOI);
}
规则移动()
{
首先返回(
序列('L',builder.moveLeft()),
序列('R',builder.moveRight())
);
}
规则oneNode()
{
返回序列(
'(',
序列(一个或多个(数字()),builder.setValue(匹配()),
',',
零或更多(移动()),
“)”,builder.commitNode();
);
}
规则allNodes()
{
返回联接(序列(testNot(endOfData()),oneNode())
.使用(“”)
.min(0);
}
公共规则fullTree()
{
返回序列(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();
final BinaryTreeParser=Parboiled.createParser(BinaryTreeParser.class);
final ParseRunner=new basicParserRunner(parser.fullTree());
最终parsingreult结果=runner.run(您的输入);
if(result.issucess())
tree=result.getTopStackValue();
因为grappa依赖于番石榴,而番石榴提供了一种新的颜色,所以您可以使用它来显示结果
当然,这种方法相当“复杂”;这里有一个更简单的方法:
- 创建一个
,该比较器进行如下比较:如果一个字符串较长,则该字符串大于另一个字符串;如果它们的长度相等,则应用规范排序比较器
- 创建一个
,路径作为键,节点值作为值,上面的比较器作为键比较器TreeMap
- 将节点解析到地图中
- 按顺序显示条目
但是请注意,在显示之前,您需要检查是否有根的条目,即空字符串。您是否已经有一个对象来为树节点建模?作业?至少显示预期结果。当然很有趣。好吧,在插入节点的过程中插入任何缺失的节点。自动插入的节点将获得默认值价值
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();