有一个好的可用(标准Java)数据结构来表示Java中的树吗?
具体来说,我需要代表以下内容:
任何节点上的树都可以有任意数量的子级
每个节点(在根之后)只是一个字符串(其子节点也是字符串)
我需要能够让所有的子节点(某种列表或字符串数组)都得到一个表示给定节点的输入字符串。
是否有可用的结构来解决这个问题,或者我是否需要创建自己的结构(如果是这样的话,实现建议会很好)。
如果您正在使用Java 8,并且希望通过流、过滤等方式遍历节点,那么您可能需要查看榴莲Github. COM/DeField/榴莲。
您可以使用此API:sourceforge.net/p/treeds4j
在这里:
public class Tree {
private Node root;
public Tree(T rootData) {
root = new Node();
root.data = rootData;
root.children = new ArrayList>();
}
public static class Node {
private T data;
private Node parent;
private List> children;
}
}
这是一个基本的树结构,可以用于String或任何其他对象。实现简单的树来做您需要的事情是相当容易的。
您需要添加的只是用于添加到、移除、遍历和构造函数的方法。Node是Tree的基本组成部分。
如果要从子节点获取路径,也可能需要父字段。
是的,如果你想上树,你需要一个家长参考。
严格来说,没有必要使用Tree类,因为每个Node本身都可以看作一棵树。
@Joa,我喜欢有一个包含根的结构。可以将方法添加到树类中,这样可以更合理地调用树而不是单个节点。
@贾斯汀:例如?这是一个诚实的问题:我想不出一个对整棵树都有意义的方法,而对一个子树却没有意义。
@约阿希姆,我想我喜欢抽象出这棵树的表现形式。可以使用基于数组的表示交换节点结构。这就是为什么我不喜欢公开一个节点。
@Justin:如果不公开节点,如何编写一个方法来表示"将该节点作为子节点添加到另一个节点"?只有在您实现一些ADT并使用树内部语言(例如,在TreeSet中)时,该参数才有意义。但我理解这个问题是关于一个实际的树广告。
@Joa,我通常在一些内部代码中使用树。所以,这就是我写这篇文章的方式。习惯的力量。而且,我认为这是一个很好的实践。我不觉得你失去了任何东西的外部树结构。而且,如果您使用的是一个具体的树,而不仅仅是节点,就更容易理解了。
我同意@joa的观点,认为不需要树类。我更喜欢在代码中显式地保留树的递归性质,不添加单独的树类,并且一致地使用节点类。相反,如果需要清楚地表明您正在处理树的根节点,那么我将变量命名为"tree"或"root"。
要节省40分钟,请在此处使用更完整的示例
@Joa"严格来说树类课程是不必要的"在什么意义上?从语义上讲(从数据结构的角度来看),您的注释不正确。根节点只是树概念的众多实现之一。例如,一个人不应该有一个类dog并说cat=new dog(),因为一只狗(为了我们所关心的)和猫做同样的事情。
@Elmarce:我之所以说没有严格必要,是因为它没有添加任何操作,您也不能在任何给定的子树(也就是"节点")上执行这些操作。如果您选择使用树类(当然这是一个完全有效的选择),那么您所要做的就是限制可以将其视为树的内容。如果我不区分一棵树和一个节点,那么我就可以把每一个子树都视为一棵树。这可能不是您的特定域所要求的,所以您可能仍然想要一个树类。
@琼,我四岁大,完全同意你的看法。不上树课。
为我分离类(接口)。Tree有isEmpty()和size(),TreeNode有childCount()、descendentCount()和toTree()。我发现这是对实际对象的更清晰的描述,并且在编写实现(而不是公共链接版本)时提供了更大的灵活性。不确定如果只有一个节点类,如何表示空树?
@Barney,这也是一个有趣的实现……但即使是那些Tree类方法也可以用某种方式在TreeNode类中实现。size()与childCount()有什么不同?对于isEmpty(),如果根TreeNode为null则为空,因此可以用空校验代替isEmpty()方法。
当然,@scott scooter weidenkopf,你可以用任何一种方式。但是,举例来说,为了使一棵树变平,我发现array = new Object[tree.size()]比array = new Object[(node == null ? 0 : (node.descendentCount() + 1))]可读得多。
@如果您希望它是AVL树,则需要一个节点类,因为旋转树可以更改根。(举个例子)
还有另一种树结构:
public class TreeNode implements Iterable> {
T data;
TreeNode parent;
List> children;
public TreeNode(T data) {
this.data = data;
this.children = new LinkedList>();
}
public TreeNode addChild(T child) {
TreeNode childNode = new TreeNode(child);
childNode.parent = this;
this.children.add(childNode);
return childNode;
}
// other features ...
}
样品使用情况:
TreeNode root = new TreeNode("root");
{
TreeNode node0 = root.addChild("node0");
TreeNode node1 = root.addChild("node1");
TreeNode node2 = root.addChild("node2");
{
TreeNode node20 = node2.addChild(null);
TreeNode node21 = node2.addChild("node21");
{
TreeNode node210 = node20.addChild("node210");
}
}
}
奖金见完全羽化的树:
迭代器
搜索
爪哇/ C
https://github.com/gt4dev/yet-another-tree-structure
刚发现你的图书馆非常有用。谢谢您。但我想知道如何根据父级和子级之间的引用关系动态填充树结构。举个例子,我有一个会员1赞助另一个会员2,会员2赞助会员3等等。已经有了表记录关系,但不确定是否可以使用您的库将它们填充到树中。
截至2016年,该链接不包含源文件或下载
在我看来,这个答案三年后以上的高分答案,是更干净的一个。但是,我将用arraylist替换linkedlist。
我会为孩子们准备一套。
我可能是错的,但在这个实现中,您必须在每次调用next()之前调用hasNext(),以获得有效的结果。这不是Iterator规范的一部分。
实际上,JDK中实现了一个非常好的树结构。
看看javax.swing.tree、treemodel和treenode。它们被设计为与JTreePanel一起使用,但实际上,它们是一个非常好的树实现,并且没有什么能阻止您在没有Swing接口的情况下使用它。
注意,对于Java 9,您可能不希望使用这些类,因为它们将不存在于"紧凑配置文件"中。
是的,我以前用过,他们会做你想从树上做的任何事。我能想到的唯一缺点是它们各自实现类的名称的长度:defaultTreeModel和defaultMutableTreeNode。冗长,但我想这并不重要。
解决这个问题的好方法是创建两个静态方法newModel()和newNode(),然后静态导入它们。
我将避免在与Swing无关的函数上使用Swing库。这是糟糕的编码实践。你永远不知道Swing是如何实现它们的树的,它们的依赖关系是什么,这在未来会如何改变。Swing不是实用程序库,而是UI库。
我认为糟糕的编码实践有点苛刻。
JavaX.SWECUT.TeReTeMeDell是一个公共接口(恰好像Java.UTI.List),它不会有不兼容的更改。另外一个优点是,您可以在开发时轻松调试/可视化树。
@杰索普,我知道现在发表评论已经很晚了。但我同意你的观点,使用图书馆对初学者来说可能是一种不好的做法。
您应该避免使用这些类,因为将来您的代码可能必须在紧凑的概要文件上运行。在这些概要文件中,Swing包中的类不可用。(参见Oracle、COM/TeaTeWorks/Java/Ent/Realth/Tea//Helip;)。我已经不得不重构那些除了使用TreeModel和TreeNode之外根本没有用户界面的代码。这是一个应该避免的风险…
@汤塞德尔似乎是一个合理的观点,更新了答案让人们真正看到,我怀疑评论中的信息并没有真正得到太多关注。
"没有什么能阻止你在没有Swing界面的情况下使用它",直到你意识到你的android apk充斥着你只需要一个或两个类的库,占总大小的50%…
@弗朗玛佐亚更有理由在JDK中使用某些运输工具:)..当然,我也不知道安卓飞船是否在运行时摇摆:(
不,事实上,它甚至不能在Android上工作…我认为在某些情况下使用第三方库是可以的,但是只为这个添加Swing是不合理的,即使它是一个桌面项目。
这个怎么样?
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
/**
* @author ycoppel@google.com (Yohann Coppel)
*
* @param
* Object's type in the tree.
*/
public class Tree {
private T head;
private ArrayList> leafs = new ArrayList>();
private Tree parent = null;
private HashMap> locate = new HashMap>();
public Tree(T head) {
this.head = head;
locate.put(head, this);
}
public void addLeaf(T root, T leaf) {
if (locate.containsKey(root)) {
locate.get(root).addLeaf(leaf);
} else {
addLeaf(root).addLeaf(leaf);
}
}
public Tree addLeaf(T leaf) {
Tree t = new Tree(leaf);
leafs.add(t);
t.parent = this;
t.locate = this.locate;
locate.put(leaf, t);
return t;
}
public Tree setAsParent(T parentRoot) {
Tree t = new Tree(parentRoot);
t.leafs.add(this);
this.parent = t;
t.locate = this.locate;
t.locate.put(head, this);
t.locate.put(parentRoot, t);
return t;
}
public T getHead() {
return head;
}
public Tree getTree(T element) {
return locate.get(element);
}
public Tree getParent() {
return parent;
}
public Collection getSuccessors(T root) {
Collection successors = new ArrayList();
Tree tree = getTree(root);
if (null != tree) {
for (Tree leaf : tree.leafs) {
successors.add(leaf.head);
}
}
return successors;
}
public Collection> getSubTrees() {
return leafs;
}
public static Collection getSuccessors(T of, Collection> in) {
for (Tree tree : in) {
if (tree.locate.containsKey(of)) {
return tree.getSuccessors(of);
}
}
return new ArrayList();
}
@Override
public String toString() {
return printTree(0);
}
private static final int indent = 2;
private String printTree(int increment) {
String s ="";
String inc ="";
for (int i = 0; i < increment; ++i) {
inc = inc +"";
}
s = inc + head;
for (Tree child : leafs) {
s +="
" + child.printTree(increment + indent);
}
return s;
}
}
如何在使用此类对象创建的树上实现DFS?
如何使用该类实现删除叶?
头场的作用是什么?
如果这个类有一些文档,那就太好了。我不太明白像setAsParent或getHead这样的方法会做什么,现在我真的可以在树数据结构上获得一些帮助。即使文档的原始源也没有注释。
我写了一个处理普通树的小库。它比秋千轻得多。我也有一个Maven项目。
我现在正在使用它,工作得很出色。必须为我自己的定制显著地更改源代码,但这是一个很好的起点。谢谢!
public class Tree {
private List leaves = new LinkedList();
private Tree parent = null;
private String data;
public Tree(String data, Tree parent) {
this.data = data;
this.parent = parent;
}
}
显然,您可以添加实用程序方法来添加/删除子项。
您应该首先定义树是什么(对于域),最好先定义接口。并不是所有的树结构都是可修改的,能够添加和删除节点应该是一个可选的特性,所以我们为此做了一个额外的接口。
不需要创建保存值的节点对象,事实上,我认为这是大多数树实现中的一个主要设计缺陷和开销。如果你看Swing,TreeModel没有节点类(只有DefaultTreeModel使用TreeNode,因为它们不是真正需要的。
public interface Tree extends Serializable {
List getRoots ();
N getParent (N node);
List getChildren (N node);
}
可变树结构(允许添加和删除节点):
public interface MutableTree extends Tree {
boolean add (N parent, N node);
boolean remove (N node, boolean cascade);
}
考虑到这些接口,使用树的代码不必太关心树是如何实现的。这允许您使用通用实现和专用实现,通过将函数委托给另一个API来实现树。
示例:文件树结构
public class FileTree implements Tree {
@Override
public List getRoots() {
return Arrays.stream(File.listRoots()).collect(Collectors.toList());
}
@Override
public File getParent(File node) {
return node.getParentFile();
}
@Override
public List getChildren(File node) {
if (node.isDirectory()) {
File[] children = node.listFiles();
if (children != null) {
return Arrays.stream(children).collect(Collectors.toList());
}
}
return Collections.emptyList();
}
}
示例:通用树结构(基于父/子关系):
public class MappedTreeStructure implements MutableTree {
public static void main(String[] args) {
MutableTree tree = new MappedTreeStructure<>();
tree.add("A","B");
tree.add("A","C");
tree.add("C","D");
tree.add("E","A");
System.out.println(tree);
}
private final Map nodeParent = new HashMap<>();
private final LinkedHashSet nodeList = new LinkedHashSet<>();
private void checkNotNull(N node, String parameterName) {
if (node == null)
throw new IllegalArgumentException(parameterName +" must not be null");
}
@Override
public boolean add(N parent, N node) {
checkNotNull(parent,"parent");
checkNotNull(node,"node");
// check for cycles
N current = parent;
do {
if (node.equals(current)) {
throw new IllegalArgumentException(" node must not be the same or an ancestor of the parent");
}
} while ((current = getParent(current)) != null);
boolean added = nodeList.add(node);
nodeList.add(parent);
nodeParent.put(node, parent);
return added;
}
@Override
public boolean remove(N node, boolean cascade) {
checkNotNull(node,"node");
if (!nodeList.contains(node)) {
return false;
}
if (cascade) {
for (N child : getChildren(node)) {
remove(child, true);
}
} else {
for (N child : getChildren(node)) {
nodeParent.remove(child);
}
}
nodeList.remove(node);
return true;
}
@Override
public List getRoots() {
return getChildren(null);
}
@Override
public N getParent(N node) {
checkNotNull(node,"node");
return nodeParent.get(node);
}
@Override
public List getChildren(N node) {
List children = new LinkedList<>();
for (N n : nodeList) {
N parent = nodeParent.get(n);
if (node == null && parent == null) {
children.add(n);
} else if (node != null && parent != null && parent.equals(node)) {
children.add(n);
}
}
return children;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
dumpNodeStructure(builder, null,"-");
return builder.toString();
}
private void dumpNodeStructure(StringBuilder builder, N node, String prefix) {
if (node != null) {
builder.append(prefix);
builder.append(node.toString());
builder.append('
');
prefix =" " + prefix;
}
for (N child : getChildren(node)) {
dumpNodeStructure(builder, child, prefix);
}
}
}
当我执行tree.a d d("a","b");tree.add("a","c");tree.add("c","d");tree.add("e","a");e是a的父级时,我面临着一个问题。我们该怎么做?
嗨,桑尼克,上面的代码中有一个错误,导致最后一个关系无法添加。现在已经修复了,我还添加了非空检查和(更重要的是):循环检查,以防止违反树结构(将代码或其祖先之一作为子代添加到自身中)。谢谢你的提示!
我修复了这个bug如果有人想修复这个bug,你要做的就是看看add方法是否返回false,如果返回false,只需创建一个temp new linkedhashset并将树的节点列表克隆到其中,你就可以清除树,添加上一步没有添加的父节点,然后将所有temp node添加回pa。租树…不过,谢谢你的结构!
只需从接口中删除那些无用的公共修饰符。
如何从中生成JSON数组
没有答案提到过简化的工作代码,所以这里是:
public class TreeNodeArray {
public T value;
public final java.util.List> kids = new java.util.ArrayList>();
}
您可以使用Java的任何XML API作为文档和节点,因为XML是一个带字符串的树结构。
好主意,我们可以使用内存中的XML模式,使用dom4j+jaxen xpath来搜索节点。
在Java中有一些树数据结构,例如JDK Swing中的Debug ToMababeleReNoDE、斯坦福解析器包中的树和其他玩具代码。但这些都不足以满足一般用途。
Java树项目试图在Java中提供另一种通用树数据结构。这个和其他的区别是
完全免费。你可以在任何地方使用它(家庭作业除外:p)
小而一般。我将数据结构的所有内容都放在一个类文件中,这样就很容易复制/粘贴。
不仅仅是玩具。我知道几十个Java树代码,只能处理二叉树或有限的操作。这棵树结比那要多得多。它提供了不同的访问节点的方法,如预排序、后排序、breadthfirst、leaves、根路径等,并且还提供了迭代器以充分利用这些方法。
将添加更多的实用程序。我愿意增加更多的操作来使这个项目更全面,特别是如果你通过GitHub发送一个请求。
blog.pengyifan.com/yet-another-java-树结构
按照加雷斯的回答,查看默认可变树型。它不是通用的,但在其他方面似乎符合这个要求。即使它在javax.swing包中,它也不依赖于任何awt或swing类。实际上,源代码实际上有注释// ISSUE: this class depends on nothing in AWT -- move to java.util?
如果你在做白板编码,面试,甚至只是打算用一棵树,这些都有点冗长。
还应该说,树不在其中的原因,比如说,Pair(可以这样说),是因为您应该使用它将数据封装在类中,最简单的实现如下:
/***
/* Within the class that's using a binary tree for any reason. You could
/* generalize with generics IFF the parent class needs different value types.
*/
private class Node {
public String value;
public Node[] nodes; // Or an Iterable nodes;
}
这真的适用于任意宽度的树。
如果需要二叉树,通常更容易与命名字段一起使用:
private class Node { // Using package visibility is an option
String value;
Node left;
Node right;
}
或者如果你想要一个特里尔:
private class Node {
String value;
Map nodes;
}
现在你说你想要
to be able to get all the children (some sort of list or array of Strings) given an input string representing a given node
听起来像你的家庭作业。不过,既然我有理由确定现在已经过了最后期限…
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class kidsOfMatchTheseDays {
static private class Node {
String value;
Node[] nodes;
}
// Pre-order; you didn't specify.
static public List list(Node node, String find) {
return list(node, find, new ArrayList(), false);
}
static private ArrayList list(
Node node,
String find,
ArrayList list,
boolean add) {
if (node == null) {
return list;
}
if (node.value.equals(find)) {
add = true;
}
if (add) {
list.add(node.value);
}
if (node.nodes != null) {
for (Node child: node.nodes) {
list(child, find, list, add);
}
}
return list;
}
public static final void main(String... args) {
// Usually never have to do setup like this, so excuse the style
// And it could be cleaner by adding a constructor like:
// Node(String val, Node... children) {
// value = val;
// nodes = children;
// }
Node tree = new Node();
tree.value ="root";
Node[] n = {new Node(), new Node()};
tree.nodes = n;
tree.nodes[0].value ="leftish";
tree.nodes[1].value ="rightish-leafy";
Node[] nn = {new Node()};
tree.nodes[0].nodes = nn;
tree.nodes[0].nodes[0].value ="off-leftish-leaf";
// Enough setup
System.out.println(Arrays.toString(list(tree, args[0]).toArray()));
}
}
这样你就可以像:
$ java kidsOfMatchTheseDays leftish
[leftish, off-leftish-leaf]
$ java kidsOfMatchTheseDays root
[root, leftish, off-leftish-leaf, rightish-leafy]
$ java kidsOfMatchTheseDays rightish-leafy
[rightish-leafy]
$ java kidsOfMatchTheseDays a
[]
public abstract class Node {
List children;
public List getChidren() {
if (children == null) {
children = new ArrayList<>();
}
return chidren;
}
}
简单易用。要使用它,请扩展它:
public class MenuItem extends Node {
String label;
String href;
...
}
由于问题要求提供可用的数据结构,因此可以从列表或数组构造树:
Object[] tree = new Object[2];
tree[0] ="Hello";
{
Object[] subtree = new Object[2];
subtree[0] ="Goodbye";
subtree[1] ="";
tree[1] = subtree;
}
instanceof可用于确定元素是子树还是终端节点。
相当丑陋。如果您的数据对象可能是数组和列表,那么它就不起作用。
我同意这很难看。Objects要么是叶对象(例如,Strings),要么是分支(由数组表示)。它确实有效:该代码将被编译,并创建一个String的小树。
例如:
import java.util.ArrayList;
import java.util.List;
/**
*
* @author X2
*
* @param
*/
public class HisTree
{
private Node root;
public HisTree(T rootData)
{
root = new Node();
root.setData(rootData);
root.setChildren(new ArrayList>());
}
}
class Node
{
private T data;
private Node parent;
private List> children;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public List> getChildren() {
return children;
}
public void setChildren(List> children) {
this.children = children;
}
}
我写了一个基于"hashmap"的小"treemap"类,它支持添加路径:
import java.util.HashMap;
import java.util.LinkedList;
public class TreeMap extends LinkedHashMap> {
public void put(T[] path) {
LinkedList list = new LinkedList<>();
for (T key : path) {
list.add(key);
}
return put(list);
}
public void put(LinkedList path) {
if (path.isEmpty()) {
return;
}
T key = path.removeFirst();
TreeMap val = get(key);
if (val == null) {
val = new TreeMap<>();
put(key, val);
}
val.put(path);
}
}
它可以用于存储"t"(通用)类型的树,但不支持在其节点中存储额外的数据。如果您有这样的文件:
root, child 1
root, child 1, child 1a
root, child 1, child 1b
root, child 2
root, child 3, child 3a
然后,您可以通过执行以下操作使其成为树:
TreeMap root = new TreeMap<>();
Scanner scanner = new Scanner(new File("input.txt"));
while (scanner.hasNextLine()) {
root.put(scanner.nextLine().split(","));
}
你会得到一棵漂亮的树。它应该很容易适应你的需要。
在过去,我只是使用了一个嵌套的映射。这是我今天用的,很简单,但它符合我的需要。也许这对另一个有用。
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* Created by kic on 16.07.15.
*/
public class NestedMap {
private final Map root = new HashMap<>();
public NestedMap put(K key) {
Object nested = root.get(key);
if (nested == null || !(nested instanceof NestedMap)) root.put(key, nested = new NestedMap<>());
return (NestedMap) nested;
}
public Map.Entry put(K key, V value) {
root.put(key, value);
return (Map.Entry) root.entrySet().stream().filter(e -> ((Map.Entry) e).getKey().equals(key)).findFirst().get();
}
public NestedMap get(K key) {
return (NestedMap) root.get(key);
}
public V getValue(K key) {
return (V) root.get(key);
}
@JsonValue
public Map getRoot() {
return root;
}
public static void main(String[] args) throws Exception {
NestedMap test = new NestedMap<>();
test.put("a").put("b").put("c", 12);
Map.Entry foo = test.put("a").put("b").put("d", 12);
test.put("b", 14);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(test));
foo.setValue(99);
System.out.println(mapper.writeValueAsString(test));
System.out.println(test.get("a").get("b").getValue("d"));
}
}
// TestTree.java
// A simple test to see how we can build a tree and populate it
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class TestTree extends JFrame {
JTree tree;
DefaultTreeModel treeModel;
public TestTree( ) {
super("Tree Test Example");
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void init( ) {
// Build up a bunch of TreeNodes. We use DefaultMutableTreeNode because the
// DefaultTreeModel can use it to build a complete tree.
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode subroot = new DefaultMutableTreeNode("SubRoot");
DefaultMutableTreeNode leaf1 = new DefaultMutableTreeNode("Leaf 1");
DefaultMutableTreeNode leaf2 = new DefaultMutableTreeNode("Leaf 2");
// Build our tree model starting at the root node, and then make a JTree out
// of it.
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
// Build the tree up from the nodes we created.
treeModel.insertNodeInto(subroot, root, 0);
// Or, more succinctly:
subroot.add(leaf1);
root.add(leaf2);
// Display it.
getContentPane( ).add(tree, BorderLayout.CENTER);
}
public static void main(String args[]) {
TestTree tt = new TestTree( );
tt.init( );
tt.setVisible(true);
}
}
请不要只是丢弃代码-解释它做了什么,特别是为什么它比所有其他答案都不同(更好)。
Java中没有特定的数据结构,适合您的需求。您的需求非常具体,因此需要设计自己的数据结构。查看您的需求,任何人都可以说您需要某种具有特定功能的n元树。您可以按以下方式设计数据结构:
树节点的结构类似于节点中的内容,子节点列表类似于:类节点字符串值;列出子级;
您需要检索给定字符串的子级,因此您可以有两种方法:1:节点searchnode(string str),将返回与给定输入值相同的节点(使用bfs进行搜索)2:列表get children(string str):此方法将在内部调用searchnode以获取具有相同字符串的节点,然后创建al的列表l字符串值的子级和返回。
您还需要在树中插入一个字符串。您必须编写一个方法,比如void insert(字符串父级,字符串值):这将再次搜索值等于父级的节点,然后您可以创建具有给定值的节点,并将其添加到找到的父级的子级列表中。
我建议您在类node string value;list children;中编写节点的结构,在另一个nodeUtils类中编写所有其他方法,如search、insert和getchildren,这样您也可以通过树根在特定的树上执行操作,例如:class nodeUtils公共静态节点搜索(node root,string value)//执行bfs并返回node
您可以使用ApacheJMeter中包含的hashtree类,它是雅加达项目的一部分。
hashtree类包含在包org.apache.jorphan.collections中。虽然这个包不是在JMeter项目之外发布的,但是您可以很容易地获得它:
1)下载JMeter源。
2)创建新包。
3)复制到it/src/jorphan/org/apache/jorphan/collections/。除data.java外的所有文件
4)也复制/src/jorphan/org/apache/jorphan/util/jorphanutils.java
5)hashtree可以使用。
我编写了一个树库,它可以很好地使用Java8,并且没有其他依赖项。它还提供了对函数式编程的一些想法的松散解释,并允许您映射/过滤/修剪/搜索整个树或子树。
网址:https://github.com/rutledgepaulv/prune
这个实现在索引方面没有做任何特殊的工作,我也没有偏离递归,所以使用大型树时性能可能会降低,您可能会破坏堆栈。但是如果你只需要一棵小到中等深度的直截了当的树,我认为它足够好用了。它提供了一个健全(基于值)的平等定义,它还具有一个ToString实现,让您可以可视化树!
请检查下面的代码,其中我使用了树数据结构,而不使用集合类。代码可能有缺陷/改进,但请使用此代码仅供参考。
package com.datastructure.tree;
public class BinaryTreeWithoutRecursion {
private TreeNode root;
public BinaryTreeWithoutRecursion (){
root = null;
}
public void insert(T data){
root =insert(root, data);
}
public TreeNode insert(TreeNode node, T data ){
TreeNode newNode = new TreeNode<>();
newNode.data = data;
newNode.right = newNode.left = null;
if(node==null){
node = newNode;
return node;
}
Queue> queue = new Queue>();
queue.enque(node);
while(!queue.isEmpty()){
TreeNode temp= queue.deque();
if(temp.left!=null){
queue.enque(temp.left);
}else
{
temp.left = newNode;
queue =null;
return node;
}
if(temp.right!=null){
queue.enque(temp.right);
}else
{
temp.right = newNode;
queue =null;
return node;
}
}
queue=null;
return node;
}
public void inOrderPrint(TreeNode root){
if(root!=null){
inOrderPrint(root.left);
System.out.println(root.data);
inOrderPrint(root.right);
}
}
public void postOrderPrint(TreeNode root){
if(root!=null){
postOrderPrint(root.left);
postOrderPrint(root.right);
System.out.println(root.data);
}
}
public void preOrderPrint(){
preOrderPrint(root);
}
public void inOrderPrint(){
inOrderPrint(root);
}
public void postOrderPrint(){
inOrderPrint(root);
}
public void preOrderPrint(TreeNode root){
if(root!=null){
System.out.println(root.data);
preOrderPrint(root.left);
preOrderPrint(root.right);
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
BinaryTreeWithoutRecursion ls= new BinaryTreeWithoutRecursion <>();
ls.insert(1);
ls.insert(2);
ls.insert(3);
ls.insert(4);
ls.insert(5);
ls.insert(6);
ls.insert(7);
//ls.preOrderPrint();
ls.inOrderPrint();
//ls.postOrderPrint();
}
}
"不使用集合类"啊?那么队列类来自哪里呢?如上所述,它是一个二叉树,在第一个需求(任何数量的子节点)失败。
可以在Java.UTL.*中使用TeeSeTepe类。它像二进制搜索树一样工作,所以已经排序了。Treeset类实现ITerable、Collection和Set接口。您可以像集合一样使用迭代器遍历树。
TreeSet treeSet = new TreeSet();
Iterator it = treeSet.Iterator();
while(it.hasNext()){
...
}
您可以检查,Java doc和其他一些。
不使用集合框架的树的自定义树实现。它包含树实现中需要的不同的基本操作。
class Node {
int data;
Node left;
Node right;
public Node(int ddata, Node left, Node right) {
this.data = ddata;
this.left = null;
this.right = null;
}
public void displayNode(Node n) {
System.out.print(n.data +"");
}
}
class BinaryTree {
Node root;
public BinaryTree() {
this.root = null;
}
public void insertLeft(int parent, int leftvalue ) {
Node n = find(root, parent);
Node leftchild = new Node(leftvalue, null, null);
n.left = leftchild;
}
public void insertRight(int parent, int rightvalue) {
Node n = find(root, parent);
Node rightchild = new Node(rightvalue, null, null);
n.right = rightchild;
}
public void insertRoot(int data) {
root = new Node(data, null, null);
}
public Node getRoot() {
return root;
}
public Node find(Node n, int key) {
Node result = null;
if (n == null)
return null;
if (n.data == key)
return n;
if (n.left != null)
result = find(n.left, key);
if (result == null)
result = find(n.right, key);
return result;
}
public int getheight(Node root){
if (root == null)
return 0;
return Math.max(getheight(root.left), getheight(root.right)) + 1;
}
public void printTree(Node n) {
if (n == null)
return;
printTree(n.left);
n.displayNode(n);
printTree(n.right);
}
}
这是一个二叉树,它在操作的第一个要求时失败了。
投反对票是因为我同意@philho