Skip to main content Informatique en prépa - Lycée Malherbe 

13.1- TP - Piles et files

Ce TP a pour but de vous faire travailler les implémentations de file, avec une proposition d'application.

Commencez par exécuter la cellule suivante :

Python
code masqué : pas besoin de le lire pour suivre, exécutez-le simplement

I. Rappels

Rappel : les piles

Pour rappel, les piles, ou Last In First Out, sont une structure de données semblable à une pile d'assiettes, avec les opérations suivantes :

En python, cela correspond au type list, avec ses méthode L.append(x) et L.pop().

3
2
1
pile

 

Les files

Les files, ou FIFO, First In First Out, sont une structure de données semblable à une file d'attente, avec les opérations suivantes :

entrée →
3
2
1
→ sortie

 

On va s'intérésser à trois implémentations possibles des files.

II. Implémentation naïve

On va commencer par faire une implémentation dite naïve des files, en utilisant des listes. On va ajouter les éléments à la fin de la liste et les enlever au début.

Question 1

Complétez les fonctions suivantes de la manière la plus simple possible, sans se soucier de la complexité des opérations.

Python

Loading editor...

def file_vide():
    """créé et renvoie une file vide"""
    #à compléter

def enfiler(file, x):
    """enfile l'élément 'x' à la file 'file' """
    #à compléter

def defiler(file):
    """defile et renvoie un élément de la file"""
    #à compléter
Python

Loading editor...

III. Application

On propose l'application suivante : on a une imprimante, et un certain nombre de terminaux (téléphones, ordinateurs) connectés à cet imprimante.

Pour simplifier, on suppose qu'une impression met une seconde. Par contre, les demandes d'impression par les terminaux peuvent arriver à n'importe quelle fréquence !

Question 2

Complétez ces deux fonctions pour faire fonctionner le serveur d'impression de manière cohérente. Vous pouvez ensuite exécuter la cellule await lancer_imprimante() pour simuler l'exécution avec vos fonctions : les demandes et les impressions s'afficheront au fur et à mesure sous la cellule.

La fonction prochain_document peut renvoyer None s'il n'y a rien à imprimer.

Python

Loading editor...

file = #à compléter
def prochain_document():
    #à compléter

def demande_impression(document):
    #à compléter
Python

Loading editor...

await lancer_imprimante()
Python

Loading editor...

IV. Implémentation efficace des files

Tant qu'on a 10 documents à imprimer, peu importe si notre file est efficace ou non. Mais maintenant, imaginons que vous gérer l'ensemble des tâches d'un ordinateur... Il y en a possiblement des milliers, à gérer chaque miliseconde ! Dans ce cas, on a besoin d'implémentations plus efficaces.

On va ici en proposer deux.

1. La double pile

Question 3

Supposons qu'on aie une variable pile contenant une pile (sous la forme d'une liste python).

Que se passe-il si on prend les éléments de la pile, un à un, et qu'on les transfert dans une autre pile ? Pour rappel, on n'utilise seulement les opérations .append et .pop.

Et non ! Les éléments sont-ils vraiment dans le même ordre ?

En effet : les éléments d'en haut se retrouvent en bas, et vice-versa.

Question 4

Écrivez une fonction transfert qui prend en argument une pile pile (sous forme de liste python), et une liste vide resultat, et qui transfert les éléments de pile dans resultat avec uniquement append et pop. A la fin de votre fonction, resultat doit contenir pile inversé, et pile doit être vide. Testez-là sur la liste [1, 2, 3, 4, 5].

Python

Loading editor...

def transfert(pile, resultat):
    """Transfere les élémentes de "pile" à "résultat" """
    #à compléter

On va maintenant utiliser cette propriété pour implémenter une file. L'idée est d'avoir une pile "d'entrée" et une pile de "sortie". Notre "file" sera donc constituée de deux piles !

pile d'entrée
pile de sortie

 

Essayez : enfilez quelques éléments, puis défilez, et observez le transfert d'une pile à l'autre.

L'idée ici, est d'ajouter tous les éléments dans la pile d'entrée, avec un simple append. Mais lorsqu'on veut sortir un élément, on ne peux pas utiliser pop sur la même pile, sinon on sortirait les éléments à l'envers, et on aurait, justement, une pile (et pas une file !).

On va donc placer, en inversé, toute la pile d'entrée dans la pile de sortie. Les éléments de cette dernière seront alors dans le bon ordre pour être pop directement !

Attention, pour que l'ordre soit préservé, il faut respecter une règle : on ne transfère la pile d'entrée dans la pile de sortie que si la pile de sortie est vide.

Question 5

Effectuez la séquence d'opération suivante sur papier, en dessinant l'état des deux piles au fur et à mesure de l'execution :

  • enfile 1
  • enfile 2
  • enfile 3
  • defile
  • defile
  • enfile 4
  • defile
  • defile
  • enfile 5

On va utiliser une liste de deux listes pour implémenter notre file en python : file = [[3, 4, 5], [2, 1]].

Question 6

Écrivez une fonction python file_vide2 pour créer une nouvelle file vide.

Python

Loading editor...

Question 7

Écriver une fonction enfile2 qui prend en argument une file et un élément, et qui y enfile l'élément.

Python

Loading editor...

Question 8

Écriver une fonction defile2 qui prend en argument une file (donc une paire de listes), et qui y défile un élément et le renvoie. Vous pouvez utiliser de votre fonction de la question 4.

Python

Loading editor...

Question 9

Modifiez l'exemple de l'imprimante pour utiliser vos nouvelles fonctions, et vérifiez que l'ordre est bien le bon.

Python

Loading editor...

2. La liste circulaire

L'autre manière classique d'implémenter une file, est d'utiliser une "liste circulaire".

L'idée est d'avoir deux pointeurs (des indices de listes), pour le début et la fin, qui se déplacent quand on ajoute ou retire des éléments. Nos éléments sont stockés dans une liste python de taille fixe, et quand on arrive au bout, on revient au début.

Voici une petite animation du fonctionnement :

0123456débutfin
1 / 30

file vide

Il est important, pour cette implémentation, que la file ne "déborde" pas : si le pointeur début rattrape le pointeur fin, on doit renvoyer une erreur. Dans le cadre de ce TP, vous pourrez supposer que ce cas n'arrive jamais.

En python, on va prendre un type de file qui est un triplet (liste de 3 éléments) [liste, debut, fin].

Dans le dessin, liste est la série de 7 carrés. Ces carrés (les éléments de la liste) peuvent être soit pleins (et contenir un nombre), soit vides (les carrés blanc, que vous pouvez remplir par exemple par None).

debut et fin sont des indices de cette liste, représentés dans le dessin par les flèches correspondantes.

Question 10

Écrivez une fonction cree_file3(n) qui créé une nouvelle file, vide, avec une capacité (donc taille maximale) de n.

Python

Loading editor...

Question 11

Écrivez une fonction enfile3(file, x) qui ajoute un élément à la file, ou renvoie une erreur si celle-ci est pleine (en utilisant assert par exemple).

Python

Loading editor...

Question 12

Écrivez une fonction defile3(file) qui défile un élément de la file, et renvoie une erreur si celle-ci est vide.

Python

Loading editor...

Question 13

Testez à nouveau vos fonctions sur l'exemple de l'imprimante.

Python

Loading editor...


Entrez le code donné en cours pour accéder à la solution :