ITI 1521. Introduction à l’informatique II Laboratoire 9 Hiver 2016 Objectifs d’apprentissage • Concevoir une liste doublement chaînée possédant aussi un noeud factice • Modifier l’implémentation d’une liste chaînée afin d’y ajouter des méthodes. • Résoudre des problèmes exigeant une bonne compréhension des interfaces. OrderedStructure Pour ce laboratoire, vous devez créer une implémentation de l’interface OrderedStructure à l’aide de noeuds doublement chaînés et d’un noeud factice. L’interface OrderedStructure déclare les méthodes suivantes. • int size() ; • boolean add(Comparable obj) ; • Object get(int pos) ; • void remove(int pos). Consultez les notes du cours ainsi que les Figures 1, 2, 3, et 4 pour des exemples de liste doublement chaînées avec un noeud factice. Les implémentations de cette interface doivent sauvegarder les éléments en ordre croissant. L’ordre des éléments est défini par l’implémentation de la méthode compareTo(Object other) que déclare l’interface Comparable. Les classes Integer et String implémentent toutes les deux cette interface et peuvent donc servir pour vos tests. IMPORTANT : puisque l’objectif principal du laboratoire est de bien maîtriser les concepts liés à l’implémentation des listes chaînées, par souci de simplicité, nous n’utiliserons pas le concept de type générique («generics»). Ainsi, 1) le compilateur produira quelques avertissements. Mais surtout, 2) les utilisateurs de la méthode get devront forcer une conversion de type puisque la valeur de retour est de type Object. Il y a à la fin du laboratoire un exercice (optionnel) où vous devez produire un type générique. La solution sera publiée la semaine prochaine. Fichiers • OrderedStructure.java • Documentation 1 1 OrderedList 1. Créez une implémentation de l’interface OrderedStructure. L’implémentation, OrderedList, doit utiliser des noeuds doublement chaînés, ainsi qu’un noeud factice. La classe doit posséder une référence head vers le noeud factice. De plus, l’implémentation doit lancer toutes les exceptions nécessaires. Voir OrderedStructure. (a) Nous allons développer cette implémentation étape par étape, de haut en bas. C’est-à-dire que nous allons d’abord implémenter les éléments de haut niveau (variables d’instance, classe imbriquée statique, et des coquilles pour chacune des méthodes). Une fois tout ça en place, nous implémenterons le corps des méthodes, une à une. Premièrement, vous devez créer une définition initiale. Pour l’instant, nous ignorons l’implémentation des méthodes afin de nous concentrer sur les variables et la nécessité d’une classe « static » imbriquée afin de représenter les noeuds de la liste. Pour satisfaire les exigences du compilateur, toutes les méthodes de l’interface OrderedStructure doivent être déclarées. La classe doit donc contenir une classe Node, les variables d’instance et des déclarations vides pour chacune des méthodes de l’interface. Le compilateur n’acceptera pas des déclarations vides pour les méthodes retournant une valeur. Vous pourriez inclure un énoncé de retour bidon, retourner la valeur -99 pour la méthode size, sachant que cet énoncé sera remplacé par une implémentation complète éventuellement. Cependant, il se peut que vous oubliiez de faire ces changements et l’ensemble de la classe deviendrait difficile à déboguer. Pour cette raison, je préfère créer une définition initiale ne contenant que l’énoncé suivant. throw new U n s u p p o r t e d O p e r a t i o n E x c e p t i o n ( " not implemented y e t ! " ) ; Ça nous permet de compiler la classe et de travailler sur l’implémentation des méthodes une à une. Toute tentative d’utiliser une méthode qui n’a pas encore d’implémentation sera signalée par une exception ! Vous pouvez demander des explications supplémentaires à votre aide à l’enseignement si nécessaire. Créez une classe test, OrderedListTest. Pour l’instant, elle ne contient qu’une méthode principale déclarant une variable de type OrderedList, désignant un objet OrderedList. (Vous pouvez utiliser JUnit si vous le souhaitez.) Assurez vous que l’implémentation partielle comprenne tous les éléments ci-haut et qu’elle compile parfaitement. Lorsque ce sera fait, vous pouvez procéder à la prochaine étape, l’implémentation de la méthode size. Fichiers • OrderedStructure.java • OrderedList.java • OrderedListTest.java (b) Implémentez la méthode size(), remplacez l’énoncé throw par une implémentation itérative, traversant la liste et comptant ses éléments. Ajoutez un test à la classe test afin de vous assurer que la méthode fonctionne pour la liste vide. Nous ajouterons d’autres tests lorsque nous aurons une méthode add. Fichiers • OrderedStructure.java • OrderedList.java • OrderedListTest.java 2 (c) Implémentez la méthode boolean add(Comparable obj) ; elle ajoute un élément en ordre croissant selon l’ordre naturel imposé par la classe de l’objet (i.e. sa méthode compareTo). Retourne true si l’élément a été ajouté à cette liste ordonnée, et false sinon. (d) Ajoutez quelques tests afin de valider la méthode add. Il sera difficile d’évaluer la méthode proprement, mais au moins la taille de la liste devrait s’accroître à mesure que des éléments sont ajoutés à la liste. (e) Implémentez Object get(int pos). Cette dernière retourne l’élément se trouvant à la position spécifiée de cette liste ordonnée ; le premier élément se trouve à la position 0. Cette opération ne doit pas transformer la liste ; (f) Ajoutez des tests afin de valider les méthodes get et add. Nous sommes maintenant en bien meilleure position pour évaluer les méthodes add, get et size. En particulier, nous pouvons ajouter des éléments, utiliser une boucle afin d’accéder aux éléments, un à un, à l’aide de la méthode get. Assurez-vous que toutes les méthodes fonctionnent bien avant de poursuivre. Fichiers • OrderedStructure.java • OrderedList.java • OrderedListTest.java (g) Implémentez void remove(int pos) ; Retire l’élément à la position spécifiée de cette liste ordonnée ; le premier élément se trouve à l’index 0. (h) Ajoutez des tests afin de valider la méthode remove. Assurez-vous que cette méthode fonctionne (ainsi que les autres) avant de poursuivre. Fichiers • OrderedStructure.java • OrderedList.java • OrderedListTest.java Nous avons maintenant une implémentation complète de l’interface OrderedStructure. 2. Ajoutez la méthode d’instance void merge(OrderedList other) qui ajoute tous les éléments de la liste other à cette liste tout en préservant l’ordre des éléments. Par exemple, si a et b sont deux listes ordonnées telles que a contient “D”, “E” et “G”, et b contient “A”, “C”, “D” et “F”, alors l’appel a.merge(b) transforme a de sorte qu’elle contient maintenant les éléments suivants “A”, “C”, “D”, “D”, “E”, “F” et “G” ; b demeure inchangée par cet appel. Cet exercice a pour but d’apprendre à traverser et transformer des listes doublement chaînées. Ainsi, vous ne devez pas utiliser des méthodes auxiliaires, en particulier, n’utilisez pas la méthode add ! Votre implémentation doit traverser les deux listes et insérer les éléments (valeurs) de l’autre liste dans celle-ci ; en ordre croissant. Rappelez-vous qu’il est préférable de développer ces habiletés maintenant, plutôt qu’à l’examen final ! Fichiers • OrderedStructure.java • OrderedList.java • OrderedListTest.java 3. Sujet avancé et optionnel Utilisez votre implémentation de la classe OrderedList comme point de départ afin de créer un type générique («generics») qui réalise l’interface OrderedStructure suivante : 3 public i n t e r f a c e O r d e r e d S t r u c t u r e <T extends Comparable<T>> { int s i z e ( ) ; boolean add (T elem ) throws I l l e g a l A r g u m e n t E x c e p t i o n ; T g e t ( i n t pos ) throws IndexOutOfBoundsException ; void remove ( i n t pos ) throws IndexOutOfBoundsException ; } L’un des avantages marqués de cette implémentation sera que tous les éléments de la liste auront le même type. Ce qui est très important pour la méthode compareTo. • OrderedStructure.java • OrderedList.java • OrderedListTest.java 2 Quiz (1 point) Pour l’implémentation de l’interface List à l’aide d’un tableau, ArrayList. 1. Les insersions aux positions intermédiaires de la liste sont toujours rapides. 2. L’ajout au début de la liste est toujours rapide. 3. Le retrait d’un élément est toujours rapide. 4. Consulter les positions intermédiaires de la liste est toujours rapide. Inscrivez votre réponse à la question ci-dessus dans le champ Soumission : de la page de soumission du devor (voir ci-dessous) ; • https://uottawa.blackboard.com/ Appendice l head size 0 Figure 1 – Une liste vide. Dernière modification : 21 mars 2016 4 l B head size 1 Figure 2 – Une liste contenant un seul élément. l D B head size 2 Figure 3 – Une liste contenant deux éléments. l B D head size 3 Figure 4 – Une liste contenant trois éléments. 5 F