1 Les arbres binaires en Java



Documents pareils
Les structures de données. Rajae El Ouazzani

Arbres binaires de recherche

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Tp 1 correction. Structures de données (IF2)

Les arbres binaires de recherche

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Programmation Par Objets

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Premiers Pas en Programmation Objet : les Classes et les Objets

TP1 : Initiation à Java et Eclipse

ARBRES BINAIRES DE RECHERCHE

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Cours 1: Java et les objets

Programmation avec des objets : Cours 7. Menu du jour

Java Licence Professionnelle CISII,

Corrigés des premiers exercices sur les classes

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

Lambda! Rémi Forax Univ Paris-Est Marne-la-Vallée

Traduction des Langages : Le Compilateur Micro Java

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Un ordonnanceur stupide

Algorithmique, Structures de données et langage C

Java Licence Professionnelle Cours 7 : Classes et méthodes abstraites

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

as Architecture des Systèmes d Information

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Chapitre VI- La validation de la composition.

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

TD3: tableaux avancées, première classe et chaînes

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets.

Utilisation d objets : String et ArrayList

Programmer en JAVA. par Tama

Package Java.util Classe générique

Gestion distribuée (par sockets) de banque en Java

Auto-évaluation Programmation en Java

Génie Logiciel avec Ada. 4 février 2013

Corrigé des exercices sur les références

Cette application développée en C# va récupérer un certain nombre d informations en ligne fournies par la ville de Paris :

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Plan du cours. Historique du langage Nouveautés de Java 7

Chapitre 10. Les interfaces Comparable et Comparator 1

Cours d initiation à la programmation en C++ Johann Cuenin

Objets et Programmation. origine des langages orientés-objet

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

TD/TP PAC - Programmation n 3

TP, première séquence d exercices.

Remote Method Invocation Les classes implémentant Serializable

TD/TP PAC - Programmation n 3

Programmation Objet Java Correction

TP1 : Initiation à Java et Eclipse

2. Comprendre les définitions de classes

Java Licence Professionnelle CISII, Cours 2 : Classes et Objets

RAPPELS SUR LES METHODES HERITEES DE LA CLASSE RACINE Object ET LEUR SPECIALISATION (i.e. REDEFINITION)

Conventions d écriture et outils de mise au point

OCL - Object Constraint Language

Programmation Objet - Cours II

Gestion mémoire et Représentation intermédiaire

INFO-F-105 Language de programmation I Séance VI

MIS 102 Initiation à l Informatique

INITIATION AU LANGAGE JAVA

Programmation Orientée Objet

Quelques Algorithmes simples

Aide mémoire UML & Java 1ère partie : Introduction. marc.lemaire@u-cergy.fr

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Algorithmique I. Algorithmique I p.1/??

Chapitre V. Les classes : Object, Vector, etc.

Chapitre 2. Classes et objets

Algorithmique et Programmation, IMA

Héritage presque multiple en Java (1/2)

Programmation par composants (1/3) Programmation par composants (2/3)

Cours 1 : La compilation

Polymorphisme, la classe Object, les package et la visibilité en Java... 1

Application web de gestion de comptes en banques

Introduction à la sécurité Cours 8 Infrastructure de clés publiques. Catalin Dima

Facultés Universitaires Notre-Dame de la Paix. Conception et Programmation Orientées- Object

Programmation en Java IUT GEII (MC-II1) 1

TP1. Outils Java Eléments de correction

Solutions du chapitre 4

Création d objet imbriqué sous PowerShell.

Environnements de développement (intégrés)

Projet de programmation (IK3) : TP n 1 Correction

INF601 : Algorithme et Structure de données

Java c est quoi? Java pourquoi?

Manuel d utilisation du module Liste de cadeaux PRO par Alize Web

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

Compression de Données - Algorithme de Huffman Document de Conception

C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement

Les structures. Chapitre 3

Introduction à MATLAB R

Initiation. àl algorithmique et à la programmation. en C

Bases de programmation. Cours 5. Structurer les données

Classe ClInfoCGI. Fonctions membres principales. Gestion des erreurs

