• Aucun résultat trouvé

EXERCICE RÉCAPITULATIF SUR LES LISTES

Dans le document Td corrigé LE LANGAGE C - Td corrigé pdf (Page 137-144)

Exercice 8.3 : écrire un programme de gestion d'une liste chaînée (LIFO) constituée de plusieurs tableaux de flottants

6.6 EXERCICE RÉCAPITULATIF SUR LES LISTES

s o m m e t in f o i in f o i - 1 in f o i - 2

b a s e i n f o 1

Structure de Pile

Il existe des piles matérielles et des piles logicielles. Une pile matérielle est un circuit qui gère automatiquement le pointeur de pile. L'avantage est une grande rapidité dans l'utilisation, l'inconvénient est sa taille limitée. Cette structure, qui a attiré les concepteurs des premiers microprocesseurs, est maintenant délaissée. Une pile logicielle est une zone réservée de la mémoire vive dont l'adresse en mémoire est décidée par le programmeur. Les dépassements sont possibles en cas d'erreur de programmation.

6.5.6 Opérations sur les piles

Les opérations de manipulation d'une pile sont l'empilement dont l'instruction est PUSH (pousse ou dépose), le dépilement supérieur dont l'instruction est POP (prends ou retire), le dépilement inférieur dont l'instruction est POPD pour déposer ou retirer un des éléments sur le sommet ou sur la base de la pile permettant l'accès à la dernière ou la première information de la pile.

s o m m e t . . . . . . . . b a s e

P U S H P O P

P U S H

s o m m e t . . . . . . . . b a s e

P O P

Dépilement supérieur Dépilement inférieur

6.6 EXERCICE RÉCAPITULATIF SUR LES LISTES

Nous allons étudier une méthode de tri par chaînage. Il s'agit, à partir d'une liste de noms saisis dans un ordre quelconque, de constituer une liste chaînée d'indices permettant de faire un

i n f o ( i - 1 ) p o i n t e u r ( i ) i n f o ( i ) p o i n t e u r ( i + 1 ) i n f o ( i + 1 ) p o i n t e u r ( i + 2 ) Soit le tableau liste, de N structures, chacune composée de deux champs :

 la chaîne de caractères nom contiendra le nom saisi,

 l'entier tsuc, contiendra l'indice, dans le tableau liste, du successeur (dans l'ordre alphabétique) du nom précédemment saisi, avec les conventions suivantes :

liste [0 ].tsuc pointe sur le premier nom, dans l'ordre alphabétique, de la liste,

liste [i ].tsuc = k, indice du successeur de liste [i].nom, dans l'ordre alphabétique, si k ¹0, liste [i ].tsuc = 0, si le i-ème nom saisi n'a pas de successeur dans l'ordre alphabétique.

Toute nouvelle saisie va modifier deux enregistrements du tableau liste. Soit les tableaux : i-ème nom saisi liste [i ].nom liste [i].tsuc

0 2 premier nom de la liste

1 DUPOND 3, successeur de DUPOND

2 ALBERT 1, successeur de ALBERT

3 MARTIN 0 n'a pas de successeur

L'introduction du nom ALAIN va modifier le tableau liste[].tsuc selon le chaînage suivant : i-ème nom saisi liste [i ].nom liste [i ].tsuc

0 4

1 DUPOND 3

2 ALBERT 1

3 MARTIN 0

4 ALAIN 2

L'algorithme de création de la liste chaînée, pour déterminer la valeur du prédécesseur et du successeur du nom saisi, est le suivant.

Notations

Soient j et pred les indices respectifs du candidat successeur et du candidat prédécesseur du i-ème nom saisi.

Au départ :

pred = 0; j:= liste [0 ].tsuc

Le premier candidat prédécesseur est initialisé à 0. Il est comparé au prédécesseur du premier nom classé dans l'ordre alphabétique. Il y a deux possibilités :

liste [i ].nom s'intercale dans la liste Dans ce cas :

$ j0 tel que liste [pred ].nom < liste [i ].nom  liste [j0 ].nom et

liste [pred ].tsuc = i;

liste [i ].tsuc = j0;

liste [i ].nom ne s'intercale pas dans la liste.

C'est donc le (nouveau) dernier élément de la liste, dans l'ordre alphabétique. Il n'aura pas de successeur. Soit j0 l'indice du dernier nom par ordre alphabétique de la liste avant l'insertion du nouveau nom dans la liste.

Représentation graphique

Soit Li la liste de noms à l'étape i, alors Li = Li-1 È liste [i ].nom Li-1 liste [i ].tsuc Li

n1 p1 n1

... ...

... È ... =

... ...

ni-1 pi-1 ni-1

ni

Evolution du tableau liste.tsuc

Voyons l'évolution du tableau liste [].tsuc dans les deux cas.

Premier cas : le nom s'intercale dans la liste.

En utilisant les relations cidessus, on obtient :

Li-1 liste[].tsuc Li liste[].tsuc

0 0

n1 p1 n1 p1 inchangé

... ... ... ...

nk j0 nk i

... ...

ni-1 pi-1 ni-1 pi-1

ni j0

Avant Après

Deuxième cas : le nom ne s'intercale pas dans la liste : On a la représentation suivante :

Li-1 liste[].tsuc Li liste[].tsuc

0 0

n1 p1 n1 p1 inchangé

... ... ... ...

nj0 0 nj0 i

... ... ...

ni-1 pi-1 ni-1 pi-1

ni 0

Avant Après

liste [j0 ].tsuc = 0

liste [j ].nom < liste [j0 ].nom pour tout j = 1,... , i-1 Après l'insertion, on a les relations :

liste [i ].tsuc = 0 = liste [j0 ].tsuc liste [j0 ].tsuc = i

Arrêt du calcul

cas 1 : dès qu'il existe j0 tel que liste [i ].nom > liste [j ].nom cas 2 : dès que j0= 0

Algorithme

L'algorithme se décompose en deux phases : Phase 1

Recherche de la position

 Initialisation de la recherche : pred := 0; j := liste[0].tsuc

 Recherche effective

 Arrêt de la recherche : deux possibilités :

dès qu'on a déterminé j0 tel que liste [j0 ].nom ³ liste [j ].nom > liste [pred ].nom ou dès que j = 0 ce qui implique que ni n'a pas de successeur.

La négation de ces deux conditions s'écrit : j ¹ 0 ou liste[j].nom < liste[i].nom Phase 2

Modification des deux champs à modifier de liste[].tsuc par les formules : liste[i].tsuc := j

liste[pred].tsuc := i

Ces formules sont valables dans les deux cas ce qui simplifie l'écriture de l'algorithme.

Programme Initialisation

lire N, dimension du tableau liste liste[i].tsuc = 0, pour tout i= 0,N liste[i].NOM = "" pour tout i = 1,N i := 1

Tant que(i < N et liste [i].nom ¹"") faire saisir liste [i ].nom;

pred := 0; j := liste [0 ].tsuc; & initialisation &

Recherche

Tant que (j ¹ 0 et (liste [j ].nom < liste [i ].nom)) faire

pred := j; & j : nouveau candidat prédécesseur &

j := liste [j ].tsuc; & nouveau candidat successeur &

fin_faire liste [i ].tsuc := j; liste [pred ].tsuc = i;

& modification de liste [ ].tsuc fin_faire

Le tri alphabétique est trivial.

j = liste [0 ].tsuc;

Tant que (j ¹ 0) faire imprimer liste [j ].nom;

j = liste [j ].tsuc;

fin_faire

Programmation

La fonction saisie saisit au clavier la liste des individus et la stocke dans un fichier.

La fonction lire permet, à partir du fichier des individus, créer le tableau des successeurs. La comparaison de deux chaînes de caractères est réalisée par la fonction st qui retourne, à partir de la fonction de la librairie C strcmp (prototype dans string.h) , un nombre entier, utilisable dans le test de fin de recherche.

La fonction tri réalise le tri alphabétique.

Version tableau

#include <stdio.h>

#include <string.h>

#define MAX 20 /* nombre maximum de noms */

#define ever (;;) /* boucle de saisie */

typedef struct {char nom [20 ]; int tsuc;} pers;

void main(void)

{int i,k; pers liste [MAX ];

/* prototypes */

void saisie(void), tri(pers [ ]);

int lire(pers [ ]);

saisie(); /* saisie de la liste dans un fichier */

k = lire(liste); /* constitution du tableau des successeurs*/

printf ("liste non triée et indice du successeur\n");

for(i=0;i<k;i++) printf("%d%-30.30s%d\n",i,liste [i ].nom, liste [i ].tsuc);

tri(liste);

}

void saisie(void) /* saisie des données */

fp=fopen("personnel","a");

for ever

{printf("Donnez le nom : ");

gets (accueil.nom);

if (!strlen(accueil.nom)) break;

/* fin de saisie */

fwrite( (char *) & accueil, sizeof(accueil),1,fp);

fflush(fp); /* vidage du tampon après chaque saisie */

accueil=vide; /* réinitialisation entre deux saisies*/

}

fclose(fp); /* fermeture du fichier */

}

