Vous êtes sur la page 1sur 62

Structures de données

& algorithmique

Structures de données et
algorithmique
Types abstraits
Structures linéaires
Itérateurs

Alain Sandoz / SA 2022 1


Structures de données
& algorithmique

Notion de structure de données


• Les algorithmes emploient des données ou des ensembles de données
• en entrée (elles définissent alors une instance du problème à résoudre)
• pour représenter et conserver des résultats intermédiaires en cours d’exécution
• comme espace de recherche
• en sortie (pour représenter ou stocker des solutions)
• La performance d'un algorithme dépend de la manière dont ces données sont
organisées, et ceci à cause…
• du coût des accès (ressources système, méthodes d'accès)
• de la complexité de la recherche d’une donnée dans l’ensemble des données
• de la complexité des opérations d'insertion, de marquage ou d'extraction
• de la nécessité de répéter le traitement de cas partiellement résolus ou d’états
intermédiaires

Alain Sandoz / SA 2022 2


Structures de données
& algorithmique

Type de données et structure de données

• Un type de données est défini par


• un ensemble de valeurs (définition d'une classe par ses
attributs et les valeurs que les attributs peuvent prendre)
• un ensemble d'opérations (définition d'une classe par ses
méthodes)
• Une structure de données est définie par
• un ensemble d’objets d'un même type de données
• des conditions sur ces objets et des relations entre eux
Ces conditions / relations vont déterminer comment organiser les
données et d'y accéder (selon certaines règles)

Alain Sandoz / SA 2022 3


Structures de données
& algorithmique

Exemple: pile de l’interpréteur ou d’une MV python


__main__(): bar
• L’interpréteur python garde en mémoire la 1
len = 3
chaîne des méthodes actives dans une pile 2 i = 5
foo(i) PC = 13
3
• Quand une méthode est appelée, #. . . m = 6
4
l’interpréteur empile un bloc contenant
. . . donnée de
• les variables locales et les valeurs à retourner 10 def foo(j=0): foo
type bloc
• un compteur qui pointe sur l'appel en cours 11 k = j+1 len = 4
d'exécution 12 bar(k) PC = 4
#. . . j = 5
• Quand une méthode est terminée, le « stack 13
frame » correspondant est retiré de la pile et . . . k = 6
le contrôle est donné à la méthode qui se 24 def bar(m=0):
#. . . main structure de
retrouve en haut de la pile 25
. . . len = 3 type pile
• Permet de faire des appels récursifs 32 return PC = 0
i = 5

Alain Sandoz / SA 2022 4


Structures de données
& algorithmique

Exemple (suite)

• Le stack-frame est un type de données


• l’ensemble de valeurs est défini des groupes de mots de 32 bits
composés 1) d’un entier pour la longueur du bloc, d’une adresse de
retour et d’une représentation de chaque argument et de chaque
variable interne d’une méthode qui peut être appelée par un
programme
• les opérations sont déterminées par le langage de programmation,
l’interpréteur ou le compilateur et la machine virtuelle, et le run-time
• La pile du système est une structure de données définie par
• un ensemble de blocs (type = stack-frame)
• la condition que seul celui qui représente le dernier appel est accessible
• la relation temporelle liant des appels imbriqués successifs (LIFO)

Alain Sandoz / SA 2022 5


Structures de données
& algorithmique

Abstraction
• Lorsque l'on définit une structure de données, qu’on la programme, puis qu’on l’utilise, il est
important de connaître quel type d’opérations l'on veut exécuter sur cette structure, et à travers
ces opérations, celles que l'on veut éventuellement exécuter sur les objets que la structure de
données contient
• La manière dont les opérations sont programmées n'a pas d'intérêt pour l'utilisateur
• Un type abstrait de données (« Abstract Data Type ») est la description d'une structure de
données comprenant:
• le type (de données) des objets contenus
• les opérations possibles sur cet ensemble d’objets
• les exceptions associées à ces opérations

Alain Sandoz / SA 2022 6


Structures de données
& algorithmique

Définition d'un type abstrait de données


