Isup 1 - Programmation TD no8 Matthieu Journault 19 juin 2020
Exercice 1 : Tableau dynamique
Dans cet exercice, il vous est demand´e d’implanter une structure de donn´ees permettant de stocker des entiers. Cette structure appel´ee tableau dynamique est repr´esent´ee par une structure C contenant 3 champs : un pointeur sur un tableau contenant les entiers ; un entier indiquant le nombre d’´el´ement stock´e dans le tableau et enfin un entier indiquant la taille allou´ee du tableau. Il est en effet possible que le tableau contienne moins d’´el´ement que sa taille allou´e. Lorsqu’un ´el´ement est ajout´e `a la collection :
— si le tableau est plein (le nombre d’´el´ements stock´es et la taille allou´ee sont les mˆemes), on alloue (avec malloc) un tableau deux fois plus grand, on recopie notre tableau dans le nouveau, on ajoute l’´el´ement dans le nouveau tableau puis on lib`ere l’ancien tableau.
— si le tableau n’est pas plein, on peut ajouter l’´el´ement dans le tableau existant.
Q. 1 D´efinir un type structur´e dynarray contenant : un pointeur content vers un tableau d’entier allou´e dans le tas, un entier size repr´esentant le nombre d’´el´ements dans la structure, un entier alloc repr´esentant la taille allou´ee pour le tableau content.
Q. 2D´efinir une fonctiondynarray empty();renvoyant un tableau vide.
Q. 3 D´efinir une fonction void print_dynarray(dynarray tab); permettant un affichage ´ecran du tableau pass´e en argument.
Q. 4D´efinir une fonction int is_in(dynarray tab, int e);permettant de tester l’appartenance de l’´el´ement e au tableau dynamique tab.
Q. 5 D´efinir une fonction void add(dynarray tab, int e); permettant l’ajout d’un ´el´ement `a la structure.
Q. 6D´efinir une fonctionvoid remove(dynarray tab, int e);permettant la suppression d’un ´el´ement de la structure.
Q. 7Pour la fonction main suivante : dynarray d = empty();
add(d, 0);
add(d, 1);
add(d, 2);
add(d, 3); /* 1 */
add(d, 4); /* 3 */
Repr´esenter l’´evolution de la m´emoire aux points 1, 2, 3 en supposant que le point 2 se trouve au milieu de votre fonctionadd, apr`es que le contenu du nouveau tableau a ´et´e rempli avec le contenu de l’ancien.
Exercice 2 : Listes chaˆın´ ees
Une liste est une structure de donn´ees qui repr´esente une collection de valeurs. L’un des int´erˆet des listes par rapport `a un tableau est qu’il est ais´e de supprimer ou ajouter des nouveaux ´el´ements entre les ´el´ements d´ej`a pr´esents dans la liste, ainsi que le fait que la taille d’une liste n’est pas strictement d´efinie `a sa cr´eation (et qu’elle peut donc changer au fil de l’ex´ecution du programme).
Le type d’une liste (simplement) chaˆın´ee qui contient des valeurs enti`eres peut ˆetre d´efini comme suit :
struct _int_list { int value;
struct _int_list* next;
};
Dans la suite, le type liste int sera un alias d’un pointeur vers unstruct int list : struct _int_list {
int value;
struct _int_list* next;
};
Chaque ´el´ement d’une liste simplement chaˆın´ee contient une valeur, et un pointeur vers la suite de la liste (i.e. l’´el´ement suivant).
Q. 8 Impl´ementer une fonction int_list push(int value, int_list list); qui permet d’ajouter un nouveau noeud dans une liste : L’astuce pour cr´eer une liste r´eduire `a un seul ´el´ement d’utiliser liste int liste = ajout debut(34,NULL) pour cr´eer une liste qui contient juste la valeur 34.
Q. 9Impl´ementer une fonction int_list empty();retournant la liste vide.
Q. 10 Impl´ementer une fonction int is_empty(int_list l); permettant de tester si une liste est vide.
Q. 11Afin de faciliter la manipulation des listes dans la suite d´efinir des macros :
— Cons(X, L) permettant de construire une liste ayant comme premi`ere valeur X et comme liste suivante X;
— Empty permettant de construire la liste vide ;
— Head(L) permettant de r´ecup´erer la valeur de l’´el´ement en tˆete de liste
— Tail(L) permettant de r´ecup´erer la sous liste des ´el´ements qui suive l’´el´ement en tˆete.
Q. 12Impl´ementer une version r´ecursive et une version it´erative de la fonctionvoid print_list(int_list list);
permettant l’affichage de la liste. Utiliser cette fonction et les macros d´efinies ci-avant pour v´erifier que vos fonctions fonctionnent.
Q. 13Impl´ementer une version r´ecursive et une version it´erative de la fonctionvoid free_list(int_list list);
permettant de lib´erer l’espace occup´e par la liste pass´ee en argument.
Q. 14 Impl´ementer une fonction r´ecursive int size_list(int_list list); calculant la taille d’une liste.
Q. 15Impl´ementer une fonctionint remove_index(int_list list, int i); permettant de suppri- mer l’´el´ement d’indice i de la liste list.
Q. 16On vous donne les trois fonctions suivantes calculant la concat´enation de deux listes.
int_list concatenation1(int_list l1, int_list l2) { if (is_empty(l1)) {return l2;}
else {
int_list ptr;
for (ptr = l1; ptr->next != NULL; ptr=ptr->next) {}
ptr->next = l2;
return l1;
} }
int_list concatenation2(int_list l1, int_list l2) { if (is_empty(l1) && is_empty(l2)) {return Empty;}
else if (is_empty(l1)) {return l2;}
else { return Cons(Head(l1), concatenation2(Tail(l1), l2)); } }
int_list concatenation3(int_list l1, int_list l2) { if (is_empty(l1) && is_empty(l2)) {return Empty;}
else if (is_empty(l1)) {return Cons(Head(l2), concatenation3(l1, Tail(l2)));}
else { return Cons(Head(l1), concatenation3(Tail(l1), l2)); } }
Pour chacune des trois fonctions donner une repr´esentation de la m´emoire au point de programme /* 1 */ en supposant que la fonction main soit la suivante :
int main() {
int_list l1 = Cons(1, Empty) ; int_list l2 = Cons(2, Empty) ;
int_list l = concatenation(l1, l2); /* 1 */
}
Q. 17D´efinir une fonction int_list reverse(int_list list); imp´erative inversant une liste.
Q. 18 D´efinir une fonction int_list rev_append(int_list list, int_list acc) r´ecursive retour- nant une copie du renversement de la listlist concat´en´e `a la liste acc.
Q. 19 En d´eduire une fonction int_list reverse2(int_list list) retournant une copie renvers´ee de la list list.
Exercice 3 : Tri fusion
Le tri fusion est un algorithme de tri fonctionnement r´ecursivement de la mani`ere suivante : Pour trier une liste de n´el´ements :
— s´eparer la liste en deux sous listes de mˆeme taille (`a 1 pr`es) ;
— trier r´ecursivement les deux sous listes ;
— fusionner intelligemment les deux sous listes ainsi tri´ees.
Ce que l’on entend par une fusion intelligente est : ´etant donn´e deux listes tri´ees on fusionne en produisant une liste tri´ee contenant tous les ´el´ements des deux sous listes. Une telle fusion peut ˆetre implant´ee assez facilement r´ecursivement en regardant uniquement les ´el´ements en tˆete des deux listes.
Q. 20Implanter une fonctionint_list split(int_list list);modifiant en place la listelistpour que celle-ci ne contienne plus qu’un ´el´ement sur deux de la liste list initial et retournant un pointeur vers une liste contenant les ´el´ements manquants.
Q. 21 Implanter une fonction int_list merge(int_list l1, int_list l2); prenant en argument deux listesl1 et l2 que vous supposerez tri´ees et modifiant ces deux listes en places pour produire une liste tri´ee contenant les ´el´ements de l1 etl2. Indication : proposer une d´efinition r´ecursive.
Q. 22En d´eduire une fonctionint_list sort(int_list l);triant une liste au moyen de l’algorithme de tri fusion propos´e ci-avant.
Exercice 4 : Listes doublement chaˆın´ ees
Nous avons vu qu’il ´etait difficile d’acc´eder aux derniers ´el´ements d’une liste chaˆın´ee (n´ecessit´e de parcourir toute la liste). Ceci peut ˆetre ennuyeux lorsqu’on aimerait avoir acc`es `a la fois au d´ebut et `a la fin d’une liste (par exemple pour repr´esenter une file d’attente o`u les gens entrent d’un cˆot´e et sortent de l’autre).
Dans cet exercice nous d´efinissons une nouvelle structure de donn´ee, les listes doublement chaˆın´ees permettant un acc`es `a la fois aux ´el´ements en tˆete et en fin de liste.
Une liste doublement chain´ees sera donc un pointeur vers une structure contenant : head un pointeur vers la tˆete de la liste ;
tail un pointeur vers la fin de la liste ;
De plus afin de faciliter la manipulation de la liste (par exemple, la suppression du dernier ´el´ement) il est important de garder en m´emoire l’´el´ement pr´ec´edant le dernier ´el´ement de la liste (sous peine d’avoir
`
a reparcourir toute la liste pour devoir trouver le nouveau dernier ´el´ement). Ainsi en plus de l’usuel pointeur vers le prochain ´el´ement de la liste nous devons garder un m´emoire pour chaque ´el´ement, un pointeur vers l’´el´ement le pr´ec´edant dans la liste. Ainsi chaque composante de notre liste aura :
elem un entier ;
prev un pointeur vers l’´el´ement de la liste qui le pr´ec`ede.
next un pointeur vers l’´el´ement de la liste qui le suit.
Ci-dessous une repr´esentation graphique d’une telle liste doublement chaˆın´ee contenant les ´el´ements 1,2,3 dans cet ordre.
0 NULL
elem prev next
1
elem prev next
2 NULL
elem prev next
head tail
Q. 23D´efinir la structurestruct dlistscontenant un entierelem, un pointeurprev vers unestruct dlists et un pointeur next vers unestruct dlists.
Q. 24 D´efinir le type dlist comme ´etant une structure contenant un pointeur head vers une struct dlist et un pointeur tail vers unestruct dlist.
Q. 25 D´efinir une fonction dlist empty(); renvoyant une dlist vide. La liste vide ne sera pas repr´esent´ee par un pointeur NULL mais par un pointeur vers une structure dont les deux champs head ettail sont des pointeurs NULL.
Q. 26D´efinir une fonction int is_empty(dlist dl); permettant de tester si une liste est vide.
Q. 27 D´efinir une fonction void print_dlist(dlist dl); permettant l’affichage de la liste pass´ee en argument.
Q. 28 D´efinir une fonction void push_head(int elem, dlist dl); permettant l’ajout en place d’un
´el´ement en tˆete de liste.
Q. 29D´efinir une fonctionint pop_head(int elem, dlist dl); permettant la suppression en place d’un ´el´ement en tˆete de liste, on retournera l’´el´ement ainsi supprim´e.
Q. 30 D´efinir une fonction void push_tail(int elem, dlist dl); permettant l’ajout en place d’un
´el´ement en fin de liste.
Q. 31D´efinir une fonctionint pop_tail(int elem, dlist dl); permettant la suppression en place d’un ´el´ement en fin de liste, on retournera l’´el´ement ainsi supprim´e.
Q. 32 D´efinir une fonctionvoid reverse(dlist dl);permettant de renverser en place la liste pass´ee en argument.
Q. 33D´efinir une fonctionvoid rem(dlist dl, int e); permettant la suppression de la valeur e de la listedl, on pourra supposer que e apparaˆıt au plus une fois dans dl.