Listes Chaînées
Sommaire Introduction Classe auto-référentielle Liste chaînée simple Listes triées Liste doublement chaînée Les itérateurs Chapitre 5 Data Structures & Algorithm, 2nd Edition, Robert Lafore
Introduction Tableau Taille fixe Recherche lente dans un tableau non ordonné Insertion lente dans un tableau ordonné Suppression lente dans les deux cas Liste chaînée : solution à certains de ces problèmes Structure la plus souple après les tableaux Convient dans plusieurs cas : pile et file Les listes chaînées sont des collections d'éléments de données alignés en une seule rangée. Structure permettant les insertions et les suppressions n'importe où. Les listes chaînées : particulièrement adaptées lorsque le nombre d'éléments à représenter est imprévisible. Les listes chaînées sont dynamiques. Les listes ne sont jamais saturées contrairement aux tableaux (sauf en cas de mémoire insuffisante). Différentes variantes : listes chaînées, listes triées, listes doublement chainées, listes avec itérateur.
Classe auto-référentielle Une classe auto-référentielle contient un membre qui consiste en une référence à un objet d'une classe de même type de classe. Exemple : class Nœud { private int donnee; private Nœud suivant; public Nœud (int donnee) {… } //constructeur public void setDonnee(int donnee) { … } // impose une valeur public int getDonne() { … } // retourne une valeur public void setSuivant( Nœud noeudSuivant) { …} //définit la valeur de suivant public void getSuivant( Nœud noeudSuivant) { … } //renvoie la valeur de suivant }
Classe auto-référentielle La classe Nœud définit un type Nœud qui comporte : une variable d'instance donnée de type entier une variable d'instance suivant de type Noeud le membre suivant référencie un objet de type Nœud : classe auto-référentielle le membre suivant : relie un objet de type Nœud à un autre du même type Structure de données liste : relier des objets auto- référentiels entre eux Nœud 1 Nœud 2
Classe auto-référentielle
Classe auto-référentielle Exemple : class Link { public int iData; //donnée public double dData; // donnée public Link next; //référence vers lien suivant … } public Personne p; //objet donnée public Link next; //référence vers lien suivant }
Classe auto-référentielle Rappel : Différence entre une donnée primitive et un objet Soit la déclaration suivante : double salaire = 300.0; création d'un espace mémoire et rangement de la valeur 300.0 Soit la déclaration suivante : Link somelink; somelink = new Link(); réservation d'un emplacement pour une référence à un objet de type Link allocation d'un espace mémoire pour un objet de type Link et placement de sa référence dans somelink Link aLink = somelink; // range la référence somelink dans alink
Liste chaînée simple La liste chaînée est une collection linéaire d'objets de classe auto- référentielle appelés nœud, reliés entre eux. Accès à une liste chaînée : référence au premier nœud de la liste. Accès au nœud suivant : membre de référence de lien stocké dans le nœud précédent. Référence dans le dernier lien est mise à null. Les données sont stockées dynamiquement dans la liste chaînée : chaque nœud est créé si nécessaire. Un nœud contient des données de tout type. Implémentation de la pile et de la file : liste chaînée.
Liste chaînée simple Opérations: Parcourir une liste Insérer une valeur au début d'une liste Remplacer la valeur du début d'une liste Savoir si une liste est vide Supprimer un élément dans une liste : recherche et suppression de l'élément trouvé Suppression et insertion : aucun déplacement Les nœuds d'une liste ne sont pas stockés dans des zones contiguës de la mémoire Contiguïté du point de vue logique
Liste chaînée simple Opérations: Insertion au début de la liste Opération facile : first pointe le début de la liste Public void insertFirst(int id, double dd) { Link newLink = new Link (id, dd); //création du nouvel élément non connecté newLink.next = first; // connection first = newLink; } création d'un nouvel élément next du nouvel élément reçoit first first reçoit la référence du nouvel élément crée
Liste chaînée simple Opérations: Insertion au début de la liste
Liste chaînée simple Opérations: Suppression au début de la liste Inverse de l'opération précédente Public Link deleteFirst() { Link temp = first; //sauvegarde du lien vers le nœud à supprimer first = first.next; // suppression return temp; //renvoie du lien supprimé } déconnecter le premier élément en faisant pointer first sur le second nœud Remarque : on suppose que la liste n'est pas vide.
Liste chaînée simple Opérations: Suppression au début de la liste
Liste chaînée simple Opérations: Affichage (parcourir la liste) Parcourt de la liste Suivre la chaîne de référence d'un lien vers le suivant Public void displayList() { System.out.print("liste depuis le début jusqu'à la fin"); Link current = first; while (current != null) current.displayLink(); current = currrent.next; }
Liste chaînée simple Opérations: Affichage (parcourir la liste)
Liste chaînée simple Voir exemple ListeChaineeApp (classe Link)
Liste chaînée simple Voir exemple ListeChaineeApp (suite … Classe LinkList)
Liste chaînée simple Voir exemple ListeChaineeApp (suite … Classe LinkList)
Liste chaînée simple Voir exemple ListeChaineeApp (suite … méthode main)
Liste chaînée simple Opérations: Recherche de lien (nœud) spécifique Recherche d'un lien avec une clé spécifique initialisation : current = first parcourt de la liste à la recherche de l'élément clé public Link find (int key) { Link current = first; while (current.iData != key) if (current.next == null) // verifier si on a atteint la fin de la liste return null; else current = current.next; } return current;
Liste chaînée simple Opérations: Suppression de lien (nœud) spécifique Suppression d'un lien avec une clé spécifique Opération semblable à l'opération de recherche précédente Sauvegarde du lien précédent en plus du lien courant public Link delete (int key) { Link current = first; Link previous = first; while (current.iData != key) if (current.next == null) return null; else { previous = current; current = current.next; } } ….
Liste chaînée simple Opérations: Suppression de lien spécifique …. if (current == first) // Suppression du premier noeud first = first.next; // Le second noeud devient la tete de liste else previous.next = current.next // le noeud precedent est branche au noeud suivant return current; }
Liste chaînée simple Opérations: Suppression de lien spécifique
Liste chaînée simple Voir exemple ListeChaineeApp-Find (méthode delete dans la classe LinkList)
Liste chaînée simple Voir exemple ListeChaineeApp-Find (méthode find dans la classe LinkList)
Liste chaînée simple Voir exemple ListeChaineeApp-Find (méthode main)
Liste à deux entrées La liste à deux entrées est similaire à la liste simple Possède un accès directe au dernier lien, en plus de l'accès au premier lien Possibilité d'insertion en début et en fin de liste Insertion plus efficace contrairement à la liste ordinaire Implémentation : queue Suppression du dernier lien non efficace
Liste à deux entrées (insertion) public void insertLast (double dd) { Link newLink = new Link( dd); if ( isempty ()) first = newLink; else last.next = newLink; // le nouveau noeud est connecte a la liste last = newLink; // MAJ de last qui pointe sur le dernier nœud ajoute }
Liste à deux entrées (insertion)
Liste à deux entrées (Voir exemple ListeChaineeDeuxEntree)
Liste à deux entrées (Voir exemple ListeChaineeDeuxEntree) Suite de la classe FirstLastList
Liste à deux entrées (Voir exemple ListeChaineeDeuxEntree) Méthode main()
Liste chaînée Efficacité Liste chaînée Tableau Insertion et suppression très rapide en début de liste O(1) time Suppression, recherche et insertion par rapport O(N) comparaisons à une clé spécifique : O(N) comparaisons Plus rapide moins rapide, moins efficace Efficacité croissante : copie > comparaison Taille flexible : dynamique taille fixe à la création
Liste triée Liste triée : liste dont les éléments sont triés selon un certain critère. Application : dans la plupart des situations dans lesquelles on utilise le tableau trié. Avantage : insertion plus rapide que dans le cas du tableau taille flexible Inconvénient : implémentation plus difficile. Implémentation : queue de priorité.
Liste triée (insertion) // creation d’un element de type Link //initialiser previous à null // initialiser current à first while (current != null && key > current.dData) // parcourir la liste a la recherche de // l’element cle { previous = current; current = current.next; } if (previous == null) // insertion du premier element first = newLink; else previous.next = newLink; // connection du nouvel element au noeud previous newLink.next = current; // connection du nouvel element au noeud suivant ….
Liste triée (efficacité) Insertion et suppression : O(N) comparaisons Recherche ou suppression de la valeur minimale : O(1) time Application : accès fréquent à l’élément minimal et insertion rapide non importante Implémentation : queue de priorité
Liste triée (opération de tri) Liste triée : offre un mécanisme de tri efficace Processus : À partir d’un tableau non trié Prendre chaque élément du tableau Insérer chaque élément dans une liste triée Recopier toute la liste triée dans le tableau Tri plus efficace que le tri par insertion Nécessite peu de copies O(N2)
Liste triée (Voir exemple ListeTriee) Classe SortedList
Liste triée (Voir exemple ListeTriee) Classe SortedList …
Liste triée (Voir exemple ListeTriee) Méthode main()
Liste doublement liée Liste simple : offre un seul sens de traversée (directe). Liste double : permet de traverser la liste dans les deux sens (directe et indirecte). Chaque lien dispose de deux références : suivant et précédent. Mise à jour possible de quatre références en cas de suppression ou d’insertion La liste peut être traversée dans les deux sens : par les pointeurs first ou last class Link { public long dData; public Link next; // lien suivant public Link previous; // lien precedent … }
Liste doublement liée
Liste doublement liée Opérations: insertion au début de la liste … if (isEmpty()) last = newLink ; else first.previous = newLink ; newLink.next = first; first = newLink;
Liste doublement liée Opérations: insertion au début de la liste
Liste doublement liée Opérations: insertion après un élément (nœud) de la liste if (current == last) { newLink.next = null; last= newLink; } else newLink.next = current.next; current.next.previous = newLink; newLink.previous = current; current.next = newLink; ….
Liste doublement liée Opérations: insertion après un élément (nœud) de la liste
Liste doublement liée Opérations: insertion à la fin de la liste … If (current == last) { newLink.next = null; last= newLink; } else newLink.next = current.next; current.next.previous = newLink; newLink.previous = current; current.next = newLink;
Liste doublement liée Opérations: suppression d’un élément au début de la liste … if (first.next ==null) // un seul élément last = null; else first.next.previous =null; first= first.next;
Liste doublement liée Opérations: suppression d’un élément à la fin de la liste … if (first.next ==null) // un seul élément first = null; else last.previous.next =null; last = last.previous;
Liste doublement liée Opérations: suppression d’un élément de la liste … if (current ==first) first = current.next; else current.previous.next = current.next; if (current ==last) last = current.previous current.next.previous = current.previous
Liste doublement liée Opérations: suppression d’un élément de la liste
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList)
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList …)
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList …)
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList …)
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList …)
Liste doublement liée Voir exemple ListeChaineeDouble (Classe DoublyLinkedList …)
Liste doublement liée Voir exemple ListeChaineeDouble (méthode main())
Les itérateurs Notions d’itérateurs Un itérateur est un objet capable de se déplacer d'un élément à l'autre vers le haut ou vers le bas de la liste (ou de gauche à droite). Il remplace l'indice des tableaux. L'utilisation des itérateurs pour traiter les listes est la même que l'utilisation des indices pour traiter les tableaux. Les itérateurs permettent le parcours de la structure ou d'une partie de celle-ci Accès à un lien : incrémentation de la référence.
Les itérateurs Classe itérateur Question : Où doit - on définir ce type de référence ? Deux solutions : Champs définit à l’intérieur d’une classe Classe à part classe itérateur Le champs current contient une référence vers le lien actuellement référencé par l'itérateur. Utilisation : création de la liste et création d'un objet iterator associé à celle- ci.
Les itérateurs Classe itérateur Classe à part Class ListIterator { private Link current; … } LinkList theList = new LinkList(); //création de la liste ListIterator iter1 = theList.getIterator(); // création de l'itérateur Link aLink = iter1.getCurrent(); //accès au lien Iter1.nextLink(); // passer au lien suivant