529 votes

Comment implémenter une structure de données arborescente en Java ?

Existe-t-il une classe standard de la bibliothèque Java pour représenter un arbre en Java ?

Plus précisément, je dois représenter les éléments suivants :

  • Le sous-arbre de n'importe quel nœud peut avoir un nombre arbitraire d'enfants.
  • Chaque noeud (après la racine) et ses enfants auront une valeur de chaîne de caractères
  • J'ai besoin d'obtenir tous les enfants (une sorte de liste ou de tableau de chaînes) d'un nœud donné et sa valeur de chaîne (c'est-à-dire une méthode qui prend un nœud en entrée et renvoie toutes les valeurs de chaîne des nœuds enfants en sortie).

Existe-t-il une structure disponible pour cela ou dois-je créer la mienne (si tel est le cas, des suggestions de mise en œuvre seraient les bienvenues).

3 votes

Si vous utilisez Java 8 et que vous souhaitez parcourir vos nœuds avec des flux, des filtres, etc., vous devriez jeter un coup d'œil à Durian. github.com/diffplug/durian

1 votes

Vous pouvez utiliser cette API : sourceforge.net/p/treeds4j

324voto

jjnguy Points 62123

Ici :

public class Tree<T> {
    private Node<T> root;

    public Tree(T rootData) {
        root = new Node<T>();
        root.data = rootData;
        root.children = new ArrayList<Node<T>>();
    }

    public static class Node<T> {
        private T data;
        private Node<T> parent;
        private List<Node<T>> children;
    }
}

C'est une structure arborescente de base qui peut être utilisée pour String ou tout autre objet. Il est assez facile d'implémenter des arbres simples pour faire ce dont vous avez besoin.

Tout ce que vous devez ajouter, ce sont des méthodes pour ajouter à, enlever de, traverser, et des constructeurs. Le site Node est l'élément de base de la Tree .

7 votes

Vous pouvez également vouloir un champ parent si vous souhaitez obtenir le chemin d'un nœud enfant.

2 votes

C'est vrai, si tu veux pouvoir monter dans l'arbre, il te faut un parent.

315 votes

A proprement parler, le Tree n'est pas nécessaire, car chaque Node peut en soi être considéré comme un arbre.

134voto

Grzegorz Dev Points 533

Encore une autre structure arborescente :

public class TreeNode<T> implements Iterable<TreeNode<T>> {

    T data;
    TreeNode<T> parent;
    List<TreeNode<T>> children;

    public TreeNode(T data) {
        this.data = data;
        this.children = new LinkedList<TreeNode<T>>();
    }

    public TreeNode<T> addChild(T child) {
        TreeNode<T> childNode = new TreeNode<T>(child);
        childNode.parent = this;
        this.children.add(childNode);
        return childNode;
    }

    // other features ...

}

Exemple d'utilisation :

TreeNode<String> root = new TreeNode<String>("root");
{
    TreeNode<String> node0 = root.addChild("node0");
    TreeNode<String> node1 = root.addChild("node1");
    TreeNode<String> node2 = root.addChild("node2");
    {
        TreeNode<String> node20 = node2.addChild(null);
        TreeNode<String> node21 = node2.addChild("node21");
        {
            TreeNode<String> node210 = node20.addChild("node210");
        }
    }
}

BONUS
Voir l'arbre à part entière avec :

  • itérateur
  • recherche
  • Java/C#

https://github.com/gt4dev/yet-another-tree-structure

2 votes

Je viens de trouver votre bibliothèque extrêmement utile. Je vous en remercie. Mais je voudrais savoir comment mettre en œuvre l'alimentation dynamique de l'arborescence basée sur la relation de référence entre le parent et l'enfant. L'exemple donné est que j'ai un membre1 qui sponsorise un autre membre2, et le membre2 sponsorise le membre 3 et ainsi de suite. J'ai déjà la relation entre les enregistrements de la table mais je ne suis pas sûr de pouvoir les remplir dans une arborescence en utilisant votre bibliothèque.

1 votes

À partir de 2016, le lien ne contient pas de fichiers sources ou de téléchargements.

2 votes

À mon avis, cette réponse, trois ans après celle qui a obtenu la meilleure note, est la plus propre. Cependant, je remplacerais la LinkedList par une ArrayList pour this.children.

98voto

Gareth Davis Points 16190

Il existe en fait une très bonne structure arborescente implémentée dans le JDK.

