Dans ce chapitre, on s'intéresse aux structures de données linéaires, autrement dit la façon de représenter des données "qui se suivent". En Python, la structure de données linéaire la plus connue est bien entendu la liste.
Comme tout langage de haut-niveau, Python permet de faire les choses simplement. Si je souhaite créer une liste de nombres et de chaînes de caractères, c'est très simple :
liste = [1, 3.14, "bonjour"]
Dans un langage bas-niveau comme le C, les listes n'existent pas : on dispose à la place de tableaux, dont les différences avec les listes sont notables.
En termes simplifiés, les données sont parfaitement ordonnées dans la mémoire avec les tableaux, et disposés un peu n'importe où avec les listes. Pour définir un tableau en Python, on peut par exemple utiliser le type
Comme les tableaux, il existe 2 autres structures linéaires dont les accès mémoire sont optimisés : il s'agit des piles et des files.
Une pile est une structure de données linéaire qui donne accès en priorité aux dernières données ajoutées. Ainsi, la dernière information ajoutée sera la première à en sortir. Autrement dit, on ne peut accéder qu'à l'objet situé au sommet de la pile.
On décrit souvent ce comportement par l'expression "dernier arrivé, premier sorti" ou encore LIFO pour Last In, First Out. Le principe est celui d'une pile d'assiettes.

Une pile d'assiettes est un exemple de pile !
Cette structure dispose de deux opérations élémentaires :

Opérations élémentaires :
On peut également définir d'autres opérations comme :
On peut réaliser une pile
Voici un exemple d'une pile de taille 4 sous forme d'objet :
>>> P = Pile(4)
>>> P.empiler(6)
>>> P.empiler(5)
>>> P.sommet()
5
>>> P.depiler()
5
>>> P.depiler()
6
>>> P.depiler()
Erreur : la pile est vide
L = [0, None, None, None, None]
L = [1, 6, None, None, None]
L = [2, 6, 5, None, None]
.
.
L = [1, 6, None, None, None]
.
L = [0, None, None, None, None]
.
.
.
class Pile:
def __init__(self, taille):
self.taille = taille
self.L = [0] + [None]*taille
def est_vide(self):
pass
def est_pleine(self):
pass
def sommet(self):
pass
def depiler(self):
pass
def empiler(self, x):
pass
def vider(self):
pass
On n'utilise aucune méthode sur les listes comme
class Pile:
def __init__(self, taille):
self.taille = taille
self.L = [0] + [None]*taille
def est_vide(self):
return self.L[0] == 0
def est_pleine(self):
return self.L[0] == self.taille
def sommet(self):
if self.est_vide():
return None
else:
return self.L[self.L[0]]
def depiler(self):
if self.est_vide():
print("La pile est vide")
return None
else:
sommet = self.sommet() # On stocke le sommet (l'élément à dépiler) dans une variable temporaire
self.L[self.L[0]] = None
self.L[0] -= 1
return sommet
def empiler(self, x):
if self.est_pleine():
print("La pile est pleine")
else:
self.L[0] += 1
self.L[self.L[0]] = x
def vider(self):
elements = []
while not self.est_vide():
elements.append(self.depiler())
return elements
Une file est une structure de données dans laquelle on accède aux éléments suivant la règle du "premier entré, premier sorti. Autrement dit, on ne peut accéder qu'à l'objet situé au début de la file. On parle encore de FIFO pour First In, First Out.
Le principe est celui d'une file de clients à un guichet : le client qui passe en premier est celui qui est arrivé en premier.

Premier arrivé, premier servi !
Une structure de ce type dispose de deux opérations élémentaires :

Opérations élémentaires :
Comme pour la pile, on peut définir d'autres opérations comme :
Une file
Quelques remarques :
Voici un exemple d'implémentation d'une file de taille 3 en objet :
>>> F = File(3)
>>> F.enfiler(5)
>>> F.enfiler(37)
>>> F.defiler()
5
>>> F.enfiler(28)
>>> F.enfiler(49)
>>> F.enfiler(0)
La file est pleine
>>> F.defiler()
37
>>> F.defiler()
28
>>> F.defiler()
49
>>> F.defiler()
La file est vide
L = [2, 2, None, None, None]
L = [2, 3, 5, None, None]
L = [2, 4, 5, 37, None]
L = [3, 4, None, 37, None]
.
L = [3, 2, None, 37, 28]
L = [3, 3, 49, 37, 28]
.
.
L = [4, 3, 49, None, 28]
.
L = [2, 3, 49, None, None]
.
L = [3, 3, None, None, None]
.
.
.
Comme pour la classe
class File:
def __init__(self, taille):
self.taille = taille
self.L = [2,2] + [None]*taille
def tete(self):
return self.L[self.L[0]]
def queue(self):
return self.L[self.L[1]]
def est_vide(self):
return self.tete() == None
def est_pleine(self):
return self.queue() != None
def defiler(self):
if self.est_vide():
print("La file est vide")
return None
else:
tete = self.tete()
self.L[self.L[0]] = None
self.L[0] += 1
if self.L[0] == self.taille + 2: # Vérification du dépassement
self.L[0] = 2
return tete
def emfiler(self, x):
if self.est_pleine():
print("La file est pleine")
else:
self.L[1] += 1
if self.L[1] == self.taille + 2: # Vérification du dépassement
self.L[1] = 2
self.L[self.L[1]] = x
def vider(self):
elements = []
while not self.est_vide():
elements.append(self.defiler())
return elements