LISTES
OBJECTIFS Apprendre à utiliser les listes fournies dans la librairie standard de Java (interface List) Apprendre à utiliser les « itérateurs » pour parcourir des listes Comprendre l’implantation des listes chaînées Faire la différence entre types de données abstraits et concrets Connaître l’efficacité des opérations fondamentales des listes et des tableaux Se familiariser avec les types pile et queue 4/20/2019 IFT1020
CODES List.java (interface) ArrayList.java LinkedList.java Stack.java SLLNode.java DLLNode.java Stack.java Queue.java Ainsi que plusieurs tests 4/20/2019 IFT1020
Types Abstraits de Données (Abstrat Data Types – ADT) Le type abstrait de données définit les opérations fondamentales sur les données (concept d’interface) Le type abstrait de données ne spécifie par l’implantation. 4/20/2019 IFT1020
ADT Liste abstraite Une séquence ordonnée d’éléments pouvant être parcourue dans l’ordre, permettant l’insertion et le retrait d’éléments à n’importe quelle position, … Tableau abstrait Une séquence ordonnée d’éléments permettant des accès directs en spécifiant la position par un index entier. 4/20/2019 IFT1020
Vue abstraite d’une liste implantée avec un tableau Premier élément Dernier élément 4/20/2019 IFT1020
Vue concrète d’une liste implantée avec un tableau 4/20/2019 IFT1020
Allons voir le code de List.java et de ArrayList.java… 4/20/2019 IFT1020
Efficacité des opérations principales de ArrayList Ajouter et retirer un élément En moyenne n/2 éléments doivent être déplacés Dans la notation grand-O, O(n) Accès aléatoires Direct avec des index dans le tableau. Dans la notation grand-O, O(1) 4/20/2019 IFT1020
Coût pour agrandir le tableau dynamiquement Pour n insertions, on a agrandi le tableau lorsque nous avions n/2, n/4, n/8, … éléments Il a fallu mettre dans un nouveau tableau ces éléments chaque fois, càd n/2 + n/4 + n/8 + … n(1/2 + 1/4 + 1/8 +…) Lorsque n tend vers l’infini, la série ½ + ¼ + … tend vers 1, pour n éléments on a donc recopié n(1) = n éléments. Conséquemment, le coût associé pour agrandir le tableau dynamiquement, lorsque n est grand, est dans O(n). Ce coût, amorti sur les n éléments insérés, est de n/n, soit sans la notation grand-O, O(1). 4/20/2019 IFT1020
Iterator… La classe interne (inner) GDIterator donne accès aux éléments de la liste en les parcourant de gauche à droite. GDIterator « protège » la liste tout en permettant d’accéder à ses éléments. GDIterator « encapsule » les positions des éléments de la liste. 4/20/2019 IFT1020
Vue conceptuelle de GDIterator next next next … next GDIterator 4/20/2019 IFT1020
Iterator… La méthode iterator de la classe ArrayList retourne un object de la classe GDIterator. ArrayList liste = . . . Iterator iterateur = liste.iterator(); 4/20/2019 IFT1020
Iterator… La méthode next déplace l’itérateur vers la droite iterateur.next(); next jète (throws) une NoSuchElementException si l’itérateur est à la fin de la liste (car il n’y a plus d’élément suivant) 4/20/2019 IFT1020
Iterator… hasNext retourne true s’il existe un élément suivant if(iterateur.hasNext()) iterateur.next(); 4/20/2019 IFT1020
Iterator… La méthode next retourne l’objet parcouru de manière à effectuer un traitement sur cet objet while iterateur.hasNext() { Object obj = iterateur.next(); //faire quelque chose avec l’objet } 4/20/2019 IFT1020
Allons voir le code de TestArrayList.java… 4/20/2019 IFT1020
On peut implanter equals avec deux itérateurs… 4/20/2019 IFT1020
Listes chaînées La liste chaînée est une implantation alternative au tableau pour des listes. Une liste chaînée est composée d’un certain nombre de nœuds (nodes), ou liens (links), dont chacun possède une référence sur le noeud suivant. Ajouter et retirer un noeud au milieu d’une liste chaînée est efficace, O(1), comparativement à une implantation avec tableau, O(n). Visiter les noeuds d’une liste chaînée séquentiellement est efficace. Par contre, l’accès aléatoire à un noeud quelconque n’est pas efficace, O(n). 4/20/2019 IFT1020
Vue abstraite d’une liste chaînée 4/20/2019 IFT1020
Vue concrète d’une liste chaînée LinkedList 0 1 2 SLLNode SLLNode SLLNode Object Object Object 4/20/2019 IFT1020
Allons voir le code de SLLNode.java… 4/20/2019 IFT1020
SLLNode SLLNode Object element SLLNode successeur 4/20/2019 IFT1020
Allons voir le code de LinkedList.java… 4/20/2019 IFT1020
LinkedList LinkedList int longueur SLLNode premier SLLNode dernier 4/20/2019 IFT1020
constructeur LinkedList int SLLNode null 4/20/2019 IFT1020
add(0, x) node(0) nouveau premier node(1) SLLNode nouveau = new SLLNode(x, null); nouveau.successeur = premier; premier = nouveau; 4/20/2019 IFT1020
add(0, x) : cas premier == null if(nouveau.successeur == null) dernier = nouveau; premier dernier nouveau SLLNode nouveau = new SLLNode(x, null); nouveau.successeur = premier; premier = nouveau; 4/20/2019 IFT1020
add(i, x) node(i-1) node(i) nouveau node(i+1) predecesseur SLLNode nouveau = new SLLNode(x, null); SLLNode predecesseur = noeud(i-1); nouveau.successeur = predecesseur.successeur; predecesseur.successeur = nouveau; 4/20/2019 IFT1020
add(i, x) : cas du dernier if(nouveau.successeur == null) dernier = nouveau; node(i-1) predecesseur dernier dernier nouveau SLLNode nouveau = new SLLNode(x, null); SLLNode predecesseur = noeud(i-1); nouveau.successeur = predecesseur.successeur; predecesseur.successeur = nouveau; 4/20/2019 IFT1020
add(x) dernier nouveau dernier = nouveau; dernier SLLNode nouveau = new SLLNode(x, null); dernier.successeur = nouveau; 4/20/2019 IFT1020
add(x) : cas premier == null dernier = nouveau; premier dernier nouveau SLLNode nouveau = new SLLNode(x, null); premier = nouveau; 4/20/2019 IFT1020
remove(0) vieilElement premier node(0) node(0) node(1) vieilElement = premier.element; premier = premier.successeur; return vieilElement; 4/20/2019 IFT1020
remove(0) : cas premier == dernier node(0) dernier vieilElement vieilElement = premier.element; dernier = null; premier = premier.successeur; return vieilElement; 4/20/2019 IFT1020
remove(i) vieilElement node(i-1) predecesseur vieux node(i) node(i+1) SLLNode predecesseur = noeud(i-1); SLLNode vieux = predecesseur.successeur; vieilElement = vieux.element; predecesseur.successeur = vieux.successeur; return vieilElement; 4/20/2019 IFT1020
remove(i) : cas vieux == dernier node(i-1) predecesseur vieux node(i) dernier vieilElement SLLNode predecesseur = noeud(i-1); SLLNode vieux = predecesseur.successeur; vieilElement = vieux.element; predecesseur.successeur = vieux.successeur; dernier = predecesseur; return vieilElement; 4/20/2019 IFT1020
constructeur de l’itérateur prochain premier courant prochain = premier; precedent courant = precedent = null; 4/20/2019 IFT1020
next de l’itérateur : premier appel prochain premier elementSuivant Object elementSuivant = prochain.element; precedent = courant; courant courant = prochain; precedent prochain = prochain.successeur; 4/20/2019 IFT1020
next de l’itérateur : deuxième appel prochain courant premier elementSuivant precedent courant Object elementSuivant = prochain.element; precedent = courant; courant = prochain; precedent prochain = prochain.successeur; 4/20/2019 IFT1020
next de l’itérateur : appels subséquents courant precedent courant prochain precedent Object elementSuivant = prochain.element; precedent = courant; courant = prochain; prochain = prochain.successeur; 4/20/2019 IFT1020
remove de l’itérateur : precedent == null prochain premier courant premier = premier.successeur; courant = precedent; precedent 4/20/2019 IFT1020
remove de l’itérateur courant prochain precedent precedent.successeur = courant.successeur; courant = precedent; 4/20/2019 IFT1020
Retirer des éléments d’une liste Cette boucle retire tous les objets qui satisfont une condition while(iterator.hasNext()) { Object obj = iterator.next(); if(obj rempli condition) iterator.remove(); } 4/20/2019 IFT1020
Allons voir le code de TestLinkedList.java… 4/20/2019 IFT1020
Vue abstraite d’une liste doublement chaînée 4/20/2019 IFT1020
Allons voir le code de DLLNode.java… 4/20/2019 IFT1020
add(i, x) // dans une liste doublement chaînée node(i-1) predecesseur node(i) node(i+1) nouveau DLLNode nouveau = new DLLNode(x, null, null); DLLNode predecesseur = noeud(i-1); nouveau.successeur = predecesseur.successeur; nouveau.predecesseur = predecesseur; predecesseur.successeur.predecesseur = nouveau; predecesseur.successeur = nouveau; 4/20/2019 IFT1020
ADT Stack Insertion et suppression d’éléments à une seule extrémité de la liste Appelé traditionnellement le top (dessus) de la pile Les nouveaux éléments sont ajoutés sur le top de la pile (push) et les éléments sont retirés du top de la pile (pop) La pile est une structure LIFO : last in, first out Pensez à une pile d’assiettes ou de livres 4/20/2019 IFT1020
Allons voir le code de Stack.java et testStack.java… 4/20/2019 IFT1020
Applications pour des piles Récursivité. Vérification du balancement de parenthèses ou d’accolades dans les programmes. Évaluation d’expressions arithmétiques. Vérification de palindromes. … 4/20/2019 IFT1020
Allons voir le code de Accolades.java… 4/20/2019 IFT1020
ADT Queue (File) Les éléments sont ajoutés à la queue (tail) de la liste Les éléments sont retirés à la tête (head) de la liste Appelée FIFO, first in, first out Pensez à une file d’attente 4/20/2019 IFT1020
Allons voir le code de Queue.java et TestQueue.java… 4/20/2019 IFT1020