web-dev-qa-db-fra.com

Pourquoi Java Collection Framework ne contient pas d'arbre et de graphique

Je connais Java Collection Framework qui contient des interfaces de base: Collection et Map. Je me demande pourquoi le Framework ne contient pas de structures comme Tree et Graph qui sont des collections de base. Les deux peuvent être considérés comme des sous-types de Collection.

Soit dit en passant, je sais que TreeSet est implémenté par Red-Black Tree sous-jacent. Cependant, le TreeSet n'est pas un arbre mais un Set, il n'y a donc pas de véritable arbre dans le framework.

44

Je me demande pourquoi le Framework ne contient pas de structures comme Tree et Graph qui sont des collections de base. Les deux peuvent être considérés comme des sous-types de Collection.

C'est une bonne question. Je pense que cela se résume simplement à la portée. Les fonctionnalités principales pour lesquelles l'API Collections fournit des classes sont les suivantes:

  • ordre d'itération: Les listes et les cartes triées ont spécifié l'ordre d'itération, la plupart des ensembles ne le font pas.

  • doublons: les listes autorisent les doublons, les ensembles ne le font pas

  • index: Les valeurs de liste sont indexées par des entiers, les valeurs de carte sont indexées par d'autres objets.

Cela nous mène très loin et je suppose que Joshua Bloch et al ont fait valoir que des collections plus riches en fonctionnalités (graphiques et arbres qui nécessitent une relation interne entre les éléments, des ensembles avec multiplicité, des cartes bidirectionnelles, ...) peuvent être implémentées au-dessus de ces trois fonctionnalités de base, et sont donc mieux dans les bibliothèques.

26
aioobe

Le Java.util le package contient des structures de données pour organiser les données de toute nature. Il traite essentiellement des structures de données abstraites (comme List, Set, Map) qui sont définis via leurs méthodes et leur comportement (par exemple, un ensemble ne contient aucun élément deux fois, une liste maintient l'ordre et autorise les doublons, etc.).

En tant que développeur, vous êtes libre de choisir la mise en œuvre de ces structures de données qui convient le mieux au type de données que vous traitez ( HashSet vs. TreeSet/LinkedList vs. ArrayList/etc.). Par exemple, pour les ensembles et les cartes, vous pouvez choisir entre les implémentations basées sur le hachage et les implémentations basées sur l'arborescence, qui peuvent ou non convenir à ce que vous voulez faire (dans la plupart des cas, une implémentation basée sur le hachage sera le meilleur choix, tandis que parfois , lorsque l'ordre est important, un arbre peut être mieux adapté à vos besoins - Voir aussi HashSet vs TreeSet (ici sur Stackoverflow) ).

Si vous pensez à un arbre comme un type spécial de graphique (ce qu'il est), alors vous êtes intéressé par des propriétés spécifiques qui s'appliquent aux graphiques, pas aux collections en général (qui, essentiellement, sont des listes, et sont à leur tour utilisées pour implémenter des choses comme des graphiques).

Comme mentionné dans ce fil de discussion, si vous êtes intéressé par la modélisation de graphiques, il existe de nombreux choix pour les bibliothèques de graphiques. Personnellement, je peux recommander JGraphT .

Je ne sais pas pourquoi il n'y a pas de bibliothèque de graphes dans le JDK (et je ne sais pas si c'est une bonne chose à demander?), Mais je suppose que Sun a décidé de laisser cela aux développeurs , car la plupart des applications qui nécessitent des graphiques nécessitent également des implémentations très uniques.

12
scravy

Réponse originale

Le principal problème avec les graphiques (et plus concrètement les arbres, comme vous le savez, un cas spécial où il n'y a qu'une seule racine, il ne peut y avoir de boucles et tous les nœuds sont connectés) est que chaque élément de cette supposée collection doit être conservé dans une autre structure : le nœud. Il est difficile de faire standard ce type de traitement car il nécessite une double couche de "conteneurs".

Si quelqu'un travaille avec TreeModel pour JTree, il est presque impossible d'éviter le fait qu'il y a TreeNode derrière (à l'intérieur?) Et que vous devez manipuler les nœuds et les arbres.

Quoi qu'il en soit, je conviens que la structure serait utile mais il est très difficile de la rendre standard, notez simplement que, par exemple, ni Apache Commons Collections ni Google Guava, deux grandes extensions de collection pour l'API, ne les avez pas non plus.

