Remarque préliminaire : Jupyter est parfois capricieux pour le téléchargement des images. Si les images n'apparaissent pas dans le notebook, chargez les dans le même dossier que le notebook. Les adresses se trouvent en double cliquant dans les cellules de texte (là où il y a précisé "image", c'est qu'il y a une image normalement...). Puis changez le code comme ceci : ![Image : listes](http://www.maths-info-lycee.fr/images/arbre1.jpg)
devient ![Image : listes](imagearbre1.jpg)
ou même ![](imagearbre1.jpg)
Les structures de données linéaires sont des suites d'éléments $e_1 , e_2 , \dots , e_n$. Dans une structure linéaire, on traite les données séquentiellement, c'est-à-dire les unes après les autres. De plus on doit pouvoir ajouter et supprimer des éléments.
On va s'intéresser à trois types de structures linéaires : les listes, les piles et les files.
Compléter ce cours/TD au fur et à mesure que vous le faites. Pour écrire dans une cellule, double-cliquez dedans. Une fois le TD fait, imprimez-le : pour réviser, la mémorisation se fait mieux avec un cours papier que sur écran.
Une première remarque fondamentale : on ne parle pas du type list
vu en Python en première. Le type list
de Python est en fait un tableau dynamique.
Une liste en informatique est une suite d'éléments. Cette suite est finie, et peut être vide. Chaque élément de la suite est repérée par son indice : la liste est ordonnée par l'indice (et non par la valeur de l'élément).
Deuxième remarque : une liste informatique n'est pas non plus ce qu'on appelle une liste dans le langage courant. Quand on a une liste de courses, on ne suit pas l'ordre de la liste pour faire ses courses. Et on ne met pas deux fois le même ingrédient (sauf étourderie). Dans un style plus littéraire, vous pouvez lire les notes de chevet (枕草子, Makura no sōshi) de Sei Shōnagon, écrites vers 990. Ce sont des listes poétiques : "Choses dont on néglige souvent la fin", "Choses que l'on méprise", "Choses qui font battre le cœur", "Fleurs des arbres", "Cascades"...
Exemple à compléter :
On donne la liste L1
des jours de la semaine :
L1 = [lundi , mardi, mercredi , jeudi , vendredi , samedi , dimanche]
L1
a pour tête ... à compléter ... et est suivie de la liste L2 =
... à compléter...
L2
a pour tête ... à compléter ... et est suivie de la liste L3 =
... à compléter ...
Donner la dernière étape de cette décomposition:
Appeler éventuellement le professeur pour vérification
Une défintion simple du type Liste
utilise les primitives suivantes (ce sont entre autre les méthodes de la classe, mais pas forcément) :
creerListe()
estVide(liste)
cons(élément, liste)
. C'est en fait le constructeur "historique" du type liste
.donnee(liste)
. Renvoie la "tête" de listesuivant(liste)
. Renvoie la "queue" de la liste.Une liste L
peut s'écrire L = cons(donnee(L) , suivant(L))
. On remarque que cette définition est récursive ; suivant(L)
pouvant être une liste.
On utilisera uniquement les fonctions primitives définies ci-dessus
En terminale NSI, on travaillera essentiellement sur les listes chaînées. Les listes chainées sont composées de maillons, et sont définies récursivement. Un maillon est composé d'un élément de tête, et... d'un autre maillon, qui contient les éléments suivants, éléments de queue. En fin de liste le maillon suivant est None
. Les maillons sont aussi appelés cellules, notamment en anglais (cell
).
On utilisera les conventions suivantes (qui ne sont pas universelles, d'autres versions peuvent exister) :
None
et de queue None
;None
, et de queue None
;None
et de queue différente de None
.Une implémentation est donnée ci-dessous, basée sur ces cellules (tête , queue). L'unique attribut de cette classe est :
cellule
: la liste proprement diteLes attributs de la classe Cell
sont :
tete
: l'élément de tête de la liste (éventuellement None
)queue
: la liste composant la deuxième partie de Cell
(éventuellement None
)Compléter le code en rajoutant les primitives longueurListe
qui, comme son nom l'indique, renvoie la longueur de la liste ; et listeElements
, qui, comme son nom l'indique moins clairement, renvoie un tableau dynamique Python (type list
) comportant les éléments de la liste, dans l'ordre où la tête de la liste a pour indice 0 dans le tableau dynamique.
class Cellule :
def __init__(self, tete = None, queue = None) :
# Admirez le joli booléen dans l'assertion
assert (queue is None) or (tete is not None), 'construction impossible'
# On peut aussi rajouter une assertion pour vérifier que queue
# est soit un maillon, soit None
self.tete = tete
self.queue = queue
def est_vide(self):
return self.tete is None # and self.queue is None est inutile vu le constructeur
def donnee(self):
# Méthode classique, mais qui n'apporte rien de plus que self.tete !
assert not(self.est_vide()) , 'Listevide'
return self.tete
def suivant(self):
# Méthode classique, mais qui n'apporte rien de plus que self.queue !
assert not(self.est_vide()) , 'Listevide'
return self.queue
def longueur_liste_rec(self):
# Algortihme à coder :
# si la liste est vide on renvoie 0, sinon on renvoie 1 + la longueur de la queue
return
def longueur_liste_iter(self):
# Algorithme :
# Après initialisation de la longueur à 0, tant qu'il reste des élements dans self, on
# ajoute 1 et on remplace self par sa queue
long = 0
return long
def liste_elements_rec(self) :
# On reprend l'algorithme récursif du calcul de la longueur :
# en cas de liste vide on renvoie [], sinon on renvoie la liste composée de la
# tête à laquelle on ajoute la liste des éléments de la queue
# Remarque : les listes s'aditionnent [1] + [2, 3] = [1, 2, 3]
# Remarque : on peut aussi programmer avec la méthode append
return
def liste_elements_iter(self) :
# Algorithme : on se base sur le calcul de la longueur en récursif
return
def appartient_iter(self, element):
return
def appartient_rec(self, element) :
return
def suppression_elt_iter(self, element) :
if not self.appartient_iter(element) :
# On écrit une fonction préliminaire qui teste si l'élément est dans la liste
return False
else :
# Il faut garder en mémoire le liens de la cellule précédente à la cellule courante
# pour pouvoir "couper et recoller" ce lien vers la cellule suivante
# On passe de :
# précédente -> courante -> suivante
# à :
# précédente -> suivante
return True
def suppression_elt_rec(self, element) :
# On écrit une fonction préliminaire qui teste si l'élément est dans la liste
if not self.appartient_rec(self, element) :
return False
else :
self.suppression_elt_rec_2(self, element)
return True
def suppression_elt_rec_2(self, element) :
# partie récursive proprement dite
# Reprendre la méthode itérative
return None
def __repr__(self):
if self.tete is None :
return '()'
else:
# la 1ère possibilité met l'aspect récursif en avant
# la 2ème possibilité mes l'aspect chaiîné en avant
return '(' + str(self.donnee()) + repr(self.suivant()).replace('None','()') + ')'
# return str(self.donnee) + '->' + repr(self.suivant)
def cons(tete, queue) :
# Ici la primitive n'est pas une méthode mais une fonction. Dont on
# peut constater la totale inutilité, puisqu'elle tient sur une ligne...
return Cellule(tete, queue)
nil = Cellule(None, None) # notation "nil" historique
print("liste nil : ",print(nil)," de longueur : ",nil.longueur_liste_iter(),". Test pour vide :",nil.est_vide())
print("la liste nil a pour tête ", nil.tete , " et pour queue ",nil.queue)
liste = Cellule(4,nil)
for i in range(3,-1,-1):
liste = Cellule(i,liste)
print("liste :" , liste," de tête ",liste.donnee()," et de queue ",liste.suivant())
# Donner l'instruction pour trouver 2, l'écrire à la place de None
print("Pour trouver 2, on a utilisé l'instruction ... " , None)
print("la longueur de la liste est : ",liste.longueur_liste_rec())
"""
print("Conversion en tableau dynamique (itératif) :", liste.liste_elements_iter())
print("Conversion en tableau dynamique :(récursif)", liste.liste_elements_iter())
print ("3 est dans ",liste," : ",liste.appartient_iter(3), liste.appartient_rec(3))
print ("7 est dans ",liste," : ",liste.appartient_iter(7), liste.appartient_rec(7))
"""
"""
# Suppression d'un élément : penser à tester les cas "limite"
liste.supprimer_elt_rec(3)
liste.supprimer_elt_rec(4)
liste.supprimer_elt_rec(0)
print(liste)
liste = Cellule(4,nil)
for i in range(3,-1,-1):
liste = Cellule(i,liste)
liste.supprimer_elt_iter(3)
liste.supprimer_elt_iter(4)
liste.supprimer_elt_iter(0)
print(liste)
"""
"""
# Egalité de listes
liste = Cellule(4,nil)
for i in range(3,-1,-1):
liste = Cellule(i,liste)
print(listeb , "est égale à ",liste," : ", liste.est_egale(listeb))
listeb = cons(4,listeb)
print(listeb , "est égale à ",liste," : ", liste.est_egale(listeb))
"""
print()
est_vide()
, longueur()
,liste_elements()
, aussi bien pour les méthodes récursives qu'itératives.appartient(element)
qui renvoie None
si l'élément n'appartient pas à la liste, et son indice sinon. Complément pour ceux qui vont vite : en déduire une méthode suppr_element(element)
qui supprime la première occurence d'un élément donné dans une liste.Questions complémentaires éventuelles
est_egale(liste2)
qui teste si la liste2 est égale à la liste appelant la méthode.derniere(liste)
qui renvoie la dernière cellule de la liste. En déduire une méthode concatener(liste2)
qui concatène la liste2 en fin de la liste appelant la méthode.On peut créer d'autres versions des listes:
Rappel sur une remarque importante : le type abstrait Liste
n'est pas le type list
de Python. Les listes de Python sont basées sur des tableaux, et mélangent des accès de type fonctions (del(ma_liste[3]
), des accès de type objet (ma_liste.append('truc')
), et des accès plus étranges (machin in ma_liste
, ma_liste[3:6]
)
Quand on passe de l'itératif au récursif pour l'implémentation des méthodes longueur_liste()
et liste_elements()
, cela change-t-il l'usage de la classe ?
Réponse :
Comme vous venez de le voir juste ci-dessus, la manière dont est programmée la classe n'influe pas sur son usage. Plus précisément, l'implémentation de la classe ne joue pas sur sa signature. Le type de données Liste
peut être définit de manière abstraite. Par exemple, pour utiliser des flottants en Python, vous n'av(i)ez pas besoin de connaître la représentation sous la forme mantisse-exposant, forme que l'on a vue dans le cours sur le codage.
On définit un type abstrait par sa signature : nom des opérations, type des arguments, type du retour des opérations.
Autant l'implémentation d'un type abstrait ne joue pas sur sa signature, par définition même, autant elle peut jouer sur la complexité des opérations du type.
Le type Liste
n'est pas fixé dans le marbre. On peut proposer des primitives plus nombreuses et plus riches.
On propose ici les fonctions primitives sur les listes suivantes :
creerListe(e = Aucun , liste = Aucun)
est_vide(liste)
longueur(liste)
lire(liste , k)
supprimer(liste , k)
. Cette méthode renvoie une nouvelle liste.inserer(liste , k)
. Cette méthode renvoie une nouvelle liste.get_maillon(liste , k)
Cette méthode est donnée ci-dessous en itératif. C'est un bon exercice que de la programmer également en récursif, et de voir que le fonctionnement des primitives n'en change pas pour autantExercice : programmer les méthodes lire
et insérer
, dans l'implémentation suivante du type liste
.
Et pour ceux qui vont vite : programmer supprimer
,
class Cellule :
def __init__(self, tete = None, queue = None) :
# Admirez le joli booléen dans l'assertion
assert (queue is None) or (tete is not None), 'construction impossible'
# On peut aussi rajouter une assertion pour vérifier que queue
# est soit un maillon, soit None
self.tete = tete
self.queue = queue
def estVide(self):
return self.tete is None # and self.queue is None est inutile vu le constructeur
def donnee(self):
assert not(self.estVide()) , 'Listevide'
return self.tete
def suivant(self):
assert not(self.estVide()) , 'Listevide'
return self.queue
def longueur_liste(self):
long = 0
while not self.estVide():
long = long + 1
self = self.suivant()
return long
def get_maillon(self, i):
# Version itérative
if i >= self.longueur_liste() :
raise IndexError('Index trop grand')
else :
while i > 0:
i = i - 1
self = self.suivant()
return self
def get_maillon_rec(self, i):
return
def lire(self , i) :
return
def inserer(self , i, element) :
return
def supprimer(self , i) :
return
def __repr__(self):
if self.tete is None :
return '()'
else:
# la 1ère possibilité met l'aspect récursif en avant
# la 2ème possibilité mes l'aspect chaiîné en avant
return '(' + str(self.donnee()) + repr(self.suivant()).replace('None','()') + ')'
# return str(self.donnee) + '->' + repr(self.suivant)
maliste = Cellule()
print(maliste, maliste.estVide(), maliste.longueur_liste())
for i in range(5 , -1 , -1) :
maliste = Cellule("film"+str(i),maliste)
print("affichage : ",maliste, "de longueur ",maliste.longueur_liste())
# TESTS nombreux et multiples ! Il en manque d'importants d'ailleurs, à compléter...
print("lecture des éléments d'indices 1 et 5 :",maliste.lire(1),maliste.lire(5))
print()
print("Insertion et suppression en itératif")
i = 5
print("get maillon d'indice ",i,)
print(maliste.get_maillon(i))
maliste = maliste.inserer(i , "film3b")
print("affichage insertion : ",maliste, "de longueur ",maliste.longueur_liste())
maliste = maliste.supprimer(i)
print("affichage suppression : ",maliste, "de longueur ",maliste.longueur_liste())
maliste = maliste.supprimer(0)
print("affichage suppression indice 0: ",maliste, "de longueur ",maliste.longueur_liste())
maliste = maliste.supprimer(maliste.longueurListe() - 1)
print("affichage suppression dernier indice : ",maliste, "de longueur ",maliste.longueur_liste())
liste_quasi_vide = Cellule("rien", Cellule())
print(liste_quasi_vide, "longueur : ", liste_quasi_vide.longueur_liste())
liste_quasi_vide = liste_quasi_vide.supprimer(0)
print("affichage suppression indice 0: ",liste_quasi_vide, "de longueur ",liste_quasi_vide.longueur_liste())
On donne ci-dessous une implémentation à base de tableaux dynamiques (le fameux type list
de Python). La tête de la liste sera l'élément d'indice 0, la queue toute la suite.
Comme vous pouvez le constater ci-dessous, on ne construit pas de classe : les primitives sont traduites en fonctions.
def liste_vide() :
return []
def est_vide(liste) :
return liste == liste_vide()
def cons(element, liste) :
liste.insert(element, 0)
return liste
def tete(liste) :
assert not(est_vide(liste)), 'liste vide'
return liste[0]
def queue(liste):
assert not(est_vide(liste)), 'liste vide'
return liste[1:]
def supprimer(liste, i) :
liste.pop(i)
#return liste : pas indispensable car il ya effet de bord : la liste est modifiée par la fonction
def inserer(liste , i, element) :
liste.insert(element, i)
#return liste : idem ci dessus
ma_liste_2 = [0]
print(ma_liste_2, "est vide : ", est_vide(ma_liste_2))
print("tete : ",tete(ma_liste_2), "queue : ", queue(ma_liste_2))
ma_liste_2 = [0, 1, 2, 3, 4, 5]
print(ma_liste_2, "est vide : ", est_vide(ma_liste_2))
print("tete : ",tete(ma_liste_2), "queue : ", queue(ma_liste_2))
inserer(ma_liste_2, 33, 4)
supprimer(ma_liste_2, 5)
print(ma_liste_2)
Une pile est une structure linéaire où les insertions et les suppressions se font toutes du même côté, à l'image d'une pile d'assiettes : on rajoute les nouvelles assiettes au sommet de la plie, on prend des assiettes sur le sommet de la pile également. Les piles sont appelées stack ou LIFO en anglais (last in, first out).
Une interface (un peu plus détaillée que la signature) d'une pile peut être :
Fonction (créerPile)/méthode(les autres) | Description |
---|---|
creer_pile() $\rightarrow$ Pile | Créer une pile vide |
est_pile_vide(p) $\rightarrow$ Booléen | Teste si la pile p est vide |
empliler(p , élément) | Insère élément en tête de p |
depiler(p) $\rightarrow$ élément | Enlève l'élément au sommet de la pile p et le renvoie |
sommet(p) $\rightarrow$ élément | Renvoie l'élément au sommet de la pile p |
Pile
, le tester. Si vous avez implémenté ce type d'une manière différente de votre voisin, vous pouvez tester et comparer l'efficacité de vos implémentations avec %timeit (mon_test(...))
from random import randint
class Pile :
def __init__(self) :
self.pile = []
def est_pile_vide(self):
return
def empiler(self , element):
return
def depiler(self):
if self.est_pile_vide():
raise IndexError("la pile est déjà vide")
else :
pass
def __repr__(self):
if self.est_pile_vide() :
return 'Pile vide'
else:
return str(self.pile)
def creer_pile():
# Comme pour les listes, le codage de cette primitive sous forme de fonction esr assez inutile
return Pile()
# un test parmi d'autres
a = Pile() # ou a = creerPile() si on veut vraiment se servir de la primitive
print("on empile")
for i in range(6):
a.empiler(randint(1, 20))
print(a)
print("on dépile")
while not a.est_pile_vide():
a.depiler()
print(a)
il est légitime de se demander à quoi sert une pile en informatique. On en trouve dans la gestion des modifications de documents dans les traitements de texte. Dans LibreOffice, ctrl-z permet d'annuler la dernière modification du texte, en "dépilant". On peut itérer cette opération. De même dans les navigateurs, le bouton "page précédente" cache une pile conservant les adresses visitées.
Plus généralement, on a précédemment mentionné les "piles d'appel", notamment en programmation récursive. C'est bien une structure du type abstrait pile
qui est utilisée.
3 . Ecrire une deuxième implémentation de la structure Pile
. On utilise la classe précédente Cellule
pour cela : on peut réaliser Pile
très économiquement à partir de cette dernière. C'est le code proposé ci-dessous, il ne reste que depiler
à coder.
class Cellule :
# On reprend la définition de la cellule d'une liste chaînée, en l'adaptant au contexte
def __init__(self, haut, suite) :
self.haut = haut
self.suite = suite
def __repr__(self):
if self.haut is None :
return 'cellule vide'
elif self.suite is None :
return str(self.haut)
else :
return str(self.haut) + "-" + str(self.suite)
class Pile :
def __init__(self) :
self.pile = None
def est_pile_vide(self):
return self.pile is None
def empiler(self , element):
self.pile = Cellule(element , self.pile)
def depiler(self):
def __repr__(self):
if self.estPileVide() :
return 'Pile vide'
elif self.pile.suite is None:
return repr(self.pile.haut)
else :
return repr(self.pile.haut) + '-' + repr(self.pile.suite)
def creer_pile():
return Pile()
ma_poule = creerPile()
print(ma_poule)
ma_poule.empiler(1)
print(ma_poule)
ma_poule.empiler(2)
print(ma_poule)
ma_poule.depiler()
print(ma_poule)
ma_poule.empiler(3)
print(ma_poule)
ma_poule.empiler(4)
print(ma_poule)
ma_poule.empiler(5)
print(ma_poule)
ma_poule.depiler()
print(ma_poule)
ma_poule.depiler()
print(ma_poule)
La notation polonaise inverse (notation postfixe) est une manière de noter les calculs sans utiliser de parenthèses. Cette notation a été utilisée par certaines calculatrices, notamment de Hewlett-Packard.
Exemple : calcul de 7 8 * 2 +
Pour cet exercice, on n'utilisera que des nombre positifs et pas de division (pour éviter la division par 0) . L'évaluation d'une expression est simple et utilise une pile :
Rappel : la méthode split
permet d'obtenir une liste comportant les différents "mots" d'une chaîne de caractères. Utilisée sans arguments, le séparateur est l'espace : 'un deux trois'.split()
renvoie ['un', 'deux', 'trois']
.
def calcul_postfixe(calcul) :
pile = Pile()
for char in calcul.split() :
#... à compléter (et enlever le pass)
pass
return
print(calculPostFixe("1 2 3 4 + * 5 * - 7 +"))
Une file est une structure linéaire où les insertions et les suppressions se font à l'opposé l'une de l'autre, à l'image d'une file d'attente : le premier arrivé est le premier servi. Les piles sont appelées FIFO ou queue en anglais (first in, first out).
Une interface possible d'une file est :
Fonction | Description |
---|---|
creerFile() $\rightarrow$ Pile | Créer une file vide |
estFileVide(f) $\rightarrow$ Booléen | Teste si la file f est vide |
enfiler(f , élément) | Insère élément en queue de f |
defiler(f) $\rightarrow$ élément | Enlève l'élément aen tête de la file f et le renvoie |
tete(f) $\rightarrow$ élément | Renvoie l'élément en tête de la file f |
File
, le tester. Si vous avez implémenté ce type d'une manière différente de votre voisin, vous pouvez tester et comparer l'efficacité de vos implémentations avec %timeit (mon_test(...))
from random import randint
class File :
# Implémentation avec un inconvénient majeur : defiler(self) est lent, car autant liste.pop()
#est en temps constant, autant liste.pop(0) est en temps linéaire
def __init__(self) :
def est_file_vide(self):
return
def enfiler(self , element):
def defiler(self):
if self.est_file_vide():
raise IndexError("la pile est déjà vide")
else :
pass
def __repr__(self):
if self.est_file_vide() :
return 'File vide'
else:
return
def creer_file():
return File()
# un test parmi d'autres
a = creer_file()
print("on enfile")
for i in range(6):
a.enfiler(randint(1, 20))
print(a)
print("on défile")
while not a.est_file_vide():
a.defiler()
print(a)
3 . Ecrire un programme qui permet de retourner une pile, en utilisant uniquement une file (type bac).
On utilisera uniquement les primitives associées aux pile et files (interdiction d'utiliser pop
, append
, len
etc.)
def retourner_pile(mapile):
return mapile
a = creerPile()
for i in range(6):
a.empiler(i)
print(a)
print(retournerPile(a))
On constate avec cette implémentation, très différente a priori de ce que vous avez fait précédemment, que le type abstrait File
peut être traduit en code de manières très différentes les unes de autres.
deque
¶Le type deque
(double ended queue, se lit deck) permet l'implémentation directe d'une file, où les primitives enfiler
et defiler
sont en complexité temporelle constante $O(1)$. On donne ci-dessous une exemple de code permettant la création d'une file. Ce type fait partie de la bibliothèque collections
.
Exercice : reprendre la fonction qui permet d'inverser une pile avec une file, et la réécrire en utilisant deque
(et éventuellement une pile formée tout simplement à partir d'un tableau dynamique Python, type list
).
from collections import deque
file = deque()
for i in range(6):
file.append(randint(1, 20))
print(file)
for i in range(6):
file.popleft()
print(file)
# Retourner une pile
def retourner_pile(pile):
file=deque()
return pile
poil = []
for i in range(6):
poil.append(i)
print(poil)
print(retournerPile(poil))
Dans ces exercices, la structure de données à utiliser parmi liste, pile et file n'est pas précisée : c'est à vous de la déterminer.
(
, fermantes )
, et de même pour les crochets [
et ]
. Ecrire une fonction qui vérifie le bon parenthésage de l'expression. ([()])
est bien parenthésée, ([()]
et ([(]))
ne le sont pas (il manque une )
dans le premier cas, et dans le deuxième )
et ]
sont inversés)Variante : 42 soldats juifs, deux survivants, et les romains en tuent un sur trois.
Implémenter une structure de file à l'aide de deux piles. Pour cela, une des piles est l'entrée, l'autre la sortie. Les deux sont liées. Lorsque l'on ajoute un élément, on l'empile sur l'entrée. Lorsque l'on retire un élément, si la pile de sortie n'est pas vide alors on la dépile (forcément le premier élément). Si la pile de sortie est vide, alors on retourne la pile d'entrée en la mettant sur la pile de sortie (on transforme au passage un structure LIFO en FIFO, puisqu'on inverse la pile d'entrée). Remarquons au passage que la file est vide si et seulement si les deux piles sont vides.
class Pile :
def __init__(self) :
self.pile = []
def est_pile_vide(self):
return self.pile == []
def empiler(self , element):
self.pile.append(element)
def depiler(self):
if self.est_pile_vide():
raise IndexError("la pile est déjà vide")
else :
return self.pile.pop()
def __repr__(self):
if self.est_pile_vide() :
return 'Pile vide'
else:
return str(self.pile)
def creerPile():
return Pile()
class File:
def __init__(self):
self.entree = Pile()
self.sortie = Pile()
def est_file_vide(self):
return
def enfiler(self , element):
def defiler(self):
def __repr__(self):
if self.est_file_vide() :
return 'File vide'
else:
return repr(self.entree) + " - " + repr(self.sortie)
def creerFile():
return File()
# un test parmi d'autres
a = File()
for i in range(4):
a.enfiler(randint(1, 20))
print(a)
for i in range(2):
print("défiler : ",a.defiler())
print(a)
for i in range(4):
a.enfiler(randint(1,20))
print(a)
while not (a.estFileVide()):
print("défiler : ",a.defiler())
print(a)
Sources :
frederic.mandon@
ac-montpellier.fr, Lycée Jean Jaurès - Saint Clément de Rivière - France (2015-2019)