On peut employer un ensemble d'axiomes pour définir la sémantique d’un type
abstrait (pas de lien avec une implémentation). Exemple de la pile (LIFO, stack):
• Une pile est une structure de données qui a les opérations:
new(), push(v, S), top(S) et popOff(S)
• Les axiomes pour ces opérations sont:
• new() retourne une pile
• popOff(push(v, S)) = S
• top(push(v, S)) = v
où S est une pile et v est une valeur
• L’opération top(new()) n'est pas définie
• Le prédicat isEmpty(S) peut être défini par les axiomes suivants
• isEmpty(new()) = true
• isEmpty(push(v, S)) = false

Alain Sandoz / SA 2022 7


Structures de données
& algorithmique

Applications de la structure de données pile

• Applications directes
• historique des pages visitées dans un navigateur internet
• séquences “undo” dans un éditeur de texte
• chaîne d'appels des méthodes par l’interpréteur python
• gestion de l'ensemble des processus d'un système multi-tâches (pour respecter les niveaux
de priorités et contraintes temps-réel)
• Applications indirectes
• apparaît comme structure de données auxiliaire dans certains algorithmes
• composante d'autres structures de données

Alain Sandoz / SA 2022 8


Structures de données
& algorithmique

Implémentation du type abstrait « STACK » (pile)


• Une pile garde en mémoire des objets d’un même type
• Les insertions et suppressions se font dans l'ordre
« dernier arrivé, premier sorti » (« LIFO »: last in first out)
Principales opérations: Opérations auxiliaires:
insérer un objet sur la pile (empiler) retourner l'objet qui est au sommet
push(o) de la pile sans le retirer
retirer l'objet qui est au sommet de la top()
pile et le retourner (dépiler) retourner le nombre d'objets
pop() contenus dans la pile
size()
indiquer si la pile est vide ou non
isEmpty()

Alain Sandoz / SA 2022 9


Structures de données
& algorithmique

class Stack():
Implémentation def __init__(self):
pass
Une pile sera définie par une classe def size() -> int:
On commence par définir une pass
interface Stack pour le type def isEmpty() -> bool:
abstrait pile pass
def top() -> object:
On devra traiter le cas d'une pile pass
vide, c'est-à-dire définir une classe def push(o):
d'exceptions pass
EmptyStackException def pop() -> object:
pass

class EmptyStackException(Exception):
def __init__(self, message):
print(message)

Alain Sandoz / SA 2022 10


Structures de données
& algorithmique

Exceptions
Parfois, exécuter une opération peut résulter en un état du programme que
l’on considère comme exceptionnel.
Le programmeur va traiter ces cas en particulier en utilisant un mécanisme
appelé exception
Une exception est soulevée lors de l'évaluation par le programme d’une
condition qui doit conduire à un tel traitement particulier.
Par exemple: dans le type abstrait pile, les opérations pop() et top() ne
devraient pas être exécutées si la pile est vide: dans ce cas, ces opérations
donneront lieu au traitement de l’exception EmptyStackException()

Alain Sandoz / SA 2022 11


Structures de données
& algorithmique

Exceptions (suite)
En général les exceptions sont définies par le programmeur: c’est un mécanisme
commode pour gérer les états peu nombreux, mais requérant des traitements
spéciaux, dans lesquels un programme peut se trouver.
Une exception est soulevée dans le programme par l’instruction
raise EmptyStackException(. . .)
Une exception est traitée dans le programme dans un bloc
try:
...
except:
...
else:
...
finally:

Alain Sandoz / SA 2022 12


Structures de données
& algorithmique

Première implémentation d'une pile


Une manière simple d'implémenter le type abstrait de données pile est
d'utiliser un tableau

P …
0 1 2 t
Algorithm size()
• On insère (empile) des éléments de
gauche à droite return t + 1
• Une variable int t garde en mémoire Algorithm pop()
l'indice du sommet de la pile
if isEmpty():
raise EmptyStackException()
else:
t¬t-1
return P[t + 1]
Alain Sandoz / SA 2022 13
Structures de données
& algorithmique

Première implémentation d’une pile (suite)


Le tableau gardant en mémoire les éléments de la pile peut être plein


