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();
}
}
私は信頼されていますが、実装をテストしていません。
Guava15. ツリートラバーサル用のNice APIが導入されているため、コードベースで膨大な時間をかけて再実装する必要はありません。
つまり、 TreeTraverser
および BinaryTreeTraverser
のような特殊な実装です。
非常に歓迎されています 追加 とてもシンプルでボーナスが追加されたものを再実装することを避けるため:
Guavaでは、Files
を使用するTreeTraverser
ユーティリティクラスに新しいメソッドも追加されていることに注意してください。 Files.fileTreeTraverser()
これにより、TreeTraverser<File>
は、ファイルシステムトラバーサルのニーズに対応しています。
コレクションライブラリにはTreeクラスはありません。ただし、Swing Frameworkにはisがあります。 DefaultTreeModel
私はこれを過去に使用しましたが、うまく機能します。それはあなたのアプリケーションに追加のクラスを引き込みますが、それは望ましい場合とそうでない場合があります。
また、別のコレクションを使用してコレクションを保存するツリーをシミュレートすることもできます。例えば。リストのリスト。
Javaで実際のツリー操作とプロパティを基礎となる実装から分離する、つまりRedBlackTreeNodeでスワップし、いくつかのメソッドをオーバーライドしてRedBlackTree実装を取得する真の汎用ツリー実装を行うのはかなり困難です。 BinaryTreeインターフェイスに含まれるすべての一般的な操作を保持します。
また、理想的な抽象化は、低レベルのツリー表現をスワップアウトすることができます。左右の子ポインター、または複数の子ポインターを持つヒープまたはノードベースインターフェイスの配列に格納された暗黙的なバイナリツリー構造、または親ポインターによる上記のいずれかの拡張、リーフノードなどのスレッド化など等.
私はこれを自分で解決しようとしましたが、タイプセーフを強制する非常に複雑なインターフェイスになりました。基になるノードクラスまたはツリークラスが変更された場合でも機能する非自明な操作(オイラーツアー)を使用して抽象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;
}
}
ああ、私は自分のソリューションに恥知らずなプラグを投稿するつもりでしたが、誰かが既にそのリンクを投稿しているのを見ました。ええ、私は同じ問題を抱えていたので、基本的に自分のGeneric Treeを書くことになりました。ツリーノードとツリー自体のテストがあります。
ノードを、データフィールドとノードのリスト(そのノードの子)を持つオブジェクトとして実装しました。
ここで、(テスト付きの)汎用ツリーの実装を見つけました。
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を知りませんでした)、このライブラリを視覚化に使用します。とてもきれいに見えます!
ツリーが必要なときは、通常次のインターフェイスを使用し、それに応じて実装します。
/**
* 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);
私はXML DOM(XMLはツリー構造を記述する)、特にオープンソースXOM( http://www.xom.n )を使用します。これは軽量であり、必要に応じてノードをサブクラス化し、非常に高度に使用およびテストできます。必要以上に大きいかもしれませんが、ツリーナビゲーションメソッド(祖先、兄弟など)がXPathを介して完全に管理されるという利点があります。また、ツリーをシリアル化し、テスト済みのXMLメソッドで変換することもできます。強力なユーザーコミュニティもあります