web-dev-qa-db-fra.com

Implémentation d'arbre générique dans Java

Quelqu'un connaît-il une implémentation d'arborescence générique (les nœuds peuvent avoir plusieurs enfants) pour Java? Il doit provenir d'une source de confiance et doit être entièrement testé.

Il ne semble tout simplement pas correct de le mettre en œuvre moi-même. Cela me rappelle presque mes années universitaires où nous étions censés écrire nous-mêmes toutes nos collections.

EDIT: Trouvé ce projet sur Java.net, pourrait valoir la peine d'être étudié.

37
Ivan Koblik

Ça vient:

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

Je suis digne de confiance, mais je n'ai pas testé la mise en œuvre.

23
Zed

Utilisez la goyave

Guava15. introduit une belle API pour la traversée des arbres, vous n'avez donc pas besoin de la réimplémenter pour la gazillionième fois dans votre base de code.

A savoir, TreeTraverser et certaines implémentations spécialisées, comme BinaryTreeTraverser .

Un très bon accueil ajout pour éviter de réimplémenter quelque chose de si simple et avec un bonus supplémentaire:

  • l'esprit tranquille (stabilité, bibliothèque supportée, etc ...),
  • bon design,
  • plusieurs modes de traversée intégrés.

Pendant que vous y êtes ...

Notez que Guava fournit également de nouvelles méthodes à sa classe d'utilitaires Files qui utilisent le TreeTraverser, par exemple Files.fileTreeTraverser() qui vous donne un TreeTraverser<File> pour vos besoins de traversée du système de fichiers.

10
haylem

Il n'y a pas de classe Tree dans les bibliothèques Collections. Cependant, il y en a dans les cadres Swing. DefaultTreeModel

Je l'ai utilisé dans le passé et cela fonctionne bien. Il ajoute des classes supplémentaires à votre application, ce qui peut ou non être souhaitable.

Vous pouvez également simuler un arbre à l'aide d'une autre collection et y stocker des collections. Par exemple. Liste des listes.

9
Fortyrunner

Il est assez difficile de faire une véritable implémentation d'arborescence générique en Java qui a vraiment séparé les opérations et les propriétés de l'arborescence des implémentations sous-jacentes, c'est-à-dire échanger dans un RedBlackTreeNode et remplacer quelques méthodes pour obtenir une implémentation de RedBlackTree tout en conservant toutes les opérations génériques contenues dans une interface BinaryTree.

En outre, une abstraction idéale serait en mesure d'échanger la représentation arborescente de bas niveau, par ex. une structure d'arbre binaire implicite stockée dans un tableau pour un tas ou une interface de base de nœuds avec des pointeurs enfants gauche et droit, ou plusieurs pointeurs enfants, ou en augmentant l'un des éléments ci-dessus avec des pointeurs parents, ou en enfilant les nœuds feuilles, etc., etc., etc.

J'ai essayé de résoudre ce problème moi-même, mais je me suis retrouvé avec une interface assez compliquée qui applique toujours la sécurité des types. Voici le squelette de l'idée qui définit une classe BinaryTree abstraite avec une opération non triviale (Euler Tour) qui fonctionnera même si la classe de nœud ou la classe d'arbre sous-jacente est modifiée. Il pourrait probablement être amélioré en introduisant l'idée de curseurs pour la navigation et les positions dans l'arborescence:

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

Ah, j'allais poster un plug sans vergogne à ma solution et j'ai vu que quelqu'un avait déjà posté un lien vers elle. Oui, j'ai eu le même problème et j'ai fini par écrire mon propre arbre générique. J'ai des tests pour le nœud d'arbre et l'arbre lui-même.

J'ai implémenté le nœud comme un objet ayant un champ de données et une liste de nœuds (qui sont les enfants de ce nœud).

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

6
Vivin Paliath

J'ai trouvé une implémentation d'un arbre générique (avec tests) ici:

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

Je pense que c'est ce que vous recherchez.

5
OccludedInsight

J'ai trouvé une bibliothèque absolument fantastique http://jung.sourceforge.net , voir le javadoc http://jung.sourceforge.net/doc/api/index.html . C'est bien plus qu'une simple implémentation graphique. Avec lui, vous pouvez visualiser et mettre en page des graphiques; De plus, il a un tas d'algorithmes graphiques standard que vous pouvez utiliser prêts à l'emploi. Allez-y! Bien que j'aie fini par implémenter mon propre graphique de base (je ne connaissais pas JUNG auparavant), j'utilise cette bibliothèque pour la visualisation . Ça a l'air très soigné!

2
Ivan Koblik

Lorsque j'ai besoin d'un arbre, j'utilise généralement l'interface suivante et je l'implémente en conséquence.

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

  }

Une mise en œuvre pourrait être

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

  }

L'avantage ici est la flexibilité acquise en implémentant des algorithmes contre l'interface. Un exemple assez simple pourrait être

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

    return node;
  }

La méthode peut être utilisée avec le type d'interface ou des implémentations concrètes

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

J'utilise un DOM XML (XML décrit une structure arborescente) et en particulier le XOM Open Source ( http://www.xom.n ). C'est léger, les nœuds peuvent être sous-classés si nécessaire et très fortement utilisés et testés. Il peut être plus grand que ce dont vous avez besoin, mais il a l'avantage que toutes les méthodes de navigation dans les arbres (ancêtres, frères et sœurs, etc.) sont entièrement gérées via XPath. Vous pouvez également sérialiser l'arborescence et la transformer par des méthodes XML testées. Il existe également une forte communauté d'utilisateurs

0
peter.murray.rust