int lire(pers liste [ ]) /* remplissage de la structure liste et constitution du tableau tsuc */

{FILE *fp;

pers accueil;

/* initialisation */

int i , pred , j;

int st(char *, char *); /* fonction de comparaison de deux chaînes*/

liste [0 ].tsuc = 0; i = 1;

fp=fopen("personnel","r");

while (fread ((char*) &accueil, sizeof(accueil),1,fp))

/* chargement d'un enregistrement de longueur sizeof(accueil) du fichier */

/* dontl'étiquette logique est fp dans le champ mémoire accueil*/

{liste [i ] = accueil; /* affectation de structure */

/* initialisation de la recherche */

pred = 0; j = liste [0 ].tsuc;

while (j!=0 && st(liste [j ].nom, liste [i ].nom)) { pred = j; j = liste [j ].tsuc; } /* modification du champ tsuc */

liste [i ].tsuc = j;

liste [pred ].tsuc = i;

i++; /* enregistrement suivant */

}

fclose(fp);

return(i);

}

int st(char *s, char *t) /* comparaison de deux chaîne de caractères */

{int ret;

ret = strcmp(s,t);

if (ret == 0) return(-1);

if (ret<0) return(1); else return(0);

}

void tri(pers liste [ ]) {int j = liste [0 ].tsuc;

printf("\n\ntri par ordre alphabétique\n");

while(j)

{printf(" %s\n",liste [j ].nom);

j = liste [j ].tsuc;

} }

// résultat

Donnez le nom :

liste non triée et indice du successeur 0 12

1 PHILIPPE 4 2 LUIS 1

3 ALBERTY 10 4 PHILIPPE 11 5 ALBERT 8 6 JULES 2

7 JEAN-LOUIS 6 8 ALBERTA 3 9 HUBERT 7 10 ALBERTINE 9 11 ADELE 5

tri par ordre alphabétique ADELE

ALBERT ALBERTA ALBERTY ALBERTINE HUBERT JEAN-LOUIS JULES

LUIS PHILIPPE PHILIPPE

Dans le document Td corrigé LE LANGAGE C - Td corrigé pdf (Page 137-144)