ajout de tous les cours et TP préparés cet été

This commit is contained in:
2026-01-17 23:10:49 +01:00
parent ed9415bc81
commit 301cf5a98f
125 changed files with 21614 additions and 542 deletions

102
Pile_File/README.md Normal file
View File

@@ -0,0 +1,102 @@
# Structure de données : Pile et File
> Structures essentielles pour résoudre des problèmes où l'ordre de traitement des données est crucial, comme la gestion des processus ou la navigation dans des graphes, les piles et files permettent de stocker et manipuler des données selon des règles spécifiques. La pile suit un principe **LIFO** (Last In, First Out), tandis que la file suit un principe **FIFO** (First In, First Out).
## Le programme
<img src="Images/bo_1.png" alt="BO_Pile & File" style="zoom:67%;" />
<img src="Images/bo_2.png" alt="BO_Pile&File_2" style="zoom:67%;" />
## 1. Rappel :
<u>**Structure de données**</u> : Collection d'information dans laquelle il est possible de stocker, traiter, organiser, extraire des données.
Les structures de données connues à ce jour sont : Les tableaux, les dictionnaires, les chaînes de caractères, les n-uplets. Chacune de ces structures possèdent des caractéristiques propres qui créent des avantages et des inconvénients selon la situation.
De plus, ces types sont natifs à Python, et aux autres langages selon les cas. Nous n'avons donc ici aucune idée de comment le type *dict* ou *tuple* est créé par exemple.
Les structures de données Pile et File ne sont pas natives à Python et nous aurons donc besoin de les implémenter.
## 2. Interface et implémentation :
Ces deux termes sont particuliers et très importants pour ce chapitre. Alors un petit rappel n'est pas de trop.
<u>**Interface :**</u> L'interface d'un type est définie par les méthodes qui lui sont associées.
**<u>Implémentation :</u>** L'implémentation d'un type est la manière dont on va le coder.
Il faut bien faire la distinction entre les deux termes.
## 3. Pile
### 3. 1. Définition
Une pile est une structure de données dans laquelle les derniers éléments entrant dans la structure seront les premiers à en sortir, nous appelons ce principe **LIFO (Last In First Out)**. Afin d'imager cette structure nous pouvons penser à une pile d'assiettes par exemple.
![image-20220729234146926](Images/Pile.png)
Ici seul le premier élément est accessible.
### 3. 2. Interface
Méthodes associées à la pile :
- Empile : Méthode permettant d'empiler un élément.
- L'élément sera positionné au haut de la pile
- Depile : Méthode permettant d'enlever un élément.
- L'élément enlevé sera celui en haut de la pile.
- Est_vide : Permet de savoir si la pile est vide ou non
On peut ajouter d'autres méthodes :
- Taille : Permet de savoir le nombre d'éléments de la pile
- Top : Permet de connaître l'élément au-dessus de la pile.
## 4. File
### 4. 1. Définition
Une file est une structure de données dans laquelle les premiers éléments entrant dans la structure seront les premiers à en sortir, nous appelons ce principe **FIFO (First In First Out)**. Afin d'imager cette structure nous pouvons penser à une file de voitures sur une route par exemple.
![File](Images/File.png)
Ici seul le premier élément peut sortir de la structure.
### 4. 2. Interface
Méthodes associées à la file :
- Enfile : Méthode permettant d'enfiler un élément.
- L'élément sera positionné en queue de la file
- Defile : Méthode permettant d'enlever un élément.
- L'élément enlevé sera celui en tête de la file.
- Est_vide : Permet de savoir si la file est vide ou non
On peut ajouter d'autres méthodes :
- Taille : Permet de savoir le nombre d'éléments de la file
- Top : Permet de connaître l'élément en tête de la file.
## 5. Conclusion
Les deux structures ont une interface très semblable. Seul le principe FIFO / LIFO peut les différencier.
La suite du chapitre se concentrera sur l'utilisation de ces structures et leurs implémentations.
---------
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -0,0 +1,181 @@
# Corrigé du TD Pile et File
---
## 1. Application de cours
### 1. 1. Pile
**État initial de la pile :**
```
5 ← sommet
4
3
2
1 ← fond
```
**Question 1** : État après `Depile(), Depile(), Empile(7), Empile(8), Depile()`
Exécution pas à pas :
| Opération | État de la pile | Élément retourné |
|-----------|-----------------|------------------|
| Initial | [1, 2, 3, 4, 5] | - |
| Depile() | [1, 2, 3, 4] | 5 |
| Depile() | [1, 2, 3] | 4 |
| Empile(7) | [1, 2, 3, 7] | - |
| Empile(8) | [1, 2, 3, 7, 8] | - |
| Depile() | [1, 2, 3, 7] | 8 |
**État final :**
```
7 ← sommet
3
2
1 ← fond
```
**`top()` renvoie : 7**
---
**Question 2** : Pour que `Est_vide()` soit vrai, il faut dépiler tous les éléments.
```
Depile() → renvoie 5
Depile() → renvoie 4
Depile() → renvoie 3
Depile() → renvoie 2
Depile() → renvoie 1
Est_vide() → True
```
**Réponse : 5 appels à Depile()**
---
**Question 3** : Créer une pile contenant 19982018 (1 en bas de pile)
La pile doit ressembler à :
```
8 ← sommet
1
0
2
8
9
9
1 ← fond
```
**Séquence de méthodes :**
```
Empile(1)
Empile(9)
Empile(9)
Empile(8)
Empile(2)
Empile(0)
Empile(1)
Empile(8)
```
---
### 1. 2. File
**État initial de la file :**
```
Entrée → 5 | 4 | 3 | 2 | 1 → Sortie
↑ ↑
queue tête
```
**Question 1** : État après `Defile(), Defile(), Enfile(7), Enfile(8), Defile()`
Exécution pas à pas :
| Opération | État de la file | Élément retourné |
|-----------|-----------------|------------------|
| Initial | [5, 4, 3, 2, 1] | - |
| Defile() | [5, 4, 3, 2] | 1 |
| Defile() | [5, 4, 3] | 2 |
| Enfile(7) | [7, 5, 4, 3] | - |
| Enfile(8) | [8, 7, 5, 4, 3] | - |
| Defile() | [8, 7, 5, 4] | 3 |
**État final :**
```
Entrée → 8 | 7 | 5 | 4 → Sortie
```
**`top()` renvoie : 4** (élément en tête, prêt à sortir)
---
**Question 2** : Pour que `Est_vide()` soit vrai, il faut défiler tous les éléments.
```
Defile() → renvoie 1
Defile() → renvoie 2
Defile() → renvoie 3
Defile() → renvoie 4
Defile() → renvoie 5
Est_vide() → True
```
**Réponse : 5 appels à Defile()**
---
**Question 3** : Créer une file contenant 19982018 (1 en tête de file)
La file doit ressembler à :
```
Entrée → 8 | 1 | 0 | 2 | 8 | 9 | 9 | 1 → Sortie
tête
```
Pour que 1 soit en tête (premier à sortir), il faut l'enfiler en premier :
**Séquence de méthodes :**
```
Enfile(1)
Enfile(9)
Enfile(9)
Enfile(8)
Enfile(2)
Enfile(0)
Enfile(1)
Enfile(8)
```
---
## Tableau récapitulatif
| Structure | Principe | Ajout | Retrait | Accès |
|-----------|----------|-------|---------|-------|
| **Pile** | LIFO (Last In First Out) | Empile (sommet) | Depile (sommet) | Top (sommet) |
| **File** | FIFO (First In First Out) | Enfile (queue) | Defile (tête) | Top (tête) |
---
## Analogies pour mémoriser
| Structure | Analogie | Explication |
|-----------|----------|-------------|
| **Pile** | Pile d'assiettes | On pose et on prend toujours par le dessus |
| **File** | File d'attente | Le premier arrivé est le premier servi |
| **Pile** | Historique du navigateur | Le bouton "retour" revient à la page précédente (la dernière visitée) |
| **File** | Imprimante | Les documents sont imprimés dans l'ordre d'envoi |
---
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -15,8 +15,8 @@ Le but du TD est de manipuler des piles et des files sans avoir d'implémentatio
1. Quel sera l'état de la pile après l'utilisation des méthodes suivantes :
- Depile(), Depile(), Empile(7), Empile(8),Depile()
- Que renvoie la méthode top() ?
2. Reprenons la pile de l'image, que faut t'il faire comme méthode pour que Est_vide() soit vrai ?
3. En partant de 0 écrire les méthodes permettant de créer une pile contenant les numéros dans cette ordre 19982018. (1 est en bas de pile)
2. Reprenons la pile de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
3. En partant de 0, écrire les méthodes permettant de créer une pile contenant les numéros dans cet ordre : 19982018. (1 est en bas de pile)
### 1. 2. File
@@ -27,5 +27,13 @@ Le but du TD est de manipuler des piles et des files sans avoir d'implémentatio
1. Quel sera l'état de la file après l'utilisation des méthodes suivantes :
- Defile(), Defile(), Enfile(7), Enfile(8),Defile()
- Que renvoie la méthode top() ?
2. Reprenons la file de l'image, que faut t'il faire comme méthode pour que Est_vide() soit vrai ?
3. En partant de 0 écrire les méthodes permettant de créer une file contenant les numéros dans cette ordre 19982018. (1 est en haut de pile)
2. Reprenons la file de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
3. En partant de 0, écrire les méthodes permettant de créer une file contenant les numéros dans cet ordre : 19982018. (1 est en tête de file)
---
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -0,0 +1,494 @@
"""
Corrigé du TP Navigateur — Piles et Files en action
"""
# =============================================================================
# PARTIE 1 : Implémentation des structures
# =============================================================================
class Pile:
"""Structure de données LIFO (Last In First Out)."""
def __init__(self):
"""Initialise une pile vide."""
self.elements = []
def empile(self, element):
"""Ajoute un élément au sommet de la pile."""
self.elements.append(element)
def depile(self):
"""
Retire et renvoie l'élément au sommet.
Renvoie None si la pile est vide.
"""
if self.est_vide():
return None
return self.elements.pop()
def est_vide(self):
"""Renvoie True si la pile est vide."""
return len(self.elements) == 0
def sommet(self):
"""
Renvoie l'élément au sommet sans le retirer.
Renvoie None si la pile est vide.
"""
if self.est_vide():
return None
return self.elements[-1]
def taille(self):
"""Renvoie le nombre d'éléments dans la pile."""
return len(self.elements)
def __repr__(self):
"""Affichage de la pile."""
if self.est_vide():
return "Pile vide"
result = "Sommet\n"
for i in range(len(self.elements) - 1, -1, -1):
result += f" | {self.elements[i]} |\n"
result += "Fond"
return result
class File:
"""Structure de données FIFO (First In First Out)."""
def __init__(self):
"""Initialise une file vide."""
self.elements = []
def enfile(self, element):
"""Ajoute un élément en queue de file."""
self.elements.append(element)
def defile(self):
"""
Retire et renvoie l'élément en tête de file.
Renvoie None si la file est vide.
"""
if self.est_vide():
return None
return self.elements.pop(0)
def est_vide(self):
"""Renvoie True si la file est vide."""
return len(self.elements) == 0
def tete(self):
"""
Renvoie l'élément en tête sans le retirer.
Renvoie None si la file est vide.
"""
if self.est_vide():
return None
return self.elements[0]
def taille(self):
"""Renvoie le nombre d'éléments dans la file."""
return len(self.elements)
def __repr__(self):
"""Affichage de la file."""
if self.est_vide():
return "File vide"
result = "Tête → "
result += "".join(str(e) for e in self.elements)
result += " → Queue"
return result
# =============================================================================
# PARTIE 2 : Simulateur de navigateur web
# =============================================================================
class Navigateur:
"""Simulateur de navigateur web avec historique."""
def __init__(self, page_accueil="https://www.google.com"):
"""
Initialise le navigateur avec une page d'accueil.
:param page_accueil: (str) URL de la page d'accueil
"""
self.historique = Pile()
self.suivant = Pile()
self.historique.empile(page_accueil)
def page_actuelle(self):
"""
Renvoie l'URL de la page actuellement affichée.
:return: (str) URL de la page actuelle ou None
"""
return self.historique.sommet()
def visiter(self, url):
"""
Visite une nouvelle page.
- Empile l'URL dans l'historique
- Vide la pile 'suivant' (on ne peut plus avancer)
:param url: (str) URL de la page à visiter
"""
self.historique.empile(url)
# Vider la pile suivant
while not self.suivant.est_vide():
self.suivant.depile()
def retour(self):
"""
Revient à la page précédente (bouton ←).
- Dépile l'historique
- Empile la page actuelle dans 'suivant'
:return: (str) URL de la nouvelle page actuelle ou None si impossible
"""
if not self.peut_reculer():
return None
page_actuelle = self.historique.depile()
self.suivant.empile(page_actuelle)
return self.page_actuelle()
def avancer(self):
"""
Avance à la page suivante (bouton →).
- Dépile 'suivant'
- Empile dans l'historique
:return: (str) URL de la nouvelle page actuelle ou None si impossible
"""
if not self.peut_avancer():
return None
page_suivante = self.suivant.depile()
self.historique.empile(page_suivante)
return self.page_actuelle()
def peut_reculer(self):
"""Renvoie True si le bouton Retour est actif."""
return self.historique.taille() > 1
def peut_avancer(self):
"""Renvoie True si le bouton Suivant est actif."""
return not self.suivant.est_vide()
def afficher_etat(self):
"""Affiche l'état actuel du navigateur."""
retour = "" if self.peut_reculer() else ""
avancer = "" if self.peut_avancer() else ""
print(f"[{retour}] [{avancer}] | {self.page_actuelle()}")
def afficher_historique(self):
"""
Affiche l'historique complet de navigation.
La page actuelle est marquée d'une flèche.
"""
print("Historique de navigation :")
# Copier la pile pour l'afficher sans la modifier
temp = Pile()
pages = []
while not self.historique.est_vide():
page = self.historique.depile()
pages.append(page)
temp.empile(page)
# Restaurer la pile
while not temp.est_vide():
self.historique.empile(temp.depile())
# Afficher (inverser pour avoir l'ordre chronologique)
pages.reverse()
for i, page in enumerate(pages, 1):
if i == len(pages):
print(f"{i}. {page} (page actuelle)")
else:
print(f" {i}. {page}")
# =============================================================================
# PARTIE 3 : File d'attente Netflix
# =============================================================================
class ListeVisionnage:
"""Gestionnaire de file d'attente de visionnage."""
def __init__(self):
"""Initialise une liste de visionnage vide."""
self.file_attente = File()
self.historique = Pile()
def ajouter(self, titre):
"""
Ajoute un film/série à la file d'attente.
:param titre: (str) Titre du contenu à ajouter
"""
self.file_attente.enfile(titre)
def regarder_suivant(self):
"""
Regarde le prochain élément de la file.
- Défile le contenu
- L'ajoute à l'historique
:return: (str) Titre du contenu regardé ou None
"""
if self.file_attente.est_vide():
return None
contenu = self.file_attente.defile()
self.historique.empile(contenu)
return contenu
def prochain(self):
"""
Renvoie le prochain contenu sans le retirer.
:return: (str) Titre du prochain contenu ou None
"""
return self.file_attente.tete()
def revoir_dernier(self):
"""
Remet le dernier contenu regardé dans la file (en tête).
Utile pour revoir un épisode.
:return: (str) Titre du contenu remis en file ou None
"""
if self.historique.est_vide():
return None
contenu = self.historique.depile()
# Créer une nouvelle file avec ce contenu en tête
nouvelle_file = File()
nouvelle_file.enfile(contenu)
# Transvaser l'ancienne file
while not self.file_attente.est_vide():
nouvelle_file.enfile(self.file_attente.defile())
self.file_attente = nouvelle_file
return contenu
def ajouter_prioritaire(self, titre):
"""
Ajoute un contenu en tête de file (sera regardé en premier).
:param titre: (str) Titre du contenu prioritaire
"""
nouvelle_file = File()
nouvelle_file.enfile(titre)
while not self.file_attente.est_vide():
nouvelle_file.enfile(self.file_attente.defile())
self.file_attente = nouvelle_file
def afficher(self):
"""Affiche l'état de la liste de visionnage."""
print("=== Ma Liste Netflix ===")
print(f"À regarder : {self.file_attente.taille()} élément(s)")
print(f"Déjà vus : {self.historique.taille()} élément(s)")
if not self.file_attente.est_vide():
print(f"Prochain : {self.prochain()}")
# =============================================================================
# PARTIE 4 : Système Undo/Redo
# =============================================================================
class EditeurTexte:
"""Éditeur de texte avec Undo/Redo."""
def __init__(self):
"""Initialise l'éditeur."""
self.texte = ""
self.historique_undo = Pile()
self.historique_redo = Pile()
def ecrire(self, texte_ajoute):
"""
Ajoute du texte.
Sauvegarde l'état actuel dans l'historique.
:param texte_ajoute: (str) Texte à ajouter
"""
self.historique_undo.empile(self.texte)
self.texte += texte_ajoute
# Vider l'historique redo car nouvelle action
while not self.historique_redo.est_vide():
self.historique_redo.depile()
def effacer(self, n=1):
"""
Efface les n derniers caractères.
:param n: (int) Nombre de caractères à effacer
"""
if n > len(self.texte):
n = len(self.texte)
self.historique_undo.empile(self.texte)
self.texte = self.texte[:-n] if n > 0 else self.texte
# Vider l'historique redo
while not self.historique_redo.est_vide():
self.historique_redo.depile()
def undo(self):
"""
Annule la dernière action (Ctrl+Z).
:return: (bool) True si l'annulation a réussi
"""
if self.historique_undo.est_vide():
return False
self.historique_redo.empile(self.texte)
self.texte = self.historique_undo.depile()
return True
def redo(self):
"""
Refait la dernière action annulée (Ctrl+Y).
:return: (bool) True si le redo a réussi
"""
if self.historique_redo.est_vide():
return False
self.historique_undo.empile(self.texte)
self.texte = self.historique_redo.depile()
return True
def afficher(self):
"""Affiche le texte actuel."""
undo_dispo = "Ctrl+Z" if not self.historique_undo.est_vide() else "-----"
redo_dispo = "Ctrl+Y" if not self.historique_redo.est_vide() else "-----"
print(f"[{undo_dispo}] [{redo_dispo}]")
print(f'Texte : "{self.texte}"')
# =============================================================================
# BONUS : File avec deux piles (complexité amortie O(1))
# =============================================================================
class FileDeuxPiles:
"""
Implémentation efficace d'une file avec deux piles.
Complexité amortie O(1) pour toutes les opérations.
"""
def __init__(self):
"""Initialise une file vide."""
self.pile_entree = Pile() # Pour les enfilements
self.pile_sortie = Pile() # Pour les défilements
def enfile(self, element):
"""Ajoute un élément en queue de file. O(1)"""
self.pile_entree.empile(element)
def _transferer(self):
"""Transfère pile_entree vers pile_sortie si nécessaire."""
if self.pile_sortie.est_vide():
while not self.pile_entree.est_vide():
self.pile_sortie.empile(self.pile_entree.depile())
def defile(self):
"""Retire et renvoie l'élément en tête. O(1) amorti."""
self._transferer()
return self.pile_sortie.depile()
def tete(self):
"""Renvoie l'élément en tête sans le retirer. O(1) amorti."""
self._transferer()
return self.pile_sortie.sommet()
def est_vide(self):
"""Renvoie True si la file est vide. O(1)"""
return self.pile_entree.est_vide() and self.pile_sortie.est_vide()
def taille(self):
"""Renvoie le nombre d'éléments. O(1)"""
return self.pile_entree.taille() + self.pile_sortie.taille()
# =============================================================================
# TESTS
# =============================================================================
if __name__ == "__main__":
print("=" * 60)
print("TEST DU NAVIGATEUR")
print("=" * 60)
nav = Navigateur()
nav.afficher_etat()
nav.visiter("https://www.wikipedia.org")
nav.visiter("https://www.youtube.com")
nav.visiter("https://www.github.com")
nav.afficher_etat()
print("\nRetour...")
nav.retour()
nav.afficher_etat()
print("\nRetour...")
nav.retour()
nav.afficher_etat()
print("\nAvancer...")
nav.avancer()
nav.afficher_etat()
print("\nVisite nouvelle page...")
nav.visiter("https://www.python.org")
nav.afficher_etat()
print("\n")
nav.afficher_historique()
print("\n" + "=" * 60)
print("TEST DE NETFLIX")
print("=" * 60)
netflix = ListeVisionnage()
netflix.ajouter("Stranger Things S5")
netflix.ajouter("Wednesday S2")
netflix.ajouter("Squid Game S3")
netflix.afficher()
print(f"\nRegardé : {netflix.regarder_suivant()}")
print(f"Regardé : {netflix.regarder_suivant()}")
netflix.afficher()
print(f"\nRevoir dernier : {netflix.revoir_dernier()}")
netflix.afficher()
print("\n" + "=" * 60)
print("TEST DE L'EDITEUR")
print("=" * 60)
editeur = EditeurTexte()
editeur.ecrire("Bonjour")
editeur.ecrire(" le monde")
editeur.afficher()
print("\nUndo...")
editeur.undo()
editeur.afficher()
print("\nRedo...")
editeur.redo()
editeur.afficher()
print("\nEffacer 6 caractères...")
editeur.effacer(6)
editeur.afficher()

