簡體   English   中英

Java中的通用樹實現

[英]Generic tree implementation in Java

有沒有人知道 Java 的通用樹(節點可能有多個子節點)實現? 它應該來自一個值得信賴的來源,並且必須經過全面測試。

自己實施它似乎並不正確。 幾乎讓我想起了我的大學時代,當時我們應該自己寫所有的收藏。

編輯:在 java.net 上找到這個項目,可能值得研究。

它來了:

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

我很受信任,但尚未測試實施。

Collections 庫中沒有 Tree 類。 然而,一個在Swing框架。 默認樹模型

我過去使用過這個,效果很好。 它確實將額外的類引入到您的應用程序中,盡管這可能是可取的,也可能是不可取的。

您還可以使用另一個集合模擬樹並將集合存儲在其中。 例如。 列表列表。

使用番石榴

Guava 15.0為樹遍歷引入了一個很好的 API,因此您無需在代碼庫中無數次重新實現它。

即, TreeTraverser和一些專門的實現,如BinaryTreeTraverser

一個非常受歡迎的補充,以避免重新實現如此簡單的東西,並有額外的好處:

  • 安心(穩定性,支持的庫等...),
  • 好的設計,
  • 內置多種遍歷模式。

當你在那里時...

請注意,Guava 現在還為其Files實用程序類提供了使用TreeTraverser新方法,例如Files.fileTreeTraverser() ,它為您的文件系統遍歷需要提供TreeTraverser<File>

在 Java 中做一個真正的通用樹實現是相當困難的,它真正將樹操作和屬性與底層實現分開,即交換一個 RedBlackTreeNode 並覆蓋幾個方法來獲得 RedBlackTree 實現,同時保留 BinaryTree 的所有通用操作界面包含。

此外,理想的抽象將能夠換出低級樹表示,例如存儲在數組中的隱式二叉樹結構,用於堆或具有左右子指針或多個子指針的節點基接口,或用父指針增加上述任何一個,或線程化葉節點等,等等。

我確實嘗試過自己解決這個問題,但最終得到了一個相當復雜的接口,它仍然強制執行類型安全。 這是使用非平​​凡操作 (Euler Tour) 設置抽象 BinaryTree 類的想法的框架,即使底層節點類或樹類發生更改,該類也能工作。 可以通過在樹結構中引入用於導航和位置的光標的想法來改進它:

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

啊,我打算在我的解決方案中發布一個無恥的插件,但看到有人已經發布了一個鏈接。 是的,我遇到了同樣的問題,我基本上最終編寫了自己的通用樹。 我對樹節點和樹本身進行了測試。

我將該節點實現為一個對象,該對象具有一個數據字段和一個節點列表(它們是該節點的子節點)。

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

我在這里找到了一個通用樹(帶測試)的實現:

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

我想這就是你要找的。

我發現了一個非常棒的庫http://jung.sourceforge.net ,請參閱 javadoc http://jung.sourceforge.net/doc/api/index.html 它不僅僅是一個圖形實現。 有了它,您可以可視化和布局圖形; 另外,它有一堆標准的圖形算法,你可以開箱即用。 去看看吧! 雖然我最終實現了自己的基本圖(我之前不知道 JUNG),但我使用這個庫進行可視化。 它看起來非常整潔!

我使用 XML DOM(XML 描述樹結構),特別是開源 XOM( http://www.xom.nu )。 這是輕量級的,如果需要,可以對節點進行子類化,並且高度使用和測試。 它可能比您需要的大,但它的優點是任何樹導航方法(祖先、兄弟等)都可以通過 XPath 完全管理。 您還可以序列化樹並通過經過測試的 XML 方法對其進行轉換。 還有一個強大的用戶社區

當需要一棵樹時,我通常使用以下接口,並相應地實現它。

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

如果您需要企業級節點樹,您可以查看 Java Content Repository ( JCR )。 但它遠不是這里建議的簡單的內存節點樹解決方案,而是一個帶有 SQL 和 XPath 的多用戶 XML 數據庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM