Title: Structure de donn
1Structure de données Liste
- IFT1025, Programmation 2
- Jian-Yun Nie
2Points importants
- Utilité dune structure de données
- Comment utiliser une structure de données de
liste existante - Comment programmer pour gérer soi-même une liste
- Dautres structures souvent utilisées en
informatique (arbre, pile, )
3Pourquoi une structure de données?
- Structure de données
- Une organisation des informations
- Pour regrouper une série de données de nature
similaire (tableau, liste, ) - Pour mieux regrouper les informations pour le
même concept (classe, ) - Traditionnellement
- Structure de données
- Traitement
- Maintenant
- Classe structure de données et traitements
4Structures de données déjà vues
- Tableau (Array) pour organiser une séquence de
données - int a new int 10
- Similairement String
- Classe pour regrouper les attributs du même
concept - public class C
-
- int a
- String name
-
- C ref new C()
a
ref
int a String name
0
null
5Liste
- Utilité pour organiser une séquence de données
- Une structure plus flexible que tableau
Tableau Liste
Taille fixe Taille variable
Ordre entre éléments Ordre selon les liens
Insertion et enlèvement difficile Plus facile
Accès rapide Plus lent
6Illustration
- Entête (Tête) réfère au premier noeud
- noeuds enchaînés
- Chaque noeud enchaîné
- Valeur stockée (A, B, )
- Référence (lien, pointeur) vers le prochain nœud
7Structure de données Liste
- Deux parties
- Structure pour lentête
- Référence vers le premier nœud
- Dautres attributs optionnels
- Référence vers le dernier nœud
- Nombre de nœuds
-
- Structure pour nœud
- Structure (ou classe) pour le stockage dune
valeur - Référence vers le prochain nœud
- Optionnel
- Référence vers le nœud précédent (liste
doublement chaînée)
8Définition dune liste simplement chaînée
- Entête contenant une référence
- public class Liste
-
- Noeud premier
- // méthodes pour traiter une liste
-
- Nœud contenant un int
- public class Noeud
-
- int valeur
- Noeud prochain
- public Noeud (int v, Noeud p)
-
- valeur v
- prochain p
-
9Création
- Créer une entête
- Liste l new Liste()
- Créer des nœuds
- l.premier new Noeud(1,
- new Noeud(2,
- new Noeud(3,null)))
-
l
null
l
1
2
3
null
10Traverser une liste (tout se fait dans Liste)
- public class Liste
-
-
- public void print()
-
- Noeud n premier
- while (n!null)
-
- System.out.print(n.valeur "-gt")
- n n.prochain
-
- System.out.println("null")
-
-
-
- 1-gt2-gt3-gtnull
11Trouver un élément
- public class Liste
-
- public Noeud trouver(int v)
-
- Noeud n premier
- while (n ! null n.valeur ! v)
- n n.prochain
- return n
-
-
12Déterminer la longueur
- public class Liste
-
- public int longueur()
-
- Noeud n premier
- int nb0
- if (premier null) return 0
- while (n ! null)
-
- nb
- n n.prochain
-
- return nb
-
-
-
13Ajouter un élément au début
- public class Liste
-
- public void ajoutDebut(int v)
-
- premier new Noeud(v, premier)
-
-
-
l
1
2
3
null
5
14Ajouter un élément à la fin
- public class Liste
-
- public void ajoutFin(int v)
- Noeud n premier
- // cas 1 aucun autre élément ajouté
- if (premier null) premier new
Noeud(v,null) - // cas 2 il y a déjà des éléments
- else
- while (n.prochain ! null) n n.prochain
- n.prochain new Noeud(v,null)
-
-
-
-
- Attention tester sur le prochain
- Pas de limite de taille
l
1
2
3
null
5
n
15Enlever un élément
- Besoin de garder la référence sur le précédent
élément - Tester sur le prochain
- public class Liste
-
- public void enlever(int v)
-
- Noeud n premier
- // cas 1 Si le premier est null
- if (premier null) return
- // cas 2 Si le premier est à enlever
- if (premier.valeur v)
-
- premier premier.prochain
- return // On pourrait aussi vouloir retourner
le neoud enlevé -
- // cas 3 sinon, tester sur les autres éléments
- while (n.prochain ! null n.prochain.valeur
! v) n n.prochain - if (n.prochain ! null) n.prochain
n.prochain.prochain -
Attention à lordre des tests
16Concatenation de 2 listes
- public class Liste
-
- public void concat(Liste l)
-
- if (premier null)
-
- premier l.premier
- return
-
- Noeud n premier
- while (n.prochain ! null) nn.prochain
- n.prochain l.premier
-
-
-
// Aller à la fin
17Traitement récursif
- Itératif Liste suite déléments
- Traitement typique parcourir la liste avec while
- Récursif Liste un élément reste (une plus
petite liste) - Traitement récursif
- Traiter un élément
- Traiter le reste par un appel récursif
- Décomposition générale
- Cas 1 liste vide ou un seul élément (cas darrêt
de récursion) - Cas 2 liste non vide
- Lélément courant
- Appel récursif pour la suite
18Déterminer la longueur(Deux niveaux de
traitement)
- Longueur
- 1, si la liste contient un seul élément
- 1 longueur du reste, sinon.
- public class Liste
- Noeud premier
- public int longueur()
-
- if (premier null) return 0
- else return premier.longueur()
-
-
- public class Nœud // Premier option utiliser la
récursion sur les noeuds - public int longueur()
-
- // cas 1 pas de récursion
- if (prochainnull) return 1
- // cas 2 récursion
- else return 1 prochain.longueur()
Cet appel est possible seulement quand
premier!null
19Structure générale
- Class Liste
- public int longueur()
- appel à la méthode de Nœud
-
- Class Nœud
- public int longueur()
- Cas simple retourner 1
- Cas complexe 1 appel récursif
-
20Déterminer la longueur (bis)
- public class Liste
- Noeud premier
- public int longueur()
-
- return longueur(premier)
-
- // Deuxième option utiliser la récursion dans
Liste, avec nœud comme paramètre - public int longueur(Noeud n)
-
- if (nnull) return 0
- else return 1 longueur(n.prochain)
-
Cet appel est possible même si premiernull
21Structure générale
- Classe Liste
- public int longueur()
- appel à une méthode avec Nœud comme paramètre
-
- public int longueur(Nœud n)
- déterminer la longueur à partir du nœud n
-
22Ajouter à la fin
- public class Liste
-
- public void ajoutFin(int v)
-
- // cas 1 aucun autre élément ajouté
- if (premier null) premier new
Noeud(v,null) - // cas 2 il y a déjà des éléments
- else premier.ajoutFin(v)
-
-
- public class Noeud
-
- public void ajoutFin(int v)
-
- if (prochain null) prochain new
Noeud(v,null) - else prochain.ajoutFin(v)
-
-
-
Traiter le cas dune liste vide
Ajouter un élément dans une liste non-vide
23Ajouter à la fin (bis)
- public class Liste
-
- public void ajoutFin(int v)
-
- // cas 1 aucun autre élément ajouté
- if (premier null) premier new
Noeud(v,null) - // cas 2 il y a déjà des éléments
- else ajoutFin(premier, v)
-
- public void ajoutFin(Noeud n, int v)
-
- if (n.prochain null) n.prochain new
Noeud(v,null) - else ajoutFin(n.prochain,v)
-
-
-
24Ajouter à la fin (bis-bis)
- public class Liste
-
- public void ajoutFin(int v)
-
- premier ajoutFin(premier, v)
-
- public Noeud ajoutFin(Noeud n, int v)
-
- if (n null) return new Noeud(v,null)
- else
-
- n.prochain ajoutFin(n.prochain,v)
- return n
-
-
-
-
25Réflexions
- Les façons récursives dimplanter les autres
méthodes - Enlever un élément
- Ajouter au début
- Insérer dans lordre
- Inverser la liste
- Concaténer deux liste
- Obtenir le i-ième noeud
26Complexité des opérations
- Longueur O(n)
- Trouver un élément O(n)
- Enlever un élément O(n)
- Ajouter au début O(1)
- Ajouter à la fin O(n)
- Améliorable ?
27Liste simplement chaînée amélioration
- Ajouter une référence au dernier élément pour
faciliter lajout à la fin - public class Liste
-
- Noeud premier
- Noeud dernier
- public void ajoutFin(int v)
-
- if (premiernull) premier dernier new
Noeud(v,null) - else
-
- dernier.prochain new new Noeud(v,null)
- dernier dernier.prochain
-
-
-
28Liste doublement chaînée
- Référence vers le prochain nœud
- Référence vers le précédent nœud (permettre de
reculer) - public class Noeud
-
- int valeur
- Noeud prochain
- Noeud precedent
-
29Exemple Enlever
- public class Liste
-
- public void enlever(int v)
-
- Noeud n premier
- if (premier null) return
- if (premier.valeur v)
-
- premier premier.prochain
- if (premiernull) dernier null
- return
-
- while (n ! null n.valeur ! v) n
n.prochain - if (n ! null)
-
- n.precedent.prochain n.prochain
- n.prochain.precedent n.predcedent
-
-
null
1
2
3
n
30Généralisation
- Définir un nœud pour contenir tout Object
- public class Noeud
-
- Object element
- Noeud prochain
- Noeud precedent
-
31Réflexion
- Adapter les traitements à cette structure
générale avec Object - Comment faire pour pouvoir trier une liste?
32Tableau v.s. Liste
- Tableau (array)
- Taille fixe
- Accès rapide avec index (O(1))
- Ajouter/enlever un élément plus difficile (O(n))
- À utiliser si
- Beaucoup daccès aléatoire
- Pas besoin de modifier souvent lordre des
éléments - Nombre déléments à stocker déterminée (ou une
limite existe) - Liste
- Taille flexible
- Accès plus lent (O(n))
- Ajouter/enlever un élément plus facile (O(1))
- À utiliser si
- Peu daccès aléatoire (souvent un parcours de
tous les éléments) - Nombre délément très variable
- Éléments sont souvent re-ordonnés, ajoutés ou
enlevés
33Allocation de mémoire
- La mémoire est allouée quand on crée un nœud
- Les nœuds enlevés ne sont plus utilisés
- Gabbage collector récupère les mémoires qui ne
sont plus utilisées - Pas besoin de gérer lallocation et désallocation
de mémoire en Java - On ne peut pas contrôler quand le gabbage
collector sera lancé (dépend de limplantation de
JVM) - finalize() la méthode héritée de Object, mais
quon peut remplacer - Définir des opérations à effectuer quand le
gabbage collector va récupérer cette mémoire. - Ne permet pas dévoquer le gabbage collector
- À utiliser dans certains cas spéciaux (e.g. pour
évoquer delete dun objet en C, utilisé en Java)
34De limplantation vers un type abstrait
- Implantation de Liste pour les éléments contenant
int, Object, etc. - Généralisation
- Définir les opérations sur la liste pour tout
type de données - Les opérations communes sur une liste (interface
List) - boolean add(Object o) Ajouter à la fin
- void add(int index, Object o) Ajouter à une
position - void clear() Enlever tout
- boolean contains(Object o) Contanir un élément?
- boolean isEmpty() Vide?
- boolean remove(Object o) Enlever le premier o
- int size() nombre déléments
-
- Iterator irerator() Iterator permet de
parcourir les éléments
35Implantation avec une liste chaînée
- LinkedList
- public class LinkedListltEgt extends
- AbstractListltEgt
-
- private class Node
- private E element
- private Node next
- // Create a Node containing specified element.
- public Node (E element)
- this.element element
- this.next null
-
- // end of class Node
- // end of class LinkedList
36Implantation LinkedList
- public class LinkedListltEgt extends
AbstractListltEgt -
- private int size
- private Node first
- // Create an empty LinkedListltEgt.
- public LinkedList ()
- size 0
- first null
-
-
-
37Implantation LinkedList
- Une méthode interne pour obtenir le i-ième
élément - /
- The i-th node of this LinkedList.
- The LinkedList must be non-empty.
- require 0 lt i i lt this.size()
- /
- private Node getNode (int i)
- Node p first
- int pos 0 // p is pos-th Node
- while (pos ! i)
- p p.next
- pos pos 1
-
- return p
-
public E get (int index) Node p
getNode(index) return p.element
38Implantation LinkedList
- Enlever le i-ième élément
- public void remove (int index)
- if (index 0)
- first first.next
- else
- Node p getNode(index-1)
- p.next p.next.next
-
- size size - 1
-
39Implantation avec tableau?
- ArrayList implante linterface List avec un
tableau - Possède une taille limite, mais est agrandi
automatiquement de 50 au besoin - Accès rapide avec un indexe
- Ajouter un élément O(n) pour déplacer les
éléments
40Méthodes de ArrayList
- void add(int index, Object o)
- boolean add(Object o) ajouter à la fin
- void clear()
- boolean contains(Object o)
- void ensureCapacity(int minCapacity) assurer
quil y a des places nécessaires - boolean isEmpty()
- Object remove(int index)
- Object set(int index, Object o)
- int size() numbre déléments dans la liste
- void trimtosize() enlever les espaces non
utilisé -
41Opération de tri sur une liste
- public class Liste
-
- Noeud premier, dernier
- public void concatener(Liste l) // à
réfléchir - public void quicksort()
-
- if (premier null) return
- Liste l1 new Liste()
- Liste l2 new Liste()
- this.separer(premier.valeur, l1, l2)
- l1.quicksort()
- l2.quicksort()
- l1.concatener(l2)
- premier l1.premier
-
-
42Opération de tri sur une liste
- private separer(int pivot, Liste l1, Liste l2)
-
- Noeud n premier
- while (n!null)
-
- if (n.valeurltpivot) l1.ajoutFin(n.valeur)
- else l2.ajoutFin(n.valeur)
-
- À réfléchir généralisation - trier une liste
contenant des éléments Comparable
43Iterator
- Permet de parcourir sur les éléments dune liste
(ou de nimporte quel ensemble) - Référence courant Position courante (initialisée
au premier) - Utilisation
- LinkedList list
- Iterator iter list.iterator()
- while (iter.hasNext())
-
- Object obj iter.next()
- // do something with obj
-
44Interface Interator
- boolean hasNext()
- Object next() retourner lélément courant, et
avancer la référence courante au prochain - void remove() enlever lélément courant, la
référence courante réfère au prochain élément
45Implanter Iterator pour Liste (ex.)
- public class Liste
-
- Noeud premier, dernier, courant
- public ListeIterator iterator()
- return new ListeIterator(this)
-
- public class ListeIterator implements Iterator
-
- private Liste liste
- private Noeud courant
- public ListeIterator(Liste liste) this.liste
liste courantliste.premier - public boolean hasNext() return courant !
null - public Object next() return courant if
(hasNext()) courant courant.prochain - public void remove() throw new
UnsupportedOperationException() -
- Liste liste ...
- for (Iterator i liste.iterator() i.hasNext() )
- Object obj i.next()
- // do something with obj
46Dautres types de données
- Pile (stack) premier entré, dernier sorti
- Empiler un élément
- Dépiler un élément
- Test isEmpty()
- Queue premier entré, premier sorti
- Mettre dans la queue (enqueue)
- Enlever de la queue (dequeue)
- Test isEmpty()
- Implantations (à réfléchir)
- Avec tableau (circulaire)
- Avec liste
47Arbre de recherche binaire
- Arbre
- Racine
- Enfants
- Chaque nœud a un parent
- au plus
- (0 parent pour racine)
- Arbre binaire
- Un parent peut avoir
- 2 enfants au plus
48Arbre de recherche binaire
- Arbre de recherche binaire
- Organiser les nœuds selon leurs valeurs
- Branche gauche valeurs lt valeur du parent
- Branche gauche valeurs gt valeur du parent
7
5
9
3
7
10
49Pourquoi arbre de recherche binaire?
- Recherche dans une liste O(n)
- Recherche dans un arbre de recherche binaire,
selon une valeur v - Valeur de racine r v?
- Sinon
- Si v lt r, chercher à gauche
- Sinon, chercher à droite
- Si larbre est balancé O(log n)
50Implantation en Java
- class Noeud
-
- int valeur
- Noeud gauche, droite
- public Noeud(int v, Noeud g, Noeud d)
-
- valeur v
- gauche g
- droire d
-
-
- class Arbre
-
- Noeud racine
- public void add(int v)
-
51Insertion dun noeud
- // Dans la classe Arbre
- public void add(int v)
-
- if (racine null) racine new Noeud(v, null,
null) - else racine.add(v)
-
- // Dans la classe Noeud
- public void add(int v)
-
- if (v lt valeur)
- if (gauche null) gauche new
Nœud(v,null,null) - else gauche.add(v)
-
- else
- if (droite null) droite new
Nœud(v,null,null) - else droite.add(v)
-
52Chercher un noeud
- // Dans la classe Arbre
- public Noeud chercher(int v)
-
- if (racine null) return null
- else return racine.chercher(v)
-
- // Dans la classe Nœud
- public Noeud chercher(int v)
-
- if (v valeur) return this
- else if (v lt valeur gauche ! null) return
gauche.chercher(v) - else if (v gt valeur droite ! null) return
droite.chercher(v) - else return null
53Enlever un noeud
7
5
9
- Si le nœud à enlever est une feuille
- Cas simple
- Si le nœud à enlever à une seule branche (5)
- Relier la branche directement au parent
- Sinon (7)
- Identifier le nœud juste supérieur (le nœud la
plus à gauche dans la branche à droite) (8) - Remplacer le nœud à enlever par ce noeud
3
8
10
7
3
9
10
8
8
3
9
10
54Transformer une liste en un arbre
- Pour accélérer laccès (recherche)
- Insérer les nœud lun après lautre dans larbre
- Problème de larbre non balancé (dégénéré)
- Liste 1, 2, 3, 4, 5, 6
- Solution
- (essayez de le faire)
- Trier la liste
- Le milieu comme racine
- Profondeur O(log n)
1
2
3
4
5
6
55Résumé
- Structure de données
- Pour organiser les données
- Tableau (array), liste
- Liste
- Structure flexible
- Adaptée pour des mises à jour fréquentes
- Type abstrait de données - généralisation
- Correspond à un ensemble dopérations bien
définies - Implantation dun type de donnée
- Différentes façons LinkedList, array, etc.
- Iterator
- Dautres types de données pile, queue, arbre
56Exercices à réfléchir
- Réfléchir sur les opérations sur un arbre de
recherche binaire, dont chaque nœud contient un
int - Comment généraliser ces opérations pour quelles
fonctionnent avec des nœuds contenant des objets
Comparable - Insertion dans larbre
- Enlever un nœud contenant une élément
- Rechercher un élément
- Optimiser la structure essayer de balancer
- Utilisation de larbre de recherche binaire pour
faire du tri (complexité?) - Arbre n-aire
- Trie
- Arbre de Briandais
57Trie
- Pour stocker des mots de façon plus conpacte
- a, ab, abc, acb, aa, bac
- Une réalisation
- Chaque nœud contient un tableau de 26 cases
(caractères) - Chaque case se dirige vers un nœud enfant
a
b
a
b
c
a
a
c
b
58Arbre de Briandais
- Représenter un arbre n-aire quelconque en un
arbre binaire - Nœud
- Info
- Premier enfant
- sibling
a
a
a
b
c
a
b
c
c
b
e
f
c
b
e
f