Licence Sciences et Technologies Examen janvier 2010

Transcription:

Université de Nice-Sophia Antipolis Deug MIAS-MI 1 Algorithmique & Programmation 2002 2003 TP N 10 Arbres binaires Buts : structuration des arbres binaires en Java. classes internes. objets de parcours. 1 Les arbres binaires en Java L orientation Objet de Java impose de compliquer légèrement la structure des pointeurs qui décrivent les arbres binaires. En effet, avec les déclarations générales données dans le cours : type T_arbre = pointeur sur T_noeud T_noeud = article : T_élément gauche, droite = T_arbre finarticle procédure insérer (donnée-résultat a : T_arbre, x : T_élément) début si a = alors a = nouveau (x,, ) sinonsi x a. alors insérer (a.gauche, x) sinon { x > a. insérer (a.droite, x) fin la transmission en donnée-résultat est essentielle lors de la première 1 insertion dans un arbre vide (qui est représenté par le pointeur ). Mais ce mode de transmission n existe pas en Java et on ne peut pas non plus s en sortir avec une fonction d instance du style : Tree insert (Element x) { if (this == null) return new Tree(x, null, null) ; else { if (x.compareto(content) <= 0) left = left.insert(x) ; else right = right.insert(x) ; return this ; qui, avec la plus grande naïveté, suppose qu une expression comme null.insert(x) possède le moindre sens! 1. Dans les insertions suivantes, a n est plus modifié. 1

Comme vous l avez déjà vu avec les listes chaînées et pour les mêmes raisons il faudra donc mettre à distance la racine de l arbre et disposer de deux classes, une classe Node qui s occupe de gérer tout ce qui est récursif (chaque nœud a deux sous-nœuds) et où les références null jouent leur rôle normal de marqueurs d inexistence, et une classe Tree qui gère un nœud unique, la racine. Un arbre vide ne sera donc pas un arbre inexistant (il ne vaudra pas null) mais un arbre sans (sa racine vaudra null). Mais, à la différence de ce que vous avez vu avec les listes, et pour vous apprendre un peu plus de Java, on ne mettra pas ces deux classes dans des fichiers distincts car, somme toute, la classe Node ne présente aucun intérêt en dehors de la classe Tree (elle n est pas réutilisable ailleurs). On le déclarera donc en classe interne, à l intérieur du fichier BinaryTree.java ; on la déclarera naturellement private mais aussi static car cette classe est commune à tous les arbres et pas à une instance particulière. En plus de cette localisation logique, un intérêt de cette présentation sera l inutilité de définir des accesseurs pour les attributs de Node : étant à la maison, ils seront accessibles dans l ensemble de la classe Tree! Le compilateur considèrera cependant cette classe comme une entité à part entière et, quand vous compilerez le fichier BinaryTree.java, vous verrez que, outre BinaryTree.class, il produira un fichier BinaryTree$Node.class qui contiendra le code de la classe Node ainsi que ses liens d import/export. Pour résumer, ces déclarations seront simplement équivalentes à la déclaration dans le même programme des types : type T_noeud = pointeur sur T_descripteurDeNoeud T_descripteurDeNoeud = article : T_élément gauche, droite = T_noeud finarticle T_arbre = pointeur sur T_descripteurDeArbre T_descripteurDeArbre = article racine : T_noeud finarticle Et l insertion se fera au moyen de deux procédures, l une récursive au niveau des nœuds : procédure insérersousnoeud (données a : T_noeud, x : T_élément) { Antécédent : a début si x a. alors si a.gauche = alors a.gauche nouveau(x,, ) sinon insérersousnoeud(a.gauche, x) sinon { x > a. si a.droite = alors a.droite nouveau(x,, ) sinon insérersousnoeud(a.droite, x) fin l autre, non récursive, au niveau des arbres, démarrant simplement le processus : 2

procédure insérer (données t : T_arbre, x : T_élément) { Antécédent : t initialisé (t ) début si t.racine = alors { arbre vide t.racine nouveau(x,, ) sinon { arbre non vide insérersousnoeud(t.racine, x) fin où l on remarque que toutes les transmissions se font maintenant sur le mode donnée. Un schéma mettra en évidence cette technique «Objet» de mise à distance de la racine. On montre deux états du chaînage à partir d une variable t de type T_arbre : arbre non vide t arbre vide t racine racine Isabelle gauche droite Frédéric gauche droite Patricia gauche droite Dimitri gauche droite Irène gauche droite Vlad gauche droite 2 Statistiques sur les arbres Le squelette qui vous est fourni dans le fichier BinaryTree.java contient des moyens d évaluation du nombre de nœuds d un arbre. Vous pouvez constater que ces moyens sont constitués de deux méthodes d instance nbnodes : l une dans la classe Node, récursive et pri- 3

vée, l autre dans la classe Tree, globale et exportée, doit traiter à part le cas root == null (car null.nbnodes() n aurait aucun sens) mais reste une méthode d instance car, dès qu il existe en tant qu objet, un arbre, même vide, ne vaut jamais null. a. Sur le même modèle, écrivez des méthodes height qui calculent la hauteur et nbleaves qui comptent le nombre de feuilles. 3 Arbres binaires de consultation Ces arbres, qu on appelle parfois en abrégé «BST» (Binary Search Tree) satisfont une condition récursive forte sur la répartition des clefs, condition simple 2 mais qu il n est pas si facile d écrire avec justesse : b. (difficile, donc facultatif) Faites renvoyer un résultat exact à la méthode isbst de la classe Node. Cependant, ce test n est pas ici un réel problème puisque, ne pouvant fabriquer des arbres qu avec le constructeur d arbre vide et des utilisations successives de la méthode insert, on est assuré que la condition est satisfaite 3! Les méthodes d insertion, simples traductions des algorithmes donnés dans la première section, ainsi que les méthodes de recherche figurent dans le squelette fourni mais ces dernières présentent une bizarrerie qu il faudrait bien expliquer. c. (subtil) Quelle est cette bizarrerie? 4 Les parcours d arbres Java propose un mécanisme général pour parcourir toute collection d objets comme tableaux, listes ou arbres. Il consiste à associer à chaque collection un objet qu on appelle une «énumération» ou un «itérateur». Cet objet sera une instance d une classe qui proposera trois outils de base : un constructeur «initialise l énumération» qui prend la collection en argument ; une méthode d instance «il y en a encore» qui renvoie vrai si le parcours n est pas terminé ; une méthode d instance «donne le prochain» qui renvoie le composant suivant et, par effet de bord, le retire de l énumération. Il devra bien sûr exister une telle classe pour chaque type de collection (listes et arbres ne se parcourent pas de la même façon) mais, comme elles proposeront toutes les outils ci-dessus, on trouve pratique de les considérer comme héritières d un même modèle de classe afin de fixer une fois pour toutes les noms de leurs méthodes d instance. Cette notion de modèle de classe existe en Java sous le nom de interface et l API de Java en propose deux pour le parcours des collections : Enumeration et Iterator. Vous pourrez les chercher dans l API mais voici la déclaration de la plus simple d entre elles : public interface Enumeration { public boolean hasmoreelements () ; public Object nextelement () ; 2. Toutes les clefs du sous-arbre gauche sont inférieures à la clef de la racine, elle-même inférieure à toutes les clefs du sous-arbre droit. 3. Ce ne sera quand même pas inutile de disposer d une méthode isbst quand, plus tard, on se livrera à de l arboriculture plus tordue et qu on voudra vérifier qu on ne fait pas n importe quoi! 4

Et, pour qu une classe MyEnumeration hérite de ce modèle, il suffira qu elle soit déclarée de la façon suivante : public class MyEnumeration implements Enumeration { // Attribut // (souvent une collection partielle intermédiaire) public MyEnumeration (...) { // corps du constructeur : initialise l attribut // à partir de la collection passée en paramètre public boolean hasmoreelements () { // corps : l attribut est-il vide? public Object nextelement () { // corps : retire un élément de l attribut // en ajoute éventuellement d autres // et renvoie l élément retiré Enfin, pour faire le parcours d une collection en traitant chaque élément, il suffira, utilisant complètement la notion d héritage, d écrire : Enumeration foo = new MyEnumeration(myCollection) ; while (foo.hasmoreelements()) deal(foo.nextelement()) 4.1 Parcours en profondeur Les trois parcours d arbre en profondeur, préfixe, infixe et postfixe, ne donneront pas lieu à exercices puisqu on fait simplement de la récupération. En effet, la classe Vector que vous connaissez déjà propose une méthode d instance elements() qui renvoie un objet de type Enumeration. Il nous suffira donc de recopier un BinaryTree dans un Vector, ce que font récursivement les méthodes fillprefixed, fillinfixed et fillpostfixed de la classe Node et d appeler simplement la méthode elements() sur ce vecteur pour obtenir les trois énumérations dans la classe BinaryTree. Regardez comment on fait et comment ces énumérations sont utilisées dans la classe TestBinaryTree. 4.2 Parcours en largeur Malheureusement, la technique ne marche plus pour le parcours en largeur car on ne voit pas bien comment recopier un arbre dans un vecteur en suivant cet ordre bizarre qui ne cesse de sauter de branche en branche! La solution est d utiliser une file d attente comme collection intermédiaire, file d attente qui varie au cours de l énumération. Les diverses façons d implémenter la notion de file d attente n ont pas encore été traitées en cours mais vous avez déjà fait la queue à la poste ou attendu chez le dentiste et vous connaissez bien le principe : on quitte la file quand on est devenu le premier et, quand on arrive, on se met en dernier! Une classe Queue qui implémente 4 cette notion vous est 4. On a choisi une implémentation (avec des pointeurs) un peu sophistiquée pour que vous ne soyiez pas tentés de vous y intéresser pour l instant! 5

fournie dans les Documents de cours avec ses trois méthodes d instance isempty, enqueue (arriver) et dequeue (sortir) et vous n aurez aucune difficulté à l utiliser. L algorithme du parcours en largeur est alors le suivant : initialisation: on crée une queue vide on y met la racine de l arbre à chaque étape : on fait sortir le premier (c est lui qui sera renvoyé) ; on met à la queue son sous-nœud gauche et son sous-nœud droit (ils attendront que la fin du niveau supérieur et le début de leur niveau soient sortis pour sortir à leur tour). Pour changer un peu (et parce que ses méthodes ont des noms plus simples) on a choisi d utiliser le modèle de classe Iterator pour définir une classe BreadthIterator. Comme la classe Node, elle sera interne à la classe BinaryTree, privée (elle ne sert que là) et statique (il n y en a pas une pour chaque instance d arbre mais une seule, commune à tous les arbres). d. Implémentez la classe BreadthIterator et la méthode breadthtraversal de telle sorte que les lignes 50 à 54 de la classe TestBinaryTree fassent leur travail. Vous vous servirez du schéma général d implémentation et de l algorithme donnés plus haut. Remarque : En allant regarder dans l API pour savoir ce qu il faut mettre dans cette classe vous verrez qu un objet Iterator permet aussi de supprimer des éléments de la collection pendant le parcours. Comme il est hors de question de le faire ici, vous utiliserez pour cette méthode l implémentation suivante qui coupera court à toute mauvaise tentation : public void remove () { throw new UnsupportedOperationException(" removing not allowed ") ; 5 Squelette Le squelette, trop long pour être reproduit ici est composé de quatre classes : Queue : outil du parcours en largeur, elle n est pas à étudier : vous pourrez y revenir plus tard quand vous aurez eu le cours sur les files d attente ; Key : elle encapsule la notion générale de clef et en donne une implémentation avec des chaînes de caractères : utilisée par les classes suivantes, elle ne donne lieu à aucun exercice ; BinaryTree : c est votre classe de travail, beaucoup est fourni (mais à étudier et comprendre) et il ne reste que quelques trous à combler... TestBinaryTree : elle vous permettra de tester votre travail ; il vous suffira de retirer les marques de commentaires au fur et à mesure que vous aurez écrit les méthodes correspondantes. Toutes ces classes sont compilables et TestBinaryTree est exécutable en l état. 6