Lien vers l'activité : type abstrait File FIFO
Dernière modif. : 25 10 2020
1 - Type abstrait FILE / QUEUE
Organisation générale
C'est une séquence ordonnée et finie d'éléments respectant le principe FIFO.
FIFO veut dire First In First Out. Le premier élément arrivé sera le premier à repartir.
On peut donc voir ce type abstrait comme une sorte de LISTE où on s'engage à n'agir que sur les extrémités : l'entrée dans la PILE est nommée ARRIERE et la sortie de la PILE se nomme AVANT.
Fonctions d'interface minimale
Il en existe des versions mutables et non mutables. Ici, c'est non mutable.
nouvelleFile() -> File
estVide(file:File) -> bool
enfiler(elt:Elt, file:File) -> File
: on rajoute un élément ARRIERE
defiler(file:File) -> File
: on supprime l'élément AVANT.
lireAvant(file:File) -> Elt
2 Implémentations
Tableau ne contenant que les données
On retrouve l'utilisation d'un TABLEAU . Mais c'est peu efficace (linéaire au défilement)
Deux piles
On peut même implémenter une FILE comme un tableau de deux PILES.
- La pile
pileEntree
stocke les entrées dans la FILE. On la stocke à l'index 0 de la FILE.
- La pile
pileSortie
stocke les sorties de la FILE. On la stocke à l'index 1 de la FILE.
- Si on veut utiliser
defiler
ou lireAvant
alors que pileSortie
est vide, on déverse tous les éléments de la PILE d'entrée vers la pile de SORTIE : cela a pour effet d'inverser l'ordre d'arrivée dans la pile de sortie !
L'ensemble des deux piles se comportent donc comme une file. Il suffit de déverser la pile d'entrée dans la pile de sortie à chaque fois que la sortie est vide.
Voir le schéma ci-dessous.
Liste chaînée
Cette implémentation est efficace car on obtient un coût CONSTANT à l'enfilement et au défilement.
On trouve des versions avec des objets et des versions basées sur des tableaux servant de cellules.
Tableau contenant infos et tableau de données
Coût CONSTANT également mais on utilise des tableaux non homogènes.
Dictionnaire contenant infos et tableau de données
Coût CONSTANT à l'enfilement et au défilement.
Et bien d'autres encore
On trouve des versions utilisant un simple tableau, deux tableaux... Tout est possible tant que cela respecte le principe FIFO.
Implémentation avec le type natif list
de Python (peu efficace)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| class Elt :
'''Juste pour pouvoir noter Elt dans les prototypes'''
class File :
'''Juste pour pouvoir noter File dans les prototypes'''
'''Implémentation de type abstrait Pile en utilisant des tableaux dynamiques'''
def nouvelleFile() -> File:
return []
def fileVide(f:File) -> bool:
return f == []
def enfiler(elt:Elt, f:File) -> None :
f.append(elt) # rajoute l'élément à la fin du tableau (ARRIERE pour nous)
def defiler(f:File) -> Elt:
if not fileVide(f) :
return f.pop(0) # supprime et renvoie le premier élément du tableau (AVANT pour nous)
def lireAvant(f:File) -> Elt:
if not fileVide(f) :
return f[0] # renvoie le contenu de l'index 0, AVANT pour nous
|
Implémentation classique à connaître : deux piles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| class Elt :
/'/'/'Juste pour pouvoir noter Elt dans les prototypes/'/'/'
class Pile :
'''Juste pour pouvoir noter Pile dans les prototypes'''
class File :
'''Juste pour pouvoir noter File dans les prototypes'''
'''Implémentation de type abstrait Pile en utilisant des tuples (sommet, autre_pile)'''
def nouvellePile() -> Pile :
'''Renvoie une liste vide'''
return ()
def pileVide(p:Pile) -> bool :
'''Renvoie True si la pile est vide'''
return p == ()
def empiler(elt:Elt, p:Pile) -> Pile :
'''Renvoie une nouvelle pile où elt est le sommet et pile la suite de notre nouvelle pile.'''
return (elt, p)
def lireSommet(p:Pile) -> Elt :
'''Renvoie la valeur stockée au sommet, sans la supprimer de la pile'''
if not pileVide(p) :
return p[0]
def depiler(p:Pile) -> Pile :
'''Renvoie une nouvelle pile où on a supprimé l'ancien sommet'''
if pileVide(p) : # la liste envoyée est ()
return nouvellePile()
else :
return p[1]
# Fonction de l'implémentation FILE hors Interface
def deverser(f:File) -> None :
while not pileVide(f[0]) :
element = lireSommet(f[0])
f[0] = depiler(f[0])
f[1] = empiler(element, f[1])
# Fonctions d'interface de la FILE
def nouvelleFile() -> File :
pileEntree = nouvellePile() # inputStack en anglais
pileSortie = nouvellePile() # outputStack en anglais
return [pileEntree, pileSortie]
def fileVide(f:File) -> None :
return pileVide(f[0]) and pileVide(f[1])
def enfiler(elt:Elt, f:File) -> None:
f[0] = empiler(elt, f[0])
def defiler(f:File) -> Elt:
if not fileVide(f) :
if pileVide(f[1]) :
deverser(f)
valeur = lireSommet(f[1])
f[1] = depiler(f[1])
return valeur
def lireAvant(f:File) -> Elt :
if not fileVide(f) :
if pileVide(f[1]) :
deverser(f)
return lireSommet(f[1])
|
Implémentation efficace : la liste chaînée
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
| '''Implémentation de la file sous forme d'une liste chaînée'''
# Déclaration des Classes Cellule et File
class Elt :
'''Juste pour pouvoir noter Elt dans les déclarations des fonctions'''
class Cellule :
'''Classe permettant de créer des cellules-maillons basiques'''
def __init__(self, valeur, suivant) :
assert isinstance(suivant, Cellule) or suivant == None
self.v = valeur
self.s = suivant
def renvoyerCelluleFinale(self) :
if self.s == None :
return self
else :
return self.s.renvoyerCelluleFinale()
class File :
'''Classe implémentant une Liste sous forme Liste chaînée '''
def __init__(self) :
self.avant = None
self.arriere = None
self.nombre = 0
# Fonction d'observation qui n'a rien à faire dans l'interface d'une File !
def afficherFile(f) :
'''Fonction debug, ce n'est pas une fonction d'interface. Affiche Avant -> Arrière'''
tableau = recupererValeur(f.avant)
return tuple(tableau)
def recupererValeur(cellule) :
if cellule.s == None :
return [cellule.v]
else :
return [cellule.v] + recupererValeur(cellule.s)
# Fonctions d'interface de la FILE
def nouvelleFile() -> File :
return File()
def fileVide(f:File) -> bool :
return f.avant == None
def enfiler(x:Elt, f:File) -> None :
'''On insére la nouvelle valeur à l'arrière'''
if fileVide(f) : # C'est vide : Avant et Arrière sont la même Cellule
cellule = Cellule(x, None)
f.avant = cellule
f.arriere = cellule
f.nombre = 1
else : # Il y a déja une cellule Arrière : on lui rajoute une suite
cellule = Cellule(x, None)
f.arriere.s = cellule # on rajoute la cellule à la suite de l'actuelle arrière
f.arriere = cellule # on déclare la nouvelle cellule comme l'arrière
f.nombre = f.nombre + 1
def lireAvant(f:File) -> Elt :
if not fileVide(f) :
return f.avant.v
def defiler(f:File) -> Elt :
if not fileVide(f) :
reponse = f.avant.v # on mémorise l'ancienne valeur à l'avant
f.avant = f.avant.s # la nouvelle Cellule avant est le successeur de la précédente
if f.avant == None : # si l'avant n'existe pas en réalité
f.arriere = None
f.nombre = f.nombre - 1
return reponse # on renvoie la valeur supprimée
def taille(f:File) -> int :
return f.nombre
|