Bienvenue à l'ORBITECH AI Academy !
Salut à toi, futur expert en informatique ! Aujourd'hui, on va s'attaquer à un pilier fondamental de la programmation : les structures de données. Listes, piles et files sont des outils indispensables pour organiser et manipuler l'information de manière efficace. Cette série d'exercices progressifs est conçue pour te permettre de maîtriser leurs principes, leurs opérations et leurs implémentations, te préparant ainsi à des défis algorithmiques plus complexes.
Compétences travaillées :
- Comprendre et différencier les structures de données : listes chaînées, piles (LIFO) et files (FIFO).
- Maîtriser les opérations de base (ajout, suppression, consultation) sur ces structures.
- Appliquer ces structures pour résoudre des problèmes algorithmiques.
- Implémenter des structures de données simples en pseudo-code ou avec des types abstraits.
Erreurs Fréquentes à Éviter :
- Confondre le principe LIFO (Last-In, First-Out) des piles avec le principe FIFO (First-In, First-Out) des files.
- Oublier de gérer les cas limites lors de l'implémentation (structure vide, structure pleine, etc.).
- Ne pas actualiser correctement les pointeurs ou références dans les listes chaînées lors des insertions/suppressions.
- Tenter d'accéder à un élément inexistant sans vérification préalable.
Exercices de Pratique
Exercice 1 : Concepts Fondamentaux
Définis avec tes propres mots les structures de données suivantes et donne un exemple d'application concrète pour chacune :
- Une Pile
- Une File
- Une Liste Chaînée (simple)
Barème indicatif : 2 points
Correction :
- Une Pile :
Une pile est une structure de données linéaire qui suit le principe LIFO (Last-In, First-Out). Le dernier élément ajouté est le premier à être retiré. Imagine une pile d'assiettes : tu ajoutes des assiettes sur le dessus, et tu retires toujours celle du dessus.
Exemple d'application : La gestion des appels de fonctions dans un programme (pile d'exécution), l'historique "annuler/rétablir" d'un éditeur de texte, la vérification de parenthèses équilibrées.
- Une File :
Une file est une structure de données linéaire qui suit le principe FIFO (First-In, First-Out). Le premier élément ajouté est le premier à être retiré. Imagine une file d'attente à la caisse : le premier client arrivé est le premier servi.
Exemple d'application : La gestion des tâches dans un système d'exploitation, l'impression de documents (spool d'impression), les requêtes réseau en attente, les algorithmes de parcours en largeur (BFS).
- Une Liste Chaînée (simple) :
Une liste chaînée est une collection ordonnée d'éléments (appelés nœuds), où chaque nœud contient une donnée et une référence (ou pointeur) vers le nœud suivant. Contrairement aux tableaux, les éléments ne sont pas stockés de manière contiguë en mémoire. On peut parcourir la liste en suivant les références d'un nœud à l'autre.
Exemple d'application : L'implémentation de piles et de files, la gestion de listes de lecture musicales, la représentation de polynômes, les systèmes de gestion de mémoire.
Résultat : Définitions claires avec exemples pertinents.
Point méthode : Comprendre la différence entre LIFO et FIFO est crucial. LIFO pour "pile" (stack), FIFO pour "file" (queue).
Exercice 2 : Opérations sur une Pile
Soit une pile initialement vide. Représente l'état de la pile après chaque opération suivante :
- Empiler (push) 'A'
- Empiler (push) 'B'
- Dépiler (pop)
- Empiler (push) 'C'
- Empiler (push) 'D'
- Dépiler (pop)
Barème indicatif : 1.5 points
Correction :
On représente la pile verticalement, le sommet étant le dernier élément.
- Empiler 'A' :
[A]
- Empiler 'B' :
[B] [A]
- Dépiler : 'B' est retiré.
[A]
- Empiler 'C' :
[C] [A]
- Empiler 'D' :
[D] [C] [A]
- Dépiler : 'D' est retiré.
[C] [A]
Résultat final de la pile : [C, A] (avec 'C' au sommet).
Astuce : Visualise toujours le sommet de la pile pour savoir quel élément sera dépilé. Le principe LIFO est la clé.
Exercice 3 : Opérations sur une File
Soit une file initialement vide. Représente l'état de la file (éléments dans l'ordre de leur position) après chaque opération suivante :
- Enfiler (enqueue) 'X'
- Enfiler (enqueue) 'Y'
- Défiler (dequeue)
- Enfiler (enqueue) 'Z'
- Enfiler (enqueue) 'W'
- Défiler (dequeue)
Barème indicatif : 1.5 points
Correction :
On représente la file horizontalement, le début (tête) à gauche et la fin (queue) à droite.
- Enfiler 'X' :
[X]
- Enfiler 'Y' :
[X, Y]
- Défiler : 'X' est retiré (le premier arrivé).
[Y]
- Enfiler 'Z' :
[Y, Z]
- Enfiler 'W' :
[Y, Z, W]
- Défiler : 'Y' est retiré (le premier arrivé parmi les restants).
[Z, W]
Résultat final de la file : [Z, W] (avec 'Z' en tête).
Astuce : Pense à la file d'attente d'une caisse. Le premier qui arrive est le premier à partir. Le principe FIFO est essentiel ici.
Exercice 4 : Parcours de Liste Chaînée
On considère une liste chaînée simple représentée par une séquence de nœuds. Chaque nœud contient une valeur et un pointeur vers le nœud suivant. Le dernier nœud pointe vers NULL.
Liste : 10 -> 20 -> 30 -> 40 -> NULL
Décris en pseudo-code l'algorithme pour parcourir cette liste et afficher toutes les valeurs qu'elle contient.
Barème indicatif : 1.5 points
Correction :
Pour parcourir une liste chaînée, tu dois commencer par le premier nœud (la tête de la liste) et suivre les pointeurs de nœud en nœud jusqu'à atteindre NULL.
PROCEDURE AfficherListe(tete_liste) nœud_actuel = tete_liste TANT QUE nœud_actuel EST NON_NULL FAIRE AFFICHER nœud_actuel.valeur nœud_actuel = nœud_actuel.suivant FIN TANT QUE FIN PROCEDURE
Résultat : L'algorithme affichera : 10, 20, 30, 40.
Point méthode : Le parcours de liste chaînée est un concept fondamental. Il est important de ne pas oublier d'avancer le pointeur nœud_actuel pour éviter une boucle infinie.
Exercice 5 : Implémentation de Pile avec un Tableau Dynamique (ou Liste Python)
Propose un pseudo-code pour implémenter une Pile en utilisant un tableau dynamique (comme une liste en Python). Tu devras définir les fonctions empiler(element), depiler() et est_vide().
Barème indicatif : 2 points
Correction :
Une pile peut être facilement implémentée à l'aide d'un tableau dynamique où l'on ajoute et retire toujours à la fin.
CLASSE Pile: ATTRIBUT tableau_interne : liste vide PROCEDURE empiler(element): AJOUTER element À LA FIN de tableau_interne FIN PROCEDURE PROCEDURE depiler(): SI est_vide() ALORS AFFICHER "Erreur: Pile vide" RETOURNE NULL // Ou lever une exception SINON RETOURNE ET SUPPRIMER LE DERNIER élément de tableau_interne FIN SI FIN PROCEDURE FONCTION est_vide(): RETOURNE VRAI SI tableau_interne EST VIDE, FAUX SINON FIN FONCTION FONCTION sommet(): SI est_vide() ALORS RETOURNE NULL SINON RETOURNE LE DERNIER élément de tableau_interne FIN SI FIN FONCTION FIN CLASSE
Résultat : Pseudo-code fonctionnel pour une pile basée sur un tableau dynamique.
Astuce : En Python, tu utiliserais append() pour empiler, pop() pour dépiler, et len() == 0 pour vérifier si la pile est vide. C'est l'un des moyens les plus simples d'implémenter une pile.
Exercice 6 : Implémentation de File avec un Tableau Dynamique
Propose un pseudo-code pour implémenter une File en utilisant un tableau dynamique. Tu devras définir les fonctions enfiler(element), defiler() et est_vide().
Barème indicatif : 2 points
Correction :
L'implémentation d'une file avec un tableau dynamique est un peu plus délicate qu'une pile. Si tu utilises pop() au début du tableau pour defiler(), cela peut être coûteux en performance car tous les éléments doivent être décalés. Cependant, pour cet exercice en pseudo-code, on acceptera cette approche simple.
CLASSE File: ATTRIBUT tableau_interne : liste vide PROCEDURE enfiler(element): AJOUTER element À LA FIN de tableau_interne FIN PROCEDURE PROCEDURE defiler(): SI est_vide() ALORS AFFICHER "Erreur: File vide" RETOURNE NULL SINON RETOURNE ET SUPPRIMER LE PREMIER élément de tableau_interne FIN SI FIN PROCEDURE FONCTION est_vide(): RETOURNE VRAI SI tableau_interne EST VIDE, FAUX SINON FIN FONCTION FONCTION premier(): SI est_vide() ALORS RETOURNE NULL SINON RETOURNE LE PREMIER élément de tableau_interne FIN SI FIN FONCTION FIN CLASSE
Résultat : Pseudo-code fonctionnel pour une file basée sur un tableau dynamique.
Point méthode : Bien que fonctionnelle, l'opération supprimer le premier élément d'un tableau dynamique peut avoir une complexité de $O(N)$ car elle nécessite de décaler tous les autres éléments. Pour une file plus performante, on utiliserait souvent une liste chaînée ou un tableau circulaire.
Exercice 7 : Vérification de Parenthèses Équilibrées
Écris un pseudo-code pour vérifier si une expression mathématique contient des parenthèses, crochets et accolades équilibrés. Par exemple :
"([{}])"est équilibré."({[)})"n'est pas équilibré."[(])"n'est pas équilibré.
Utilise une structure de pile pour résoudre ce problème.
Barème indicatif : 3 points
Correction :
Ce problème est un cas d'école pour l'utilisation des piles. L'idée est d'empiler les parenthèses ouvrantes et de dépiler quand une parenthèse fermante correspond. Si la pile est vide à la fin et qu'aucune incohérence n'a été trouvée, l'expression est équilibrée.
FONCTION SontParenthèsesÉquilibrées(expression):
pile = CREER_PILE_VIDE()
parenthèses_ouvrantes = "([{"
parenthèses_fermantes = ")]}"
paires_parenthèses = {')': '(', ']': '[', '}': '{'}
POUR CHAQUE caractère DANS expression FAIRE
SI caractère EST DANS parenthèses_ouvrantes ALORS
empiler(pile, caractère)
SINON SI caractère EST DANS parenthèses_fermantes ALORS
SI est_vide(pile) ALORS
RETOURNE FAUX // Une parenthèse fermante sans parenthèse ouvrante correspondante
FIN SI
dernier_ouvrant = depiler(pile)
SI dernier_ouvrant N'EST PAS paires_parenthèses[caractère] ALORS
RETOURNE FAUX // Non-correspondance
FIN SI
FIN SI
FIN POUR
RETOURNE est_vide(pile) // Vrai si toutes les parenthèses ont été appariées
FIN FONCTION
Résultat : Pseudo-code pour vérifier l'équilibre des parenthèses à l'aide d'une pile.
Point méthode : L'utilisation d'un dictionnaire (ou map) pour stocker les paires de parenthèses est une approche élégante et efficace.
Exercice 8 : Utilisation de File pour le Parcours en Largeur (BFS - Conceptuel)
Imagine que tu as un réseau social simple où chaque personne est un nœud et les amitiés sont des connexions. Tu veux trouver tous les amis d'un ami, puis les amis de ces amis, et ainsi de suite, en partant d'une personne donnée (le point de départ). Explique comment une file peut t'aider à explorer ce réseau par niveaux, garantissant que tu vois tous les amis proches avant de passer aux amis plus éloignés.
Barème indicatif : 2 points
Correction :
L'exploration par niveaux est exactement ce que le Parcours en Largeur (BFS - Breadth-First Search) fait, et une file est l'outil parfait pour cela.
Voici l'explication conceptuelle :
- Initialisation : Tu commences avec la personne de départ. Tu l'ajoutes à une file (c'est la première personne à "visiter") et tu la marques comme "visitée" pour ne pas la traiter plusieurs fois.
- Boucle d'exploration : Tant que la file n'est pas vide :
- Tu défiles une personne de la file (c'est la personne actuelle que tu explores).
- Tu regardes tous les amis de cette personne (ses voisins dans le réseau).
- Pour chaque ami :
- Si cet ami n'a pas encore été visité, tu l'ajoutes à la file (pour le visiter plus tard) et tu le marques comme "visitée".
- Résultat : En utilisant une file, tu t'assures que toutes les personnes à distance 1 (amis directs) sont ajoutées à la file et traitées avant que tu ne commences à traiter les personnes à distance 2 (amis d'amis), et ainsi de suite. Cela garantit un parcours "par couches" ou "par niveaux".
Résultat : Explication claire de l'application d'une file pour le BFS.
Astuce : La file maintient l'ordre de découverte, ce qui est essentiel pour un parcours en largeur. Sans elle, tu pourrais te perdre dans une branche du réseau avant d'explorer les autres.
Exercice 9 : Inverser une Pile SANS Utiliser de Structure Auxiliaire (Sauf Récursion)
C'est un défi classique ! Écris un pseudo-code pour inverser une pile. Tu n'as pas le droit d'utiliser une autre pile, une file, ou un tableau/liste temporaire. La seule "structure" autorisée en plus de la pile elle-même est la pile d'appels de fonction (donc tu peux utiliser la récursion).
Tu devras créer deux fonctions récursives :
insérer_au_fond(pile, element): Qui insère un élément au fond de la pile.inverser_pile(pile): Qui utilise la première fonction pour inverser la pile.
Barème indicatif : 3 points
Correction :
Cet exercice est complexe car il faut penser de manière récursive à la fois pour insérer un élément au fond et pour inverser la pile.
FONCTION est_vide(pile): // Supposons cette fonction disponible // . FONCTION depiler(pile): // Supposons cette fonction disponible // . PROCEDURE empiler(pile, element): // Supposons cette fonction disponible // . PROCEDURE insérer_au_fond(pile, element_a_inserer): SI est_vide(pile) ALORS empiler(pile, element_a_inserer) SINON temp = depiler(pile) insérer_au_fond(pile, element_a_inserer) empiler(pile, temp) FIN SI FIN PROCEDURE PROCEDURE inverser_pile(pile): SI NON est_vide(pile) ALORS element_du_sommet = depiler(pile) inverser_pile(pile) // Inverser le reste de la pile insérer_au_fond(pile, element_du_sommet) // Mettre l'ancien sommet au fond FIN SI FIN PROCEDURE
Résultat : Pseudo-code récursif pour inverser une pile sans structure auxiliaire explicite.
Astuce : C'est un excellent exemple de la puissance de la récursion pour simuler des structures de données. La pile d'appels de fonctions agit comme une pile auxiliaire implicite.
Exercice 10 : Implémentation d'une Liste Doublement Chaînée
Décris en pseudo-code l'implémentation d'une liste doublement chaînée. Pour simplifier, tu te concentreras sur la structure des nœuds et la fonction d'insertion d'un élément à une position donnée (par exemple, après un nœud spécifique).
Un nœud doit contenir : une valeur, un pointeur vers le nœud précédent, et un pointeur vers le nœud suivant.
Barème indicatif : 3 points
Correction :
La liste doublement chaînée ajoute un pointeur "précédent" à chaque nœud, ce qui permet un parcours dans les deux sens et simplifie certaines opérations comme la suppression.
CLASSE Nœud: ATTRIBUT valeur ATTRIBUT précédent : Nœud (pointeur vers le Nœud précédent) ATTRIBUT suivant : Nœud (pointeur vers le Nœud suivant) CONSTRUCTEUR Nœud(valeur): CECI.valeur = valeur CECI.précédent = NULL CECI.suivant = NULL FIN CONSTRUCTEUR FIN CLASSE CLASSE ListeDoublementChaînée: ATTRIBUT tête : Nœud (premier Nœud de la liste) ATTRIBUT queue : Nœud (dernier Nœud de la liste) CONSTRUCTEUR ListeDoublementChaînée(): CECI.tête = NULL CECI.queue = NULL FIN CONSTRUCTEUR PROCEDURE insérer_après(nœud_existant, nouvelle_valeur): SI nœud_existant EST NULL ALORS AFFICHER "Erreur: Le nœud existant ne peut pas être NULL." RETOUR FIN SI nouveau_nœud = Nœud(nouvelle_valeur) nouveau_nœud.suivant = nœud_existant.suivant nouveau_nœud.précédent = nœud_existant SI nœud_existant.suivant EST NON_NULL ALORS nœud_existant.suivant.précédent = nouveau_nœud SINON // Si nœud_existant était la queue CECI.queue = nouveau_nœud FIN SI nœud_existant.suivant = nouveau_nœud FIN PROCEDURE // Pour l'exemple, ajoutons une fonction d'ajout en fin pour initialisation PROCEDURE ajouter_en_fin(valeur): nouveau_nœud = Nœud(valeur) SI CECI.tête EST NULL ALORS CECI.tête = nouveau_nœud CECI.queue = nouveau_nœud SINON CECI.queue.suivant = nouveau_nœud nouveau_nœud.précédent = CECI.queue CECI.queue = nouveau_nœud FIN SI FIN PROCEDURE FIN CLASSE
Résultat : Pseudo-code pour les structures de Nœud et Liste Doublement Chaînée avec une fonction d'insertion après un nœud.
Point méthode : L'ajout ou la suppression dans une liste doublement chaînée implique de manipuler deux pointeurs (précédent et suivant) pour chaque nœud impacté, ce qui peut être un peu plus délicat que pour une liste simple. Attention aux cas limites : insertion en début, en fin, et sur une liste vide.
Comment ORBITECH Peut T'aider
ORBITECH AI Academy met à ta disposition des outils concrets pour réviser plus efficacement et progresser à ton rythme.
- Générateur de Quiz : crée des quiz personnalisés pour tester tes connaissances et identifier tes lacunes.
- Générateur d'Exercices : crée des exercices d'entraînement adaptés à ton niveau avec corrections détaillées.
- Générateur de Résumés : transforme tes cours en fiches de révision claires et structurées.
- Générateur de Mind Maps : visualise et organise tes idées avec des cartes mentales générées automatiquement.
Tous ces outils sont disponibles sur ta plateforme ORBITECH. Connecte-toi et explore ceux qui correspondent le mieux à tes besoins !
Commencer gratuitement