• Aucun résultat trouvé

Solutions du cahier d’exercices Structures de données et algorithmes GPA665

N/A
N/A
Protected

Academic year: 2022

Partager "Solutions du cahier d’exercices Structures de données et algorithmes GPA665"

Copied!
8
0
0

Texte intégral

(1)

École de technologie supérieure

Département de génie de la production automatisée

GPA665

Structures de données et algorithmes Solutions du cahier d’exercices

Série d’exercices no. 3 : Les listes élémentaires (les listes chaînées)

Session : Automne 2002 Responsable du cours : Mohamed Cheriet, ing., Ph. D.

Locaux : Cours : 3740 Chargé de cours : Jean-Christophe Demers

Laboratoire : 3324 Chargé de laboratoire : Nicolas Morency

(2)

Le programme montré pour cet exercice est incomplet, donc ne compile pas. En fait, vous devez le considérer comme du pseudo-code. Par exemple la fonction new n’est pas définit en langage C (mais elle existe en langage C++). Voici le code de ce programme corrigé :

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#define maxname 8

#define maxfamily 100

typedef struct { char Name[maxname];

int age;

} Person;

void NewPerson(Person** P);

void main(void) {

int i;

Person *personptr, *family[maxfamily];

NewPerson(&personptr);

personptr->age = 25; strcpy(personptr->Name, "Fred ");

for (i = 0; i < maxname; i++) printf("%c", personptr->Name[i]);

printf("\test age de \t%d\n", personptr->age);

family[10] = personptr;

for (i = 0; i < maxname; i++) printf("%c", personptr->Name[i]);

printf("\test age de \t%d\n", personptr->age);

}

void NewPerson(Person** P) {

*P = (Person*)malloc(sizeof(Person));

}

La sortie de ce programme est :

Fred ??? est âgé de 25 Fred ??? est âgé de 25

(3)

Fonction qui compte le nombre de noeuds dans une liste chaînée.

int count(node *head) {

node* current = head;

int n = 0;

while (current != NULL) { n++;

current = current->next;

}

return n;

}

Exercice 3

Fonction qui libère toute la mémoire allouée pour une liste chaînée. Voici deux exemples différents pour une même fonction.

Premier exemple :

void FreeLinkedList1(node *head) {

node *First = head, *Temp;

while (First != NULL) { Temp = First;

First = First->next;

free(Temp);

} }

Deuxième exemple :

void FreeLinkedList2(node **head) {

node *Temp;

while (*head != NULL) { Temp = *head;

*head = (*head)->next;

free(Temp);

} }

L’avantage du deuxième exemple est qu’après l’exécution de la fonction le pointeur head

vaut nul. Ainsi, cette méthode aide à ne pas faire d’accès mémoire incorrect.

(4)

Fonction qui copie entièrement une liste chaînée dans une autre.

void CopyLinkedList(node *HeadSource, node** HeadTarget) {

node *CurrentSource = HeadSource;

node *CurrentTarget;

/* S'assure qu'il y ait au moins 1 élément */

if (HeadSource == NULL) { *HeadTarget = NULL;

} else {

/* Affectation du premier noeud de la liste chaîné */

CurrentTarget = (node*)malloc(sizeof(node));

CurrentTarget->data = CurrentSource->data;

*HeadTarget = CurrentTarget;

CurrentSource = CurrentSource->next;

/* Affectation de tout les noeuds suivants */

while (CurrentSource != NULL) {

CurrentTarget->next = (node*)malloc(sizeof(node));

CurrentTarget->next->data = CurrentSource->data;

CurrentSource = CurrentSource->next;

CurrentTarget = CurrentTarget->next;

}

CurrentTarget->next = NULL;

} }

(5)

Fonction qui copie le contenu d’une liste chaînée en ordre inverse. Voici deux exemples différents pour cette fonction.

Premier exemple :

void CopyBackward1(node *HeadSource, node** HeadTarget) {

if (HeadSource != NULL) {

CopyBackward1(HeadSource->next, HeadTarget);

InsertLast(HeadTarget, HeadSource->data);

} }

void InsertLast(node** Head, int Data) {

node *Cur = *Head, *New = (node*)malloc(sizeof(node));

New->data = Data;

New->next = NULL;

if (*Head == NULL) { *Head = New;

} else {

while (Cur->next != NULL) Cur = Cur->next;

Cur->next = New;

} }

Deuxième exemple :

void CopyBackward2(node *HeadSource, node** HeadTarget) {

static node* LastTargetNode = *HeadTarget;

if (HeadSource != NULL) {

CopyBackward2(HeadSource->next, HeadTarget);

if (LastTargetNode == NULL) {

*HeadTarget = (node*)malloc(sizeof(node));

(*HeadTarget)->data = HeadSource->data;

(*HeadTarget)->next = NULL;

LastTargetNode = *HeadTarget;

} else {

LastTargetNode->next = (node*)malloc(sizeof(node));

LastTargetNode->next->data = HeadSource->data;

LastTargetNode->next->next = NULL;

LastTargetNode = LastTargetNode->next;

} } }