Jetez un coup d'œil à javax.swing.tree , Modèle d'arbre y TreeNode . Ils sont conçus pour être utilisés avec le JTreePanel mais il s'agit, en fait, d'une assez bonne implémentation de l'arbre et rien ne vous empêche de l'utiliser sans interface swing.

Notez qu'à partir de Java 9, vous souhaiterez peut-être ne pas utiliser ces classes car elles ne seront pas présentes dans le répertoire de l'utilisateur. Profils compacts .

5 votes

Oui, je les ai utilisés dans le passé, et ils font tout ce que vous voulez d'un arbre. Le seul inconvénient auquel je peux penser est la longueur des noms de leurs classes d'implémentation respectives : DefaultTreeModel et DefaultMutableTreeNode. Verbose, mais ce n'est pas si important que ça, je suppose.

4 votes

Une bonne façon de faire face à cela est de créer deux méthodes statiques newModel() et newNode(), puis de les importer statiquement.

146 votes

J'éviterais d'utiliser les bibliothèques Swing pour des fonctions non liées à Swing. C'est mauvaise pratique de codage . Vous ne savez jamais comment Swing met en œuvre ses arbres, quelles sont leurs dépendances et comment cela pourrait changer à l'avenir. Swing n'est pas une bibliothèque utilitaire mais une bibliothèque d'interface utilisateur.

47voto

MountainX Points 1680

Et ça ?

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

/**
  * @author ycoppel@google.com (Yohann Coppel)
  * 
  * @param <T>
  *          Object's type in the tree.
*/
public class Tree<T> {

  private T head;

  private ArrayList<Tree<T>> leafs = new ArrayList<Tree<T>>();

  private Tree<T> parent = null;

  private HashMap<T, Tree<T>> locate = new HashMap<T, Tree<T>>();

  public Tree(T head) {
    this.head = head;
    locate.put(head, this);
  }

  public void addLeaf(T root, T leaf) {
    if (locate.containsKey(root)) {
      locate.get(root).addLeaf(leaf);
    } else {
      addLeaf(root).addLeaf(leaf);
    }
  }

  public Tree<T> addLeaf(T leaf) {
    Tree<T> t = new Tree<T>(leaf);
    leafs.add(t);
    t.parent = this;
    t.locate = this.locate;
    locate.put(leaf, t);
    return t;
  }

  public Tree<T> setAsParent(T parentRoot) {
    Tree<T> t = new Tree<T>(parentRoot);
    t.leafs.add(this);
    this.parent = t;
    t.locate = this.locate;
    t.locate.put(head, this);
    t.locate.put(parentRoot, t);
    return t;
  }

  public T getHead() {
    return head;
  }

  public Tree<T> getTree(T element) {
    return locate.get(element);
  }

  public Tree<T> getParent() {
    return parent;
  }

  public Collection<T> getSuccessors(T root) {
    Collection<T> successors = new ArrayList<T>();
    Tree<T> tree = getTree(root);
    if (null != tree) {
      for (Tree<T> leaf : tree.leafs) {
        successors.add(leaf.head);
      }
    }
    return successors;
  }

  public Collection<Tree<T>> getSubTrees() {
    return leafs;
  }

  public static <T> Collection<T> getSuccessors(T of, Collection<Tree<T>> in) {
    for (Tree<T> tree : in) {
      if (tree.locate.containsKey(of)) {
        return tree.getSuccessors(of);
      }
    }
    return new ArrayList<T>();
  }

  @Override
  public String toString() {
    return printTree(0);
  }

  private static final int indent = 2;

  private String printTree(int increment) {
    String s = "";
    String inc = "";
    for (int i = 0; i < increment; ++i) {
      inc = inc + " ";
    }
    s = inc + head;
    for (Tree<T> child : leafs) {
      s += "\n" + child.printTree(increment + indent);
    }
    return s;
  }
}

5 votes

Comment le DFS serait-il mis en œuvre sur un arbre créé à l'aide de cette classe d'objet ?

3 votes

Comment la suppression d'une feuille serait-elle mise en œuvre à l'aide de cette classe ?

2 votes

A quoi servirait le champ de tête ?

24voto

Vivin Paliath Points 40975

I a écrit une petite bibliothèque qui gère les arbres génériques. C'est beaucoup plus léger que les trucs de swing. J'ai aussi une projet maven pour cela.

3 votes

Je l'utilise maintenant, il fonctionne parfaitement. J'ai dû modifier la source de manière significative pour mes propres personnalisations, mais c'était un excellent point de départ. Merci Vivin !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X