Mise à jour

Selon l'aperçu de l'API :

Le principal objectif de conception était de produire une API qui était raisonnablement petite, à la fois en taille et, plus important encore, en "poids conceptuel". Il était essentiel que la nouvelle fonctionnalité ne semble pas étrangère aux programmeurs actuels Java; elle devait augmenter les installations actuelles plutôt que de les remplacer. En même temps, la nouvelle API devait être suffisamment puissante pour offrent tous les avantages décrits ci-dessus.

Ainsi, alors que les graphiques sont des collections appropriées et qu'il serait peut-être possible de le rendre standard, la taille et la complexité de l'implémentation seraient trop grandes pour répondre à cet objectif de conception, en raison du besoin précédemment expliqué d'un double couche de conteneurs.

En outre, Google Guava a ajouté la prise en charge des graphiques . Apache avait un bac à sable (développement en cours) pour les graphiques mais semble dormant depuis 2011.

3
Yago Méndez Vidal

J'ai peur que la réponse soit: c'est trop gênant pour concevoir et maintenir une structure arborescente générique et des interfaces (voir la réponse à ce post ). La plupart des utilisateurs auront besoin des performances des implémentations arborescentes de listes et d'ensembles, mais ne seront pas concernés par les internes, donc la plupart d'entre eux sont cachés.

2
rodion

Il existe une interface pour les arbres - javax.swing.tree.TreeModel, qui fonctionne en fait pour les graphes dirigés arbitrairement (avec un nœud "racine" distingué). Cependant, il n'implémente pas l'interface Collection (puisque Swing est un peu plus ancien que le framework de collection, et il n'est pas vraiment clair qu'être une collection serait vraiment approprié ici). (Une implémentation de TreeModel est DefaultTreeModel, qui utilise une arborescence à partir d'objets TreeNode, qui est elle-même une interface implémentable par les utilisateurs.)

Un autre type d'arbres est donné par les frameworks XML-DOM. Certains arbres d'utilisation spécifiques (ou principalement des "nœuds d'arbre") sont définis par Java.io.File, Java.awt.Component (et les sous-classes), l'API de l'arborescence du compilateur (com.Sun.source.tree.*), l'API Doclet (com.Sun.javadoc.*), l'API Reflection (Java.lang.Class), l'API du modèle de langage (javax.lang.**).

Si vous comparez ces API

Le problème est qu'il n'y a pas d'interface claire à usage général pour les arbres - que devrait faire un tel arbre? Un arbre est-il simplement une collection d'autres arbres (ceux d'un niveau inférieur), ou simplement un pointeur vers le nœud racine, où chaque nœud lui-même contient plus de nœuds? Ou un arbre est-il une collection de tous les nœuds? Ou une collection de tous les contenus de tous les nœuds? Tous les nœuds doivent-ils avoir du "contenu", ou seulement les nœuds feuilles? Si un arbre était une collection de certains éléments de contenu (et non les nœuds lui-même), comment un itérateur devrait-il se comporter? Quelle serait la taille d'un arbre?

Voici une proposition pour un nœud d'arbre (ou en fait ce pourrait être un nœud de graphe orienté général, sinon pour le parent-pointeur):

/**
 * A general interface for a tree node.
 * @param <N> the concrete node type.
 */
public interface Node<N extends Node<N>> {

   /**
    * equivalent to {@link #children children()}.{@link Collection#isEmpty isEmpty()}.
    * @returns true, if this is a leaf node, else false.
    */
   public boolean isLeaf();

   /**
    * returns a collection of all children of this node.
    * This collection can be changed, if this node is mutable.
    */
   public Collection<N> children();
   /**
    * returns the parent of this node.
    * @return null, if this is the root node, or the node does not know its parent, or has multiple parents.
    */
   public N parent();
}

/**
 * a tree node with content objects.
 * @param <N> the concrete node type
 * @param <C> the type of the content of this node.
 */
public interface ContentNode<C,N extends ContentNode<C,N>>
          extends Node<N>
{
   /**
    * returns the content of this node, if any.
    */
   public C content();
}

Serait-ce suffisant pour tous les types d'arbres, par exemple ceux répertoriés ci-dessus? Je ne pense pas.

1
Paŭlo Ebermann