Le premier exemple possède le désavantage important de parcourir toute la nouvelle liste

lors de chaque insertion. Le deuxième exemple parcours la nouvelle liste chaînée en

utilisant habilement une variable static qui permet d’identifier le dernier noeud de la

nouvelle liste pour chaque nouvelle insertion.

(6)

Fonction déterminant si deux listes chaînées circulaires sont identique en considérant les duplications interdites. On suppose une liste chaînée circulaire ordonnée avec un pointeur de liste pointant sur le dernier élément.

int IsEqual1(node *L1, node *L2) {

node *Cur1 = L1, *Cur2 = L2;

int Equal = 1;

do {

Cur1 = Cur1->Next;

Cur2 = Cur2->Next;

if (Cur1 && Cur2 && (Cur1->data == Cur2->data) &&

((Cur1->data != Cur1->next->data) || (Cur1 == Cur1->next))) Equal = 0;

} while (Equal && (Cur1 != L1));

if (Equal && (Cur2 == L2)) return 1; /* EQUAL */

else

return 0; /* NOT EQUAL OR DUPLICATE */

}

Exercice 6b

Fonction déterminant si deux listes chaînées circulaires sont identique en considérant les duplications interdites. On suppose une liste chaînée circulaire ordonnée avec un pointeur de liste pointant sur le dernier élément.

int IsEqual2(node *L1, node *L2) {

node *Cur1 = L1, *Cur2 = L2;

int Equal = 1;

do {

Cur1 = Cur1->Next;

Cur2 = Cur2->Next;

if (Cur1 && Cur2 && (Cur1->data == Cur2->data)) Equal = 0;

} while (Equal && (Cur1 != L1));

if (Equal && (Cur2 == L2)) return 1; /* EQUAL */

else

return 0; /* NOT EQUAL */

}

(7)

Pour l’implantation d’une chaîne de caractères sous forme de liste chaînée, on suppose que :

• chaque noeud possède un char pour chaque caractère;

• la fin de la liste chaînée (pointant vers nul) indique la fin de la chaîne de caractères (ainsi, le caractère \0 n’est plus utilisé pour indiquer la fin de la chaîne de caractères).

Voici la déclaration du type utilisé :

typedef struct _LinkedListStringNode { char Character;

_LinkedListStringNode *Next;

} LinkedListStringNode;

La fonction de concaténation peut être utilisée à l’aide de la fonction qui a été définie au numéro 4 (CopyLinkedList). Évidemment, les types de données ne concordent pas (node* et LinkedListStringNode*). Mais il suffit d’adapter ce nouveau type à la même logique et la fonction est utilisable.

void StringConcatenation(

LinkedListStringNode **StringSource, LinkedListStringNode *StringToConcatenate) {

LinkedListStringNode* CurSource = *StringSource;

if (CurSource == NULL) {

CopyLinkedList(StringToConcatenate, StringSource);

} else {

while (CurSource->next != NULL) { CurSource = CurSource->next;

}

CopyLinkedList(StringToConcatenate, &(CurSource->next));

} }

La fonction de calcul de la longueur est :

int StringLength(LinkedListStringNode* HeadString) {

LinkedListStringNode* Current = HeadString;

int n = 0;

while (Current != NULL) { n++;

Current = Current->next;

}

return n;

}

(8)

chaque insertion on incrémente cette variable et à chaque suppression on décrémente la variable. Une technique élégante et pratique pour implanter une telle technique consiste à définir une structure d’entête contenant à la fois le pointeur de tête mais aussi le nombre de caractère. Voici la déclaration d’un tel type de donnée :

typedef struct {

_LinkedListStringNode *Head;

int Length;

} LinkedListString;

Exercice 8

Références

Documents relatifs

- Être mieux en soi pour être mieux dans ses relations avec les autres et dans son travail Durée : 2 jours soit 14 heures.

Returns the index in this list of the first occurrence of the specified element, or -1 if the List does not contain this element. Retourner l’indice de la première occurence

Cet algorithme de calcul de reste euclidien peut être justifié par la propriété ci-dessus : Que la réponse soit 2 veut dire que 2015=3n+2, et dans ce cas, 2015-3=3(n-1)+2 : On

FICHIERS FICHIERS Mémoire de masse découpée en blocs Fichier : liste chaînée de blocs, ou.. arbre de blocs (répertoires

N’oubliez pas que la fonction d’initialisation (ou de création) est une fonction permettant de démarrer à vide (sans aucun élément) votre TDA afin qu’elle soit cohérente avec

cases 1 et 2 du tableau Result (la somme dans la case 1 et la moyenne dans la case 2). On calcule l’écart type des données contenues dans le tableau Data et on la met dans

Même si ce n’est pas une erreur, il faut faire attention à cette ligne de code puisque ce n’est pas une comparaison d’égalité entre c et 2 qui est faite mais plutôt une

Le 30 mars 1872, elle est condamnée par le 4° conseil de guerre, à la déportation simple pour excitation à la guerre civile et pour provocation par discourt, cri ou menacer