View File

@@ -53,8 +53,8 @@ class File1 :
Fonction qui ajoute un élément, si la taille le permet.
return (bool): Renvoie True si l'ajout de l'élément a eu lieu, False sinon
"""
if file.taille() < 5 :
file.enfile(fichier)
if self.taille() < 7 :
self.enfile(element)
return True
else :
return False
@@ -63,8 +63,8 @@ class File1 :
"""
Fonction qui vide une file et affiche ces éléments
"""
while file.est_vide() == False :
e = file.defile()
while self.est_vide() == False :
e = self.defile()
print(e)
# PARTIE 3 :

View File

@@ -27,7 +27,7 @@ Supposons que notre file à une taille fixe, disons 7 éléments maximum.
## 3. Deuxième implémentation
Ici nous allons implémenter la file de manière récursive. Elle possèdera deux attributs, le premier sera un élément de la pile nommé tête, le second sera une autre File. Cette seconde file possèdera elle aura un élément et une autre file en attribut. Ainsi de suite.
Ici nous allons implémenter la file de manière récursive. Elle possèdera deux attributs, le premier sera un élément de la file nommé tête, le second sera une autre File. Cette seconde file possèdera elle aura un élément et une autre file en attribut. Ainsi de suite.
1. Programmez cette classe nommée File2 avec les méthodes suivantes
* **enfile( )**
@@ -44,11 +44,11 @@ Chacun tire la carte du dessus de son paquet et la pose sur la table. Celui qui
Lorsqu'il y a "bataille" les joueurs tirent la carte suivante et la posent, face cachée, sur la carte précédente. Puis ils tirent une deuxième carte qu'ils posent cette fois-ci face découverte et c'est cette dernière qui départagera les joueurs.
Lorsqu'il y a bataille et qu'un des deux joueur à moins de 3 cartes alors il a perdu
Lorsqu'il y a bataille et qu'un des deux joueurs a moins de 3 cartes alors il a perdu.
Le gagnant est celui qui remporte toutes les cartes.
Le jeu de la bataille peut être facilement coder avec des Files.
Le jeu de la bataille peut être facilement codé avec des Files.
Un fichier carte.py contient la classe carte et les fonctions suivantes :
@@ -69,4 +69,12 @@ Un fichier carte.py contient la classe carte et les fonctions suivantes :
## Pour aller plus loin :
Ecrire une nouvelle implémentation d'une file, cette fois-ci il faut manipuler la file avec deux piles.
Écrire une nouvelle implémentation d'une file, cette fois-ci il faut manipuler la file avec deux piles.
---
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -0,0 +1,530 @@
# TP : Simulateur de Navigateur Web — Piles et Files en action
> **Thème** : Structures de données linéaires (Pile, File)
---
## Contexte
Chaque jour, vous utilisez un navigateur web (Chrome, Firefox, Safari...). Avez-vous déjà remarqué comment fonctionnent les boutons **← Retour** et **→ Suivant** ? Et comment Netflix gère votre file d'attente "**À regarder ensuite**" ?
Dans ce TP, vous allez recréer ces mécanismes en utilisant les structures **Pile** et **File**.
---
## Partie 1 : Implémentation des structures
### Exercice 1 : La classe Pile
Implémentez une classe `Pile` avec les méthodes suivantes :
```python
class Pile:
"""Structure de données LIFO (Last In First Out)."""
def __init__(self):
"""Initialise une pile vide."""
pass
def empile(self, element):
"""Ajoute un élément au sommet de la pile."""
pass
def depile(self):
"""
Retire et renvoie l'élément au sommet.
Renvoie None si la pile est vide.
"""
pass
def est_vide(self):
"""Renvoie True si la pile est vide."""
pass
def sommet(self):
"""
Renvoie l'élément au sommet sans le retirer.
Renvoie None si la pile est vide.
"""
pass
def taille(self):
"""Renvoie le nombre d'éléments dans la pile."""
pass
def __repr__(self):
"""Affichage de la pile."""
pass
```
**Tests à effectuer :**
```python
>>> p = Pile()
>>> p.est_vide()
True
>>> p.empile("A")
>>> p.empile("B")
>>> p.empile("C")
>>> p.sommet()
'C'
>>> p.depile()
'C'
>>> p.taille()
2
```
---
### Exercice 2 : La classe File
Implémentez une classe `File` avec les méthodes suivantes :
```python
class File:
"""Structure de données FIFO (First In First Out)."""
def __init__(self):
"""Initialise une file vide."""
pass
def enfile(self, element):
"""Ajoute un élément en queue de file."""
pass
def defile(self):
"""
Retire et renvoie l'élément en tête de file.
Renvoie None si la file est vide.
"""
pass
def est_vide(self):
"""Renvoie True si la file est vide."""
pass
def tete(self):
"""
Renvoie l'élément en tête sans le retirer.
Renvoie None si la file est vide.
"""
pass
def taille(self):
"""Renvoie le nombre d'éléments dans la file."""
pass
def __repr__(self):
"""Affichage de la file."""
pass
```
**Tests à effectuer :**
```python
>>> f = File()
>>> f.est_vide()
True
>>> f.enfile("Premier")
>>> f.enfile("Deuxième")
>>> f.enfile("Troisième")
>>> f.tete()
'Premier'
>>> f.defile()
'Premier'
>>> f.taille()
2
```
---
## Partie 2 : Simulateur de navigateur web
### Principe de fonctionnement
Un navigateur utilise **deux piles** pour gérer l'historique :
- **Pile `historique`** : contient les pages visitées (la page actuelle est au sommet)
- **Pile `suivant`** : contient les pages "en avant" (après avoir cliqué sur Retour)
| Action | Effet |
|--------|-------|
| Visiter une page | Empile dans `historique`, vide `suivant` |
| Clic sur ← Retour | Dépile `historique` → empile dans `suivant` |
| Clic sur → Suivant | Dépile `suivant` → empile dans `historique` |
---
### Exercice 3 : La classe Navigateur
```python
class Navigateur:
"""Simulateur de navigateur web avec historique."""
def __init__(self, page_accueil="https://www.google.com"):
"""
Initialise le navigateur avec une page d'accueil.
:param page_accueil: (str) URL de la page d'accueil
"""
self.historique = Pile()
self.suivant = Pile()
# À compléter : empiler la page d'accueil
def page_actuelle(self):
"""
Renvoie l'URL de la page actuellement affichée.
:return: (str) URL de la page actuelle ou None
"""
# À compléter
pass
def visiter(self, url):
"""
Visite une nouvelle page.
- Empile l'URL dans l'historique
- Vide la pile 'suivant' (on ne peut plus avancer)
:param url: (str) URL de la page à visiter
"""
# À compléter
pass
def retour(self):
"""
Revient à la page précédente (bouton ←).
- Dépile l'historique
- Empile la page actuelle dans 'suivant'
:return: (str) URL de la nouvelle page actuelle ou None si impossible
"""
# À compléter
pass
def avancer(self):
"""
Avance à la page suivante (bouton →).
- Dépile 'suivant'
- Empile dans l'historique
:return: (str) URL de la nouvelle page actuelle ou None si impossible
"""
# À compléter
pass
def peut_reculer(self):
"""Renvoie True si le bouton Retour est actif."""
# À compléter
pass
def peut_avancer(self):
"""Renvoie True si le bouton Suivant est actif."""
# À compléter
pass
def afficher_etat(self):
"""Affiche l'état actuel du navigateur."""
retour = "←" if self.peut_reculer() else "✗"
avancer = "→" if self.peut_avancer() else "✗"
print(f"[{retour}] [{avancer}] | {self.page_actuelle()}")
```
**Tests à effectuer :**
```python
>>> nav = Navigateur()
>>> nav.afficher_etat()
[] [] | https://www.google.com
>>> nav.visiter("https://www.wikipedia.org")
>>> nav.visiter("https://www.youtube.com")
>>> nav.visiter("https://www.github.com")
>>> nav.afficher_etat()
[] [] | https://www.github.com
>>> nav.retour()
'https://www.youtube.com'
>>> nav.afficher_etat()
[] [] | https://www.youtube.com
>>> nav.retour()
'https://www.wikipedia.org'
>>> nav.avancer()
'https://www.youtube.com'
>>> nav.visiter("https://www.python.org")
>>> nav.afficher_etat()
[] [] | https://www.python.org
>>> nav.peut_avancer()
False # La pile 'suivant' a été vidée
```
---
### Exercice 4 : Historique complet
Ajoutez une méthode pour afficher tout l'historique de navigation :
```python
def afficher_historique(self):
"""
Affiche l'historique complet de navigation.
La page actuelle est marquée d'une flèche.
"""
# À compléter
pass
```
**Exemple de sortie :**
```
Historique de navigation :
1. https://www.google.com
2. https://www.wikipedia.org
3. https://www.youtube.com
→ 4. https://www.github.com (page actuelle)
```
---
## Partie 3 : File d'attente Netflix
### Contexte
Sur Netflix, vous pouvez ajouter des films à votre liste "**À regarder**". Les films sont regardés dans l'ordre d'ajout (FIFO), mais vous pouvez aussi mettre un film en priorité.
---
### Exercice 5 : La classe ListeVisionnage
```python
class ListeVisionnage:
"""Gestionnaire de file d'attente de visionnage."""
def __init__(self):
"""Initialise une liste de visionnage vide."""
self.file_attente = File()
self.historique = Pile() # Films déjà regardés
def ajouter(self, titre):
"""
Ajoute un film/série à la file d'attente.
:param titre: (str) Titre du contenu à ajouter
"""
# À compléter
pass
def regarder_suivant(self):
"""
Regarde le prochain élément de la file.
- Défile le contenu
- L'ajoute à l'historique
:return: (str) Titre du contenu regardé ou None
"""
# À compléter
pass
def prochain(self):
"""
Renvoie le prochain contenu sans le retirer.
:return: (str) Titre du prochain contenu ou None
"""
# À compléter
pass
def revoir_dernier(self):
"""
Remet le dernier contenu regardé dans la file (en tête).
Utile pour revoir un épisode.
:return: (str) Titre du contenu remis en file ou None
"""
# À compléter (utiliser une file temporaire ou une autre approche)
pass
def afficher(self):
"""Affiche l'état de la liste de visionnage."""
print("=== Ma Liste Netflix ===")
print(f"À regarder : {self.file_attente.taille()} élément(s)")
print(f"Déjà vus : {self.historique.taille()} élément(s)")
if not self.file_attente.est_vide():
print(f"Prochain : {self.prochain()}")
```
**Tests à effectuer :**
```python
>>> netflix = ListeVisionnage()
>>> netflix.ajouter("Stranger Things S5")
>>> netflix.ajouter("Wednesday S2")
>>> netflix.ajouter("Squid Game S3")
>>> netflix.afficher()
=== Ma Liste Netflix ===
À regarder : 3 élément(s)
Déjà vus : 0 élément(s)
Prochain : Stranger Things S5
>>> netflix.regarder_suivant()
'Stranger Things S5'
>>> netflix.regarder_suivant()
'Wednesday S2'
>>> netflix.afficher()
=== Ma Liste Netflix ===
À regarder : 1 élément(s)
Déjà vus : 2 élément(s)
Prochain : Squid Game S3
>>> netflix.revoir_dernier()
'Wednesday S2'
>>> netflix.prochain()
'Wednesday S2'
```
---
### Exercice 6 : File avec priorité
Netflix permet aussi de mettre un contenu "en haut de la liste". Ajoutez cette fonctionnalité :
```python
def ajouter_prioritaire(self, titre):
"""
Ajoute un contenu en tête de file (sera regardé en premier).
Nécessite de reconstruire la file.
:param titre: (str) Titre du contenu prioritaire
"""
# Indice : créer une nouvelle file, enfiler le titre prioritaire,
# puis transvaser l'ancienne file
pass
```
**Test :**
```python
>>> netflix.ajouter("Film 1")
>>> netflix.ajouter("Film 2")
>>> netflix.ajouter_prioritaire("Film URGENT")
>>> netflix.prochain()
'Film URGENT'
```
---
## Partie 4 : Système Undo/Redo
### Exercice 7 : Éditeur de texte simplifié
Créez un éditeur qui permet d'annuler (Ctrl+Z) et de refaire (Ctrl+Y) des actions.
```python
class EditeurTexte:
"""Éditeur de texte avec Undo/Redo."""
def __init__(self):
"""Initialise l'éditeur."""
self.texte = ""
self.historique_undo = Pile() # États précédents
self.historique_redo = Pile() # États annulés
def ecrire(self, texte_ajoute):
"""
Ajoute du texte.
Sauvegarde l'état actuel dans l'historique.
:param texte_ajoute: (str) Texte à ajouter
"""
# À compléter
pass
def effacer(self, n=1):
"""
Efface les n derniers caractères.
:param n: (int) Nombre de caractères à effacer
"""
# À compléter
pass
def undo(self):
"""
Annule la dernière action (Ctrl+Z).
:return: (bool) True si l'annulation a réussi
"""
# À compléter
pass
def redo(self):
"""
Refait la dernière action annulée (Ctrl+Y).
:return: (bool) True si le redo a réussi
"""
# À compléter
pass
def afficher(self):
"""Affiche le texte actuel."""
undo_dispo = "Ctrl+Z" if not self.historique_undo.est_vide() else "-----"
redo_dispo = "Ctrl+Y" if not self.historique_redo.est_vide() else "-----"
print(f"[{undo_dispo}] [{redo_dispo}]")
print(f"Texte : \"{self.texte}\"")
```
**Tests :**
```python
>>> editeur = EditeurTexte()
>>> editeur.ecrire("Bonjour")
>>> editeur.ecrire(" le monde")
>>> editeur.afficher()
[Ctrl+Z] [-----]
Texte : "Bonjour le monde"
>>> editeur.undo()
True
>>> editeur.afficher()
[Ctrl+Z] [Ctrl+Y]
Texte : "Bonjour"
>>> editeur.redo()
True
>>> editeur.afficher()
[Ctrl+Z] [-----]
Texte : "Bonjour le monde"
>>> editeur.effacer(6)
>>> editeur.afficher()
[Ctrl+Z] [-----]
Texte : "Bonjour le"
```
---
## Bonus : Comparaison des complexités
| Opération | Pile (liste Python) | File (liste Python) | File (deux piles) |
|-----------|---------------------|---------------------|-------------------|
| Empile/Enfile | O(1) | O(n)* | O(1) amorti |
| Dépile/Défile | O(1) | O(1) | O(1) amorti |
| Sommet/Tête | O(1) | O(1) | O(1) |
| Est_vide | O(1) | O(1) | O(1) |
*L'insertion en début de liste Python est en O(n).
**Exercice bonus** : Implémentez une file efficace en utilisant deux piles.
---
## Résumé des notions
| Structure | Principe | Analogie | Cas d'usage |
|-----------|----------|----------|-------------|
| **Pile** | LIFO | Pile d'assiettes | Historique, Undo, Appels de fonctions |
| **File** | FIFO | File d'attente | Impression, Streaming, BFS |
---
Auteurs : Florian Mathieu
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -44,7 +44,7 @@ Afin d'implémenter la pile il nous faut utiliser une structure de données perm
## 2. 2. Calculatrice polonaise inverse
### 2. 2. Calculatrice polonaise inverse
La calculatrice polonaise inverse permet de faire des calculs simple mais pose l'opérateur après les deux opérandes.
@@ -75,7 +75,7 @@ La calculatrice polonaise inverse permet de faire des calculs simple mais pose l
Le but ici est de trier une pile. Pour cela nous utiliserons une autre pile temporaire permettant de stocker les éléments.
1. Ecrire une fonction tri_pile( ) prennant en paramètre une pile et renvoyant la pile triée.
1. Écrire une fonction tri_pile( ) prenant en paramètre une pile et renvoyant la pile triée.
> L'idée ici est d'utiliser seulement deux piles. Afin de comprendre le fonctionnement il faut faire quelques essais à la main.
@@ -98,3 +98,10 @@ Le but ici est de trier une pile. Pour cela nous utiliserons une autre pile temp
9
```
---
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -8,8 +8,8 @@ class Pile :
def empile(self,x) :
"""
Méthode qui enpile un élément
param x : () Elément x à enpiler
Méthode qui empile un élément
param x : () Elément x à empiler
"""
self.pile.append(x)
@@ -52,8 +52,8 @@ class Pile :
while pile_tmp.taille() != 0 and pile_tmp.top() < val_tmp:
self.empile(pile_tmp.depile())
pile_tmp.empile(val_tmp)
p.pile = pile_tmp.pile
return p
self.pile = pile_tmp.pile
return self
p = Pile()