DS 5 — Listes chaînées¶
MP2I, année scolaire 2022-2023, devoir surveillé du 11 mars 2023. Durée totale 4h.
Tout document interdit. Tout dispositif électronique interdit.
On vous demande d'écrire lisiblement et de bien présenter. Les programmes en particulier doivent être bien indentés et lisibles. Utilisez de préférence plusieurs couleurs. Commentez votre code dès que ce qu'il fait n'est pas évident.
L'introduction et l'utilisation de fonctions auxiliaires est autorisée, et même encouragée, d'autant plus si cela améliore la lisibilité et la compréhension. Les fonctions auxiliaires doivent être précédées de leur type (en OCaml) et commentées.
Lorsque l'on pose des hypothèses sur les arguments, il n'est pas nécessaire dans vos fonctions de le vérifier ni de prévoir le comportement si l'hypothèse est violée.
De nombreuses questions comportent une sous-question sur la complexité. On prendra garde à ne pas lire trop vite l'énoncé et à ne pas ainsi oublier de répondre à une partie de la question.
Le sujet comporte un premier exercice de reprise du cours et un problème découpé en plusieurs parties relativement indépendantes.
Attention : on rédigera chaque partie sur des copies séparées pour bien différencier les numéros des questions.
I. A link to a past TP¶
On va reprendre le type des listes chaînées en C :
struct maillon {
int valeur;
struct maillon *suivant;
};
typedef struct maillon maillon;
struct liste {
maillon *debut;
maillon *fin;
};
typedef struct liste liste;
- Dans un maillon, soit
suivantpointe vers le maillon suivant de la chaîne ou vautNULL. - La liste vide aura la valeur
NULLpourdebutetfin. - Dans une liste non vide,
debutpointe sur le premier maillon etfinsur le dernier.
On suppose définies des fonctions
// cree un maillon
maillon *creer_maillon(int valeur, maillon *suivant);
// supprime un maillon
void suppr_maillon(maillon *);
// cree une liste vide
liste *creer_liste(void);
// supprime une liste
void suppr_liste(liste *);
Q.1 Écrire une fonction de prototype
int longueur(liste *);
qui renvoie la longueur d'une liste.
Corrigé
int longueur(liste *l)
{
int n = 0;
maillon *m = l->debut;
while (m != NULL)
{
n++;
m = m->suivant;
}
return n;
}
Q.2 Écrire une fonction de prototype
int somme(liste *);
qui renvoie la somme des valeurs des éléments d'une liste.
Corrigé
int somme(liste *l)
{
int s = 0;
maillon *m = l->debut;
while (m != NULL)
{
s = s + m->valeur;
m = m->suivant;
}
return s;
}
Q.3 Écrire une fonction de prototype
void liste_ajout_en_tete(liste *l, int valeur);
qui ajoute un maillon en tête de la liste passée en paramètre en \(O(1)\).
On fera attention au cas où la liste est vide.
Corrigé
void liste_ajout_en_tete(liste *l, int valeur)
{
l->debut = creer_maillon(valeur, l->debut);
if (l->fin == NULL)
l->fin = l->debut;
}
Q.4 Écrire une fonction de prototype
maillon *liste_cherche_maillon(liste *l, int valeur);
qui renvoie un pointeur sur le premier maillon de valeur valeur
ou renvoie NULL s'il n'y en a pas.
Corrigé
maillon *liste_cherche_maillon(liste *l, int valeur)
{
maillon *m = l->debut;
while (m != NULL && m->valeur != valeur)
{
m = m->suivant;
}
return m;
}
Q.5 Expliquer comment cette structure permet d'implémenter une pile et donner les différentes complexités des opérations de la structure liste.
Corrigé
L'ajout et la suppression en tête sont en \(O(1)\), on s'en sert donc respectivement pour les opérations push et pop.