Java中的通用树实现

时间:2009-08-31 08:19:07

标签: java collections reference tree generics

是否有人知道Java的通用树(节点可能有多个子节点)实现?它应来自一个值得信赖的来源,必须经过全面测试。

我自己实施它似乎并不合适。几乎让我想起大学时代,我们应该自己写完所有的藏品。

编辑:在java.net上找到this project,可能值得研究。

10 个答案:

答案 0 :(得分:23)

来了:

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();
  }
}

我很信任,但尚未测试实施。

答案 1 :(得分:10)

使用Guava

Guava 15.0为树遍历引入了一个很好的API,因此您无需在代码库中的数十亿次重新实现它。

TreeTraverser和一些专门的实施,例如BinaryTreeTraverser

非常欢迎addition以避免重新实施如此简单且带来额外奖励的事情:

  • 安心(稳定,支持图书馆等),
  • 好的设计,
  • 内置了几种遍历模式。

当你在那里......

请注意,Guava现在还为其Files实用程序类提供了使用TreeTraverser的新方法,例如Files.fileTreeTraverser()为您的文件系统遍历需求提供了TreeTraverser<File>

答案 2 :(得分:9)

Collections库中没有Tree类。但是,Swing框架中的一个。 DefaultTreeModel

我过去曾经使用过它并且运行良好。它会在您的应用程序中引入其他类,尽管这可能是也可能不是。

您还可以使用其他集合模拟树并在其中存储集合。例如。列表清单。

答案 3 :(得分:8)

在Java中实现真正的通用树实现相当困难,它实际上将树操作和属性与底层实现分开,即交换RedBlackTreeNode并覆盖一些方法以获得RedBlackTree实现,同时保留所有泛型操作BinaryTree接口包含。

此外,理想的抽象将能够交换低级树表示,例如,存储在数组中的隐式二进制树结构,用于具有左右子指针的Heap或Node-base接口,或多个子指针,或使用父指针扩充上述任何一个,或者线程化叶节点等等,等

我确实尝试过自己解决这个问题,但结果却是一个非常复杂的界面,仍然强制执行类型安全。这是一个概念的框架,它设置了一个带有非平凡操作的抽象BinaryTree类(Euler Tour),即使更改了底层节点类或树类,它也能工作。通过在树结构中引入用于导航和位置的游标的概念,可能会改进:

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;
   }    
}

答案 4 :(得分:6)

啊,我打算在我的解决方案中发布一个无耻的插件,看到有人已经发布了一个链接。是的,我有同样的问题,我基本上最终编写了自己的通用树。我已经测试了树节点和树本身。

我将节点实现为具有数据字段和节点列表(该节点的子节点)的对象。

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

答案 5 :(得分:5)

我在这里找到了一个通用树的实现(带有测试):

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

我认为这就是你要找的东西。

答案 6 :(得分:2)

我发现了一个绝对出色的库http://jung.sourceforge.net,请参阅javadoc http://jung.sourceforge.net/doc/api/index.html。它不仅仅是图形实现。有了它,您可以可视化和布局图形;此外,它还有一堆标准图形算法,您可以直接使用它们。 去,检查出来!虽然我最终实现了自己的基本图形(之前我不知道JUNG),但我使用这个库进行可视化。它看起来很整洁!

答案 7 :(得分:0)

我使用XML DOM(XML描述树结构),特别是开源XOM(http://www.xom.nu)。这是轻量级的,如果需要,节点可以是子类,并且使用和测试非常高。它可能比您需要的大,但它的优点是任何树导航方法(祖先,兄弟姐妹等)都可以通过XPath完全管理。您还可以序列化树并通过测试的XML方法对其进行转换。还有一个强大的用户社区

答案 8 :(得分:0)

当需要树时,我通常使用以下接口,并相应地实现它。

  /**
   * 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();

  }

实现可能是

  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();
    }

  }

这里的优势是针对接口实现算法所获得的灵活性。一个相当简单的例子可能是

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

    return node;
  }

该方法可以与接口类型或具体实现一起使用

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);

答案 9 :(得分:0)

如果需要企业级节点树,则可以查看Java Content Repository(JCR)。但是,它与这里建议的简单的内存中节点树解决方案以及带有SQL和XPath的多用户XML数据库相比,远非如此。