P
0 1 2 t

Algorithm push(o)
L'opération push(o) va soulever
if t == (len(P) - 1):
une exception raise FullStackException()
FullStackException else
t¬t+1
Ceci est dû seulement à P[t] ¬ o
l'implémentation dans un tableau

Alain Sandoz / SA 2022 14


Structures de données
& algorithmique

Complexité et limitations
Si N est la taille du tableau utilisé dans l'implémentation
• Complexité en espace: O(N)
• Complexité en temps des opérations: O(1)

Limitations
• La longueur maximale du tableau est définie à priori et ne peut être
changée
• Essayer d'empiler un nouvel élément dans un tableau plein soulève une
exception (ceci est lié à l'implémentation)

class FullStackException(Exception):
def __init__(self, message):
print(message)

Alain Sandoz / SA 2022 15


Structures de données
& algorithmique

Implémentation
class ArrayStack(Stack):

pile = []
t = -1

def __init__(self, capacity):


if capacity < 1:
print("Cannot create zero-capacity array stack")
return
self.pile = [None for i in range(capacity)]

def size(self):
return self.t + 1

def isEmpty(self):
return (self.t == -1)

def isFull(self):
return (self.size()==len(self.pile))

Alain Sandoz / SA 2022 16


Structures de données
& algorithmique

Implémentation de la pile (suite)


def top(self):
if self.isEmpty():
raise EmptyStackException("Pile vide, ne peut pas en lire le sommet")
temp=self.pile[self.t]
return temp

def push(self,o):
if self.isFull():
raise FullStackException("Pile pleine, ne peut pas empiler")
self.t+=1
self.pile[self.t]=o

def pop(self):
if self.isEmpty():
raise EmptyStackException("Pile vide, ne peut pas dépiler")
temp=self.pile[self.t]
self.pile[self.t]=None
self.t-=1
return temp

Alain Sandoz / SA 2022 17


Structures de données
& algorithmique

Illustration

• Lors de la construction
pile

t -1

• Quand la pile contient 4


éléments
pile

t 3

Alain Sandoz / SA 2022 18


Structures de données
& algorithmique

Exemple : correspondance de parenthèses

Chaque “(”, “{”, ou “[” doit faire la paire correspondant avec “)”, “}”, ou “]”
• correct: ( )(( )){([( )])}
• correct: ((( )(( )){([( )])}))
• incorrect: )(( )){([( )])}
• incorrect: ({[ ])}
• incorrect: (

Alain Sandoz / SA 2022 19


Structures de données
& algorithmique

Algorithme parenthèses
Algorithm ParenMatch(X,n):
Input: An array X of n tokens, each of which is either a grouping symbol, a
variable, an arithmetic operator, or a number
Output: true if and only if all the grouping symbols in X match
Let S be an empty stack

for i=0 to n-1 do


if X[i] is an opening grouping symbol then
S.push(X[i])
else if X[i] is a closing grouping symbol then
if S.isEmpty() then
return false {nothing to match with}
if S.pop() does not match the type of X[i] then
return false {wrong type}
if S.isEmpty() then
return true {every symbol matched}
else
return false {some symbols were never matched}

Alain Sandoz / SA 2022 20


Structures de données
& algorithmique

File d’attente, FIFO, queue


Une file d’attente est une structure de données qui garde en mémoire
des objets d’un même type
Les insertions et suppressions se font dans l'ordre « premier arrivé,
premier servi » (« FIFO »)
Principales opérations:
• ajouter un objet: insère un objet à la fin de la file
• enlever un objet: retire et retourne l'objet au début de la file
Opérations auxiliaires
• retourner (une référence sur) l'objet au début de la file sans le retirer
• retourner le nombre d'objets dans la file
• indiquer si la file est vide ou non
Exceptions
• si on exécute enlever un objet ou retourner l’objet en tête de file sur une file vide

Alain Sandoz / SA 2022 21


Structures de données
& algorithmique

Type abstrait de données «QUEUE»

• Une file d'attente est une structure de données qui a les opérations
new(), add(v, Q), front(Q) et remove(Q)
• Les axiomes pour ces opérations sont:
• new() retourne une file d'attente
• front(add(v, new())) = v
• remove(add(v, new())) = new()
• front(add(v, add(w, Q))) = front(add(w, Q))
• remove(add(v, add(w, Q))) = add(v, remove(add(w, Q)))
où Q est une file d'attente et v et w sont des valeurs
• L’opération remove(new()) n'est pas définie

Alain Sandoz / SA 2022 22


Structures de données
& algorithmique

class Queue():
Implémentation def __init__(self):
pass
Une file sera définie par une classe def size() -> int:
On commence par définir une pass
interface Queue pour le type def isEmpty() -> bool:
abstrait file pass
def front() -> object:
On devra traiter le cas d'une file pass
vide, c'est-à-dire définir une classe def enqueue(o):
d'exceptions pass
EmptyQueueException def dequeue() -> object:
pass

class EmptyQueueException(Exception):
def __init__(self, message):
print(message)

Alain Sandoz / SA 2022 23


Structures de données
& algorithmique

Exemples
!"#$%&'() *($&'+ ,'-+...
enqueue(5) – (5)
enqueue(3) – (5, 3)
dequeue() 5 (3)
enqueue(7) – (3, 7)
dequeue() 3 (7)
front() 7 (7)
dequeue() 7 ()
dequeue() “error” ()
isEmpty() true ()
enqueue(9) – (9)
enqueue(7) – (9, 7)
size() 2 (9, 7)
enqueue(3) – (9, 7, 3)
enqueue(5) – (9, 7, 3, 5)
dequeue() 9 (7, 3, 5)

Alain Sandoz / SA 2022 24


Structures de données
& algorithmique

Applications des files

Applications directes
• Listes/files d'attentes
• «Faire la queue» à la Poste avec son numéro de passage
• Accessibilité à des ressources partagées (imprimante, print queue)

Applications indirectes
• Apparaît comme structure de données auxiliaire dans certains algorithmes

Alain Sandoz / SA 2022 25


Structures de données
& algorithmique

Application: Round Robin Schedulers

On peut utiliser une file Q pour implémenter un échéancier à tourniquet en


exécutant les opérations suivantes:
1. e = Q.dequeue()
2. service element e
3. Q.enqueue(e)
The Queue

1. Dequeue the 2 . Service the 3. Enqueue the


next element next element serviced element

Shared
e Service e

Alain Sandoz / SA 2022 26


Structures de données
& algorithmique

Première implémentation d'une file


• On utilise un tableau de longueur N, d'une façon circulaire
• Deux variables gardent en mémoire la position avant (first) et la position
arrière (rear) de la file. Une variable mémorise le nombre courant d'objets
dans la file.
• f est l'indice de la position avant de la file
• r est l'indice de la position arrière de la file
• L'indice r indique l'emplacement du prochain élément à insérer dans le
tableau
Configuration sans chevauchement
Q
0 1 2 f r
Configuration avec chevauchement
Q
0 1 2 r f
Alain Sandoz / SA 2022 27
Structures de données
& algorithmique

Opérations sur une file


La taille de la file est donnée Algorithm size()
par la variable int
currentsize return currentsize

Algorithm isEmpty()
return (currentsize==0)

Q currentsize = 10
0 1 2 f r

Q currentsize = 10
0 1 2 r f

Alain Sandoz / SA 2022 28


Structures de données
& algorithmique

Opérations sur une file


Algorithm enqueue(o)
• L'opération
enqueue(o) soulève une if size() == N :
exception si le tableau est raise FullQueueException
plein else:
• Cette exception est liée à Q[r] ¬ o
l'implémentation r ¬ (r + 1) mod N
currentsize++

Q
0 1 2 f r
Q
0 1 2 r f
Alain Sandoz / SA 2022 29
Structures de données
& algorithmique

Opérations sur une file


Algorithm dequeue()
• L'opération
dequeue() soulève une if isEmpty():
exception si la file est vide raise EmptyQueueException()
else:
• Cette exception est
inhérente au type abstrait o ¬ Q[f]
de données File f ¬ (f + 1) mod N
currentsize--
return o

Q
0 1 2 f r
Q
0 1 2 r f
Alain Sandoz / SA 2022 30
Structures de données
& algorithmique

Complexité et limitations

Si N est la longueur du tableau utilisé dans l'implémentation


• Complexité en espace: O(N)
• Complexité en temps des opérations: O(1)
Limitations
• La longueur maximale de la file est définie à priori et ne peut être changée
• Essayer d'ajouter un nouvel élément dans une file pleine cause une exception (liée à
l'implémentation)

Alain Sandoz / SA 2022 31


Structures de données
& algorithmique

Listes chaînées
• Une liste simplement chaînée est une nextNode
structure de données constituée d'une
séquence de nœuds (node)
• Chaque nœud garde en mémoire une
référence à un objet et un lien vers un autre
element node
nœud (linked list).
Remarque: ce lien est une référence vers un
autre nœud.

A B C D

Alain Sandoz / SA 2022 32


Structures de données
& algorithmique

Classe Node

class Node: # Accessor methods

element=None def getElement(self):


nextNode=None return self.element

def __init__(self, element, nextNode): def getNext(self):


self.element=element return self.nextNode
self.nextNode=nextNode

# Modifier methods

def setElement(self, element):


self.element=element

def setNext(self, nextNode):


self.nextNode=nextNode

Alain Sandoz / SA 2022 33


Structures de données
& algorithmique

Insérer un élément en tête de liste

• Créer un nouvel élément Æ

• Faire pointer le champ « nextNode »


du nouveau nœud sur l'ancienne
tête de liste

• Affecter à la tête de liste la


référence au nouveau nœud

Alain Sandoz / SA 2022 34


Structures de données
& algorithmique

Enlever l'élément en tête de liste

• La tête devient le prochain


élément de la liste

Æ
• Détacher l'ancienne tête de la
liste

Alain Sandoz / SA 2022 35


Structures de données
& algorithmique

Insérer à la fin de la liste

• Créer un nouveau nœud


Æ

Zurich

• Faire pointer l'ancien dernier élément


sur notre nouveau nœud

• Affecter au pointeur de dernier


élément la référence sur le nouveau
nœud

Alain Sandoz / SA 2022 36


Structures de données
& algorithmique

Enlever un élément à la fin de la liste


• Dans une liste simplement chaînée, on ne peut pas enlever efficacement un élément à la fin de la
liste
• Cela vient du fait que pour accéder au nœud avant le nœud final, on doit passer à travers toute la
liste.

Alain Sandoz / SA 2022 37


Structures de données
& algorithmique

Implémenter une pile avec une liste chaînée


• On peut implémenter une pile avec une liste simplement chaînée
• L'objet au sommet de la pile est gardé en mémoire dans le premier nœud de la liste
• La complexité en espace est O(n), où n est le nombre d’éléments dans la pile
• Chaque opération peut s'exécuter en O(1)
nœuds

t Æ

éléments

Alain Sandoz / SA 2022 38


Structures de données
& algorithmique

Classe NodeStack
class NodeStack(Stack): def push(self, elem):
v = Node(elem, self.stackTop)
stackTop=None self.stackTop = v
stackSize=0 self.stackSize+=1

def __init__(self): def top(self):


self.stackTop=None if self.isEmpty():
self.stackSize=0 raise EmptyStackException("Stack is empty.")
temp = self.stackTop.getElement()
def size(self): return temp
return self.stackSize
def pop(self):
def isEmpty(self): if self.isEmpty():
return self.stackSize==0 raise EmptyStackException("Stack is empty.")
temp = self.stackTop.getElement()
self.stackTop = self.stackTop.getNext()
self.stackSize-=1
return temp

Alain Sandoz / SA 2022 39


Structures de données
& algorithmique

Implémenter une file avec une liste chaînée


• On peut implémenter une file avec une liste simplement chaînée
• l'élément au début de la file est gardé en mémoire dans le premier nœud de la liste
• l'élément à la fin de la file est le dernier nœud de la liste. Une référence spéciale est maintenue sur cet
élément.
• La complexité en espace est O(n), où n est le nombre d’éléments dans la la file
• Chaque opération peut s'exécuter en O(1) r
nœuds

f Æ

éléments
Alain Sandoz / SA 2022 40
Structures de données
& algorithmique

Problème:
insertion dans une liste / opération en fin de liste

L’endroit où insérer un élément dans une liste peut dépendre du new node

type de liste (pile, queue, etc.) ou de la valeur de cet élément


Mais l'usage de l'insertion ne devrait pas dépendre de la manière
dont la liste est implémentée (tableau, vecteur, liste chaînée, etc.)

Alain Sandoz / SA 2022 41


Structures de données
& algorithmique

Plus généralement
Comment implémenter des opérations sur les éléments d'une structure
de données de sorte que
• l'accès aux éléments de la structure de données soit possible par l'intermédiaire de cette
implémentation
• l'accès aux éléments de la structure de données à travers sa structure d'enchaînement (organisation)
ne soit pas nécessaire
• différents usages (accès par position, recherche, parcours) soient possibles sur les instances de la
structure de données
Buts:
• garantir la protection et la consistance des contenus
• pouvoir appliquer les algorithmes indépendamment de l'implémentation des structures de données
et éventuellement les (trans)porter d’un environnement à un autre
On regroupe les opérations sur les éléments de la structure dans une classe
séparée appelée itérateur
Alain Sandoz / SA 2022 42
Structures de données
& algorithmique

Application: cas d'une liste chaînée


Interface de l’itérateur pour une liste
class ListIterator:
# mémorise la position courante

def advanceCurrent(self):
def insertAfterCurrent(self, x): # raises ItemNotFoundException
def setCurrentToFirst(self):
def currentIsInList(self):
def retrieveCurrent(self):
def findAndSetCurrent(self, x):
def setCurrentToZeroth(self):
def removeAndSetCurrentToZeroth(self, x): # raises ItemNotFoundException
def removeNext(self):

current

list

Alain Sandoz / SA 2022 43


Structures de données
& algorithmique

Organisation (liste chaînée)


class List(): class LinkedList(List):

def __init__(self): linkedListHeader = None


pass # is a Node

def isEmpty(self): def __init__(self):


pass self.linkedListHeader = Node(None, None)

def makeEmpty(self): def isEmpty(self):


pass return self.linkedListHeader.getNext() is None

def makeEmpty(self):
self.linkedListHeader.setNext(None)

Alain Sandoz / SA 2022 44


Structures de données
& algorithmique

Itérateur pour une liste chaînée simple

class LinkedListIterator(ListIterator):
# mémorise la position courante

linkedList = None
currentPos = None

def __init__(self, myList):


self.linkedList = myList
if self.linkedList.isEmpty():
self.currentPos = self.linkedList.linkedListHeader
else:
self.currentPos = self.linkedList.linkedListHeader.getNext()

Alain Sandoz / SA 2022 45


Structures de données
& algorithmique

Construction

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

éléments de la liste myList


LinkedList myList

linkedList

LinkedListIterator itr = new LinkedListIterator( myList );


itr = LinkedListIterator(myList)

currentPos

LinkedListIterator itr

Alain Sandoz / SA 2022 46


Structures de données
& algorithmique

Insertion

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

LinkedList myList

éléments de la liste myList

linkedList

itr.insertAfterCurrent(x)
itr.insertAfterCurrent( x );

currentPos

LinkedListIterator itr

Alain Sandoz / SA 2022 47


Structures de données
& algorithmique

Parcours

None
null p-l-1 x p-l-2 p-l-3 p-l-4

linkedListHeader None
null

LinkedList myList éléments de la liste myList

linkedList

itr.advanceCurrent()
itr.advanceCurrent();

currentPos

LinkedListIterator itr

Alain Sandoz / SA 2022 48


Structures de
Structures de données
données
&&algorithmique
algorithmique

Extraction
Extraction
ListNode itr
ListNode itr interne à la méthode
interne à la méthode
while ...
while ...

None
null p-l-1 x p-l-2 p-l-3 p-l-4

linkedListHeader None
null p-l-1 x p-l-2 p-l-3 null p-l-4
None
linkedListHeader None
null
LinkedList myList éléments de la liste myList
else ...
LinkedList myList éléments de la liste myList
else ...

linkedList

linkedList itr.removeAndSetCurrentToZeroth(x) x );
itr.removeAndSetCurrentToZeroth(

currentPos
itr.removeAndSetCurrentToZeroth(x) x );
itr.removeAndSetCurrentToZeroth(

LinkedListIterator
currentPos itr

LinkedListIterator itr
Alain Sandoz / SA 2021 51

Alain Sandoz / SA 2022 49


Structures de données
& algorithmique

Applications

Déterminer la longueur d'une liste chaînée

def listSize(theList):
size = 0
itr = LinkedListIterator(theList)
itr.setCurrentToFirst()
while itr.currentIsInList():
itr.advanceCurrent()
size+=1
return size

Alain Sandoz / SA 2022 50


Structures de données
& algorithmique

Copie d'une liste chaînée


def copy(lhs, rhs)
if (lhs is rhs):
return # test de l'alias

lhs.makeEmpty()
lhItr = LinkedListIterator( lhs )
rhItr = LinkedListIterator( rhs )
while rhItr.currentIsInList():
lhItr.insertAfterCurrent(rhItr.retrieveCurrent())
rhItr.advanceCurrent()

… next slide please …

Alain Sandoz / SA 2022 51


Structures de données
& algorithmique

Déroulement de la copie

None
null pl-5
p-l-1 pl-6
p-l-2 pl-7
p-l-3

linkedListHeader None

éléments de la liste lhs


LinkedList lhs

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

éléments de la liste rhs


LinkedList rhs

lhs.makeEmpty()
lhs.makeEmpty();

lhItr = LinkedListIterator(lhs)
LinkedListIterator lhItr = new LinkedListIterator( lhs);

LinkedListIterator
rhItr rhItr = new LinkedListIterator( rhs);
= LinkedListIterator(rhs)

Alain Sandoz / SA 2022 52


Structures de données
& algorithmique

None
null pl-5
p-l-1 pl-6
p-l-2 pl-7
p-l
-3

linkedListHeader null None


null

éléments de la liste lhs


LinkedList lhs

LinkedListIterator rhItr

linkedList linkedList

currentPos currentPos

LinkedListIterator lhItr

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

éléments de la liste rhs


LinkedList rhs

Alain Sandoz / SA 2022 53


Structures de données
& algorithmique

None
null

linkedListHeader None
null

LinkedList lhs

LinkedListIterator rhItr

linkedList linkedList

currentPos currentPos

LinkedListIterator lhItr
rhItr.currentIsInList(
rhItr.currentIsInList() )
==== true
True

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

éléments de la liste rhs


LinkedList rhs

Alain Sandoz / SA 2022 54


Structures de données
& algorithmique

lhItr.insertAfterCurrent(rhItr.retrieveCurrent())
lhItr.insertAfterCurrent(
None
null rhItr.retrieveCurrent( ) );
linkedListHeader None
null
rhItr.advanceCurrent()
rhItr.advanceCurrent( );
LinkedList lhs

LinkedListIterator rhItr

linkedList linkedList

currentPos currentPos

LinkedListIterator lhItr

None
null p-l-1 p-l-2 p-l-3 p-l-4

linkedListHeader None
null

éléments de la liste rhs


LinkedList rhs

Alain Sandoz / SA 2022 55


Structures de données
& algorithmique

Itérateur pour une liste


class ListIterator:
# mémorise la position courante

def advanceCurrent(self):
def insertAfterCurrent(self, x): # raises ItemNotFoundException
def setCurrentToFirst(self):
def currentIsInList(self):
def retrieveCurrent(self):
def findAndSetCurrent(self, x):
def setCurrentToZeroth(self):
def removeAndSetCurrentToZeroth(self, x): # raises ItemNotFoundException
def removeNext(self):

class ItemNotFoundException(Exception):
def __init__(self, message):
print(message)

Alain Sandoz / SA 2022 56


Structures de données
& algorithmique

Itérateur pour une liste: implémentation


def advanceCurrent(self):
if (self.currentPos is not None):
self.currentPos = self.currentPos.getNext()

def insertAfterCurrent(self, x):


# raises ItemNotFoundException
if (self.currentPos is None):
raise ItemNotFoundException( "Insertion error" )
else:
newNode = Node( x, self.currentPos.getNext() )
self.currentPos.nextNode = newNode
self.currentPos = self.currentPos.getNext()

def setCurrentToFirst(self):
self.currentPos = self.linkedList.linkedListHeader.getNext()

Alain Sandoz / SA 2022 57


Structures de données
& algorithmique

Itérateur pour une liste: implémentation


def currentIsInList(self):
return (self.currentPos is not None) and (self.currentPos is not self.linkedList.linkedListHeader)

def retrieveCurrent(self):
if self.currentIsInList():
return self.currentPos.getElement()
else:
return None

def findAndSetCurrent(self, x):


itr = self.linkedList.linkedListHeader.getNext()
while (itr is not None) and not (itr.getElement() is x):
itr = itr.getNext()
if ( itr is None ):
return False
else:
self.currentPos = itr
return True

Alain Sandoz / SA 2022 58


Structures de données
& algorithmique

Itérateur pour une liste: implémentation


def setCurrentToZeroth(self):
self.currentPos = self.linkedList.linkedListHeader

def removeAndSetCurrentToZeroth(self, x):


# raises ItemNotFoundException
itr = self.linkedList.linkedListHeader
while (itr.getNext() is not None) and not (itr.getNext().getElement() is x):
itr = itr.getNext()
if ( itr.getNext() is None ):
raise ItemNotFoundException( "removeAndSetCurrentToZeroth fails")
else:
itr.nextNode = itr.getNext().getNext()
self.currentPos = self.linkedList.linkedListHeader

def removeNext(self):
if (self.currentPos is None):
return False
if (self.currentPos.getNext() is None):
return False
self.currentPos.nextNode = self.currentPos.getNext().getNext()
return True

Alain Sandoz / SA 2022 59


Structures de données
& algorithmique

Relation d'ordre entre les valeurs d'une


structure de données
class Comparable:

def compares ( self, rhs ) -> int:


pass

def lessThan ( self, rhs ) -> bool:


pass

class MyClass(Comparable):

def __init__(self):
pass

a = MyClass()
b = MyClass()
compare = a.compares(b)
less = a.lessThan(b)

Alain Sandoz / SA 2022 60


Structures de données
& algorithmique

Application: liste chaînée triée


Le type des contenus est une classe qui implémente

class SortListIterator(LinkedListIterator):

def insertAfterCurrent(x):
if (self.currentIsInList()):
if (self.currentPos.getElement().lessThan(x)) and
((self.currentPos.getNext() is None) or
(x.lessThan(self.currentPos.getNext().getElement()))):
newNode = Node( x, self.currentPos.getNext() )
self.currentPos.nextNode = newNode
self.currentPos = self.currentPos.getNext()
else:
l'interface Comparable

raise ItemNotFoundException( "Try to insert in wrong place" )


else:
if ( self.currentPos is self.linkedList.linkedListHeader ):
newNode = Node( x, None)
self.currentPos.nextNode = newNode
self.currentPos = self.currentPos.getNext()
else:
raise ItemNotFoundException( "Insertion error" )

Alain Sandoz / SA 2022 61


Structures de données
& algorithmique
Le type des contenus est une classe qui implémente

def insert( Comparable x ):


prev = LinkedListIterator( self.linkedList )
curr = LinkedListIterator( self.linkedList )
prev.setCurrentToZeroth( )
curr.setCurrentToFirst( )
while curr.currentIsInList( ) and
curr.retrieveCurrent( ).lessThan( x ):
curr.advanceCurrent( )
prev.advanceCurrent( )
l'interface Comparable

prev.insertAfterCurrent( x )
self.currentPos = prev.currentPos

Alain Sandoz / SA 2022 62

Vous aimerez peut-être aussi