简体   繁体   English

Java中的通用树实现

[英]Generic tree implementation in Java

Is anyone aware of a generic tree (nodes may have multiple children) implementation for Java?有没有人知道 Java 的通用树(节点可能有多个子节点)实现? It should come from a well trusted source and must be fully tested.它应该来自一个值得信赖的来源,并且必须经过全面测试。

It just doesn't seem right implementing it myself.自己实施它似乎并不正确。 Almost reminds me of my university years when we were supposed to write all our collections ourselves.几乎让我想起了我的大学时代,当时我们应该自己写所有的收藏。

EDIT: Found this project on java.net, might be worth looking into.编辑:在 java.net 上找到这个项目,可能值得研究。

Here it comes:它来了:

abstract class TreeNode implements Iterable<TreeNode> {

  private Set<TreeNode> children;

  public TreeNode() {
    children = new HashSet<TreeNode>();
  }

  public boolean addChild(TreeNode n) {
    return children.add(n);
  }

  public boolean removeChild(TreeNode n) {
    return children.remove(n);
  }

  public Iterator<TreeNode> iterator() {
    return children.iterator();
  }
}

I am well trusted, but haven't tested the implementation.我很受信任,但尚未测试实施。

There isn't a Tree class in the Collections libraries. Collections 库中没有 Tree 类。 However, there is one in the Swing Frameworks.然而,一个在Swing框架。 DefaultTreeModel 默认树模型

I have used this in the past and it works well.我过去使用过这个,效果很好。 It does pull in additional classes into your application though which may or may not be desirable.它确实将额外的类引入到您的应用程序中,尽管这可能是可取的,也可能是不可取的。

You can also simulate a Tree using another collection and storing collections in it.您还可以使用另一个集合模拟树并将集合存储在其中。 Eg.例如。 List of Lists.列表列表。

Use Guava使用番石榴

Guava 15.0 introduces a nice API for tree traversal so you don't need to re-implement it for the gazillionth time in your codebase. Guava 15.0为树遍历引入了一个很好的 API,因此您无需在代码库中无数次重新实现它。

Namely, TreeTraverser and some specialized implementations, like BinaryTreeTraverser .即, TreeTraverser和一些专门的实现,如BinaryTreeTraverser

A very much welcomeaddition to avoid re-implementing something so simple and with added bonus:一个非常受欢迎的补充,以避免重新实现如此简单的东西,并有额外的好处:

  • with peace of mind (stability, supported library, etc...),安心(稳定性,支持的库等...),
  • good design,好的设计,
  • several traversal modes built-in.内置多种遍历模式。

While You're There...当你在那里时...

Notice that Guava also provides now new methods to its Files utility class that make use of the TreeTraverser , eg Files.fileTreeTraverser() which gives you a TreeTraverser<File> for your file-system traversal needs.请注意,Guava 现在还为其Files实用程序类提供了使用TreeTraverser新方法,例如Files.fileTreeTraverser() ,它为您的文件系统遍历需要提供TreeTraverser<File>

It's rather hard to do a true generic tree implementation in Java that really separated the tree operations and properties from the underlying implementations, ie swap in a RedBlackTreeNode and override a couple of method to get a RedBlackTree implementation while retaining all the generic operations that a BinaryTree interface contains.在 Java 中做一个真正的通用树实现是相当困难的,它真正将树操作和属性与底层实现分开,即交换一个 RedBlackTreeNode 并覆盖几个方法来获得 RedBlackTree 实现,同时保留 BinaryTree 的所有通用操作界面包含。

Also, an ideal abstraction would be able to swap out the low-level tree representation, eg an implicit binary tree structure stored in an array for a Heap or a Node-base interface with left and right child pointers, or multiple child pointers, or augmenting any of the above with parent pointers, or threading the leaf nodes, etc, etc, etc.此外,理想的抽象将能够换出低级树表示,例如存储在数组中的隐式二叉树结构,用于堆或具有左右子指针或多个子指针的节点基接口,或用父指针增加上述任何一个,或线程化叶节点等,等等。

I did try and solve this myself, but ended up with quite a complicated interface that still enforces type safety.我确实尝试过自己解决这个问题,但最终得到了一个相当复杂的接口,它仍然强制执行类型安全。 Here's the skeleton of the idea that sets up a abstract BinaryTree class with a non-trivial operation (Euler Tour) that will work even if the underlying node class or tree class is changed.这是使用非平​​凡操作 (Euler Tour) 设置抽象 BinaryTree 类的想法的框架,即使底层节点类或树类发生更改,该类也能工作。 It could probable be improved by introducing the idea of cursors for navigation and positions within the tree structure:可以通过在树结构中引入用于导航和位置的光标的想法来改进它:

public interface Tree<E, P extends Tree.Entry<E, P>> extends Collection<E>
{
   public P getRoot();
   public Collection<P> children(P v);
   public E getValue(P v);

   public static interface Entry<T, Q extends Entry<T, Q>> { }
}

public interface BinaryTree<E, P extends BinaryTree.Entry<E, P>> extends Tree<E, P>
{
   public P leftChild(P v);
   public P rightChild(P v);

   public static interface Entry<T, Q extends Entry<T, Q>> extends Tree.Entry<T, Q>
   {
      public Q getLeft();
      public Q getRight();
   }
}

public interface TreeTraversalVisitor<E, P extends BinaryTree.Entry<E, P>, R> 
{
   public R visitLeft( BinaryTree<E, P> tree, P v, R result );
   public R visitCenter( BinaryTree<E, P> tree, P v, R result );
   public R visitRight( BinaryTree<E, P> tree, P v, R result );
}

public abstract class AbstractBinaryTree<E, P extends BinaryTree.Entry<E, P>> extends AbstractCollection<E> implements BinaryTree<E, P>
{
   public Collection<P> children( P v )
   {
      Collection<P> c = new ArrayList<P>( 2 );

      if ( hasLeft( v ))
         c.add( v.getLeft());

      if ( hasRight( v ))
         c.add( v.getRight());

      return c;
   }

   /**
    * Performs an Euler Tour of the binary tree
    */
   public static <R, E, P extends BinaryTree.Entry<E, P>> 
   R eulerTour( BinaryTree<E, P> tree, P v, TreeTraversalVisitor<E, P, R> visitor, R result )
   {
      if ( v == null )
         return result;

      result = visitor.visitLeft( tree, v, result );

      if ( tree.hasLeft( v ))
         result = eulerTour( tree, tree.leftChild( v ), visitor, result );

      result = visitor.visitCenter( tree, v, result );

      if ( tree.hasRight( v ))
         result = eulerTour( tree, tree.rightChild( v ), visitor, result );

      result = visitor.visitRight( tree, v, result );

      return result;
   }    
}

Ah, I was going to post a shameless plug to my solution and saw that someone already posted a link to it.啊,我打算在我的解决方案中发布一个无耻的插件,但看到有人已经发布了一个链接。 Yeah, I had the same issue and I basically ended up writing my own Generic Tree.是的,我遇到了同样的问题,我基本上最终编写了自己的通用树。 I've got tests for the tree node and the tree itself.我对树节点和树本身进行了测试。

I implemented the node as an object having a data field and a list of nodes (which are the children of that node).我将该节点实现为一个对象,该对象具有一个数据字段和一个节点列表(它们是该节点的子节点)。

http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/ http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/

I found an implementation of a Generic Tree (with tests) here:我在这里找到了一个通用树(带测试)的实现:

http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/ http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/

I think this is what you are looking for.我想这就是你要找的。

I found an absolutely fantastic library http://jung.sourceforge.net , see the javadoc http://jung.sourceforge.net/doc/api/index.html .我发现了一个非常棒的库http://jung.sourceforge.net ,请参阅 javadoc http://jung.sourceforge.net/doc/api/index.html It is much more than just a graph implementation.它不仅仅是一个图形实现。 With it you can visualize and layout graphs;有了它,您可以可视化和布局图形; plus, it has a bunch of standard graph algorithms you can use out of the box.另外,它有一堆标准的图形算法,你可以开箱即用。 Go, check it out!去看看吧! Although I ended up implementing my own basic graph (I didn't know of JUNG before), I use this library for visualization.虽然我最终实现了自己的基本图(我之前不知道 JUNG),但我使用这个库进行可视化。 It looks very neat!它看起来非常整洁!

I use an XML DOM (XML describes a tree structure) and specifically the Open Source XOM ( http://www.xom.nu ).我使用 XML DOM(XML 描述树结构),特别是开源 XOM( http://www.xom.nu )。 This is lightweight, nodes can be subclassed if required and very highly used and tested.这是轻量级的,如果需要,可以对节点进行子类化,并且高度使用和测试。 It may be larger than you require but it has the advantage that any tree navigation methods (ancestors, siblings, etc.) are fully managed through XPath.它可能比您需要的大,但它的优点是任何树导航方法(祖先、兄弟等)都可以通过 XPath 完全管理。 You can also serialize the tree and transform it by tested XML methods.您还可以序列化树并通过经过测试的 XML 方法对其进行转换。 There is also a strong user community还有一个强大的用户社区

When in need of a tree I typically use following interface, and implement it accordingly.当需要一棵树时,我通常使用以下接口,并相应地实现它。

  /**
   * Generic node interface
   * 
   * @param <T> type of contained data
   * @param <N> self-referential type boundary that captures the implementing type
   */
  interface Node<T, N extends Node<T, N>>
  {

    public T getObject();

    public boolean addChild(N node);

    public List<N> getChildren();

  }

An implementation could be一个实现可能是

  class StringNode implements Node<String, StringNode>
  {

    private final String value;

    public StringNode(String value)
    {
      this.value = value;
    }

    @Override
    public String getObject()
    {
      return value;
    }

    @Override
    public boolean addChild(StringNode node)
    {
      // add child
      return false;
    }

    @Override
    public List<StringNode> getChildren()
    {
      // return children
      return Collections.emptyList();
    }

  }

The advantage here is the flexibility gained by implementing algorithms against the interface.这里的优势是通过针对接口实现算法而获得的灵活性。 A rather simple example could be一个相当简单的例子可能是

  public <T, N extends Node<T, ? extends N>> N performAlgorithm(N node)
  {
    if (!node.getChildren().isEmpty())
      return node.getChildren().get(0);

    return node;
  }

The method can be used with the inteface type or concrete implementations该方法可以与接口类型或具体实现一起使用

StringNode sn = new StringNode("0");
Node<String, StringNode> node = sn;

// perform computations on the interface type
Node<String, StringNode> result = performAlgorithm(node);

// or use a concrete implementation
StringNode result2 = performAlgorithm(sn);

If you need an enterprise-level node tree, you could look into Java Content Repository ( JCR ).如果您需要企业级节点树,您可以查看 Java Content Repository ( JCR )。 But it is far from the simple in-memory node tree solutions suggested here and more of a multi-user XML database with SQL and XPath.但它远不是这里建议的简单的内存节点树解决方案,而是一个带有 SQL 和 XPath 的多用户 XML 数据库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM