Partie 03 - Université de M`sila

publicité
Programmation et structures de données
1MI
TYPE STRUCTURÉ
Il est souvent pratique de regrouper logiquement plusieurs variablesen une seule variable
composée. On parle alors de structure oud’enregistrement.
Retenir
• Un type enregistrement ou type structuré est un type T de variable v obtenu en
juxtaposant plusieurs variables v1; v2; … ayant chacune un type T1;T2; …
• les différentes variables vi sont appelées champs de v elles sont repérées par un
identificateur de champ
• si v est une variable de type structuré T possédant le champch, alors la variable v:ch
est une variable comme les autres :(type, adresse, valeur)
Les structures permettent de rassembler des valeurs de type différent. Par exemple, pour
uneadresse, on a besoin du numéro (int) et du nom de la rue (char).
1. Déclaration
En algorithmique
En langage C
nom_de_type= structure:
nom_du_champ_1 :
type_du_champ_1;
nom_du_champ_2 :
type_du_champ_2;
...
Déclaration de variable
structurée :
v: nom_de_type;
structnom_de_struct {
nom_du_champ_1 : type_du_champ_1;
nom_du_champ_2 : type_du_champ_2;
...
};
Déclaration de variable structurée :
structnom_de_struct v;
Ou avec une définition de type :
typedefstructnom_de_structnom_type;
nom_type v;
Chaque élément déclaré à l’intérieur de la structure est appelé un champ. Le nom donné à la
structure est appelé étiquette de structure. Ici, on a en fait déclaré un type de structure, pas
une variable.
On déclare les variables associées à une structure de cette manière :
struct adresse chez_pierre ,chez_julie ;
Car si la structure d’une adresse est toujours la même (numéro et nom de la rue),
chez_pierreetchez_julie, qui sont des structadressedifférentes, n’habitent pas au même
endroit.
On peut initialiser une structure lors de sa déclaration :
struct adresse chez_pierre={ 15 , "rue_Dugommier" } ;
Exemple de déclaration de type structuré
typedef structs_date {
charnom_jour[9]; // lundi, mardi, ..., dimanche
intnum_jour; // 1, 2, ..., 31
int mois; // 1, 2, ..., 12
intannee;
}
16
Programmation et structures de données
1MI
typedef structs_date date = {"vendredi", 21, 10, 2011};
2. Manipulation
On accède aux données contenues dans les champs d’une structure et faisant suivre le nom de
la
strucure par un point "." et le nom du champ voulu :
chez_julie.numero=19 ;
strcpy(chez_julie.rue,"avenue Pasteur") ;
Si 2 structures ont le même type, on peut effectuer :
chez_pierre=chez_julie ; /* Pierre a emménagé chez Julie ! */
Mais on ne peut pas comparer 2 structures (avec == ou !=).
Rem :
On suppose déclarées des variables v;w d’un type structuré.
On dispose donc de variablesv.nom_du_champ_ide type type_du_champ_i
Toute opération valide sur une variable de type type_du_champ_iest valide sur
v.nom_du_champ_i.
De plus, l’affectation v = w est valide. Elle est équivalente auxaffectations :
v.nom_du_champ_1 = w.nom_du_champ_1
v.nom_du_champ_2 = w.nom_du_champ_2
……….
3. Tableau de structure
On déclare un tableau de structure de la même façon qu’un tableau de variables simples : le
nombre d’éléments est précisé entre crochets.
struct adresse pers[100] ;
Cette déclaration nécessite que la structure adresseait déjà été déclarée avant. persest alors un
tableau dont chaque élément est une structure de type adresse. Et pers[i].ruefait référence au
champ "rue" de la iemepersonne de la structure pers.
Exemple
#include<stdio.h>
typedef struct point
{
double abs;
double ord;
};
intmain()
{
point p[10];
int i;
p[0].ord = 0;
p[0].abs = 1;
for(i = 1 ; i < 10 ; i++)
{ p[i].ord = p[i - 1].ord + 1.;
p[i].abs = p[i - 1].abs + 2.; }
for(i = 0 ; i < 10 ; i++)
{ printf("p[%d] = (%f, %f)\n", i, p[i].abs, p[i].ord); }
}
17
Programmation et structures de données
1MI
4. Structure de structure
On peut utiliser une structure comme champ d’une autre structure. Dans la lignée des
exemples précédents, on peut définir une structure adressequi pourra être utilisée dans la
structure repertoire.
Elle peut également être utilisée dans une autre structure.
typedef struct adresse {
intnumero ;
char rue[50] ; } ;
structrepertoire {
char nom[20] ;
char prenom[20] ;
struct adresse maison ; } ; /* déclaration d’un champ structure */
/* de type ’adresse’ appelé ’maison’ */
structrepertoiremonrepertoire[100] ;
strcpy(monrepertoire[0].nom,"Cordier") ;
strcpy(monrepertoire[0].prenom,"Julie") ;
monrepertoire[0].maison.numero = 19 ;
strcpy(monrepertoire[0].maison.rue,"avenue_Pasteur") ;
strcpy(monrepertoire[1].nom,"Durand") ;
strcpy(monrepertoire[1].prenom,"Pierre") ;
monrepertoire[1].maison.numero = 15 ;
strcpy(monrepertoire[1].maison.rue,"rue_Dugommier") ;
Lorsqu’un tableau fait partie des champs d’une structure, on peut accéder aux valeurs de ce
tableau
par :
char initiale ;
initiale=monrepertoire[1].prenom[0] ; /* initiale de Pierre */
18
Programmation et structures de données
1MI
Les listes chaînées
1. Définition
Une liste chaînée est une structure linéaire qui n'a pas de dimension fixée à sa création. Ses
éléments de même type sont éparpillés dans la mémoire et reliés entre eux par des pointeurs.
Sa dimension peut être modifiée selon la place disponible en mémoire. La liste est accessible
uniquement par sa tête de liste c’est-à-dire son premier élément.
Pour les listes chaînées la séquence est mise en œuvre par le pointeur porté par chaque
élément qui indique l'emplacement de l'élément suivant. Le dernier élément de la liste ne
pointe sur rien (Nil).
On accède à un élément de la liste en parcourant les éléments grâce à leurs pointeurs.
Chaque élément de la liste contient :
- des informations sur l’élément
- un pointeur sur un autre élément de la liste, ou un pointeur NULL s’il n’y a pas d’élément
suivant.
2. Représentation en mémoire d’une liste
Soit la liste chaînée suivante (@ indique que le nombre qui le suit représente une adresse) :
Adresses
Données
@:3
@ : 24
@:8
@ : 31
Voici
une
liste
chainée
Pointeurs
24
8
31
Nil
En allocation dynamique, les emplacements mémoires sont dispersés en mémoire centrale.
L’espace est réservé au fur et à mesure des créations des éléments de la liste. La seule limite
étant la taille de la mémoire centrale.
Pour accéder au troisième élément de la liste il faut toujours débuter la lecture de la liste par
son premier élément dans le pointeur duquel est indiqué la position du deuxième élément.
Dans le pointeur du deuxième élément de la liste on trouve la position du troisième élément…
Pour ajouter, supprimer ou déplacer un élément il suffit d'allouer une place en mémoire et de
mettre à jour les pointeurs des éléments.
Il existe différents type de listes chainées :
Il existe différents types de listes chaînées :
• listes simplement chainées (comme ci-dessus) constituée d'éléments reliés entre eux
par des pointeurs.
• Liste chaînée ordonnée où l'élément suivant est plus grand que le précédent.
L'insertion et la suppression d'élément se font de façon à ce que la liste reste triée.
• Liste doublement chaînée où chaque élément dispose non plus d'un mais de deux
pointeurs pointant respectivement sur l'élément précédent et l'élément suivant. Ceci
permet de lire la liste dans les deux sens, du premier vers le dernier élément ou
inversement.
• Liste circulaire où le dernier élément pointe sur le premier élément de la liste. S'il
s'agit d'une liste doublement chaînée alors de premier élément pointe également sur le
dernier.
• Les piles
19
Programmation et structures de données
1MI
• Les files
3.listes simplement chainées
Une liste chaînée simple est composée :
d'un ensemble d'éléments tel que chacun :
• est rangé en mémoire à une certaine adresse,
• contient une donnée (Info),
• contient un pointeur, souvent nommé Suivant, qui contient l'adresse de
l'élémentsuivant dans la liste,
d'une variable, appelée Tête, contenant l'adresse du premier élément de la liste chaînée.
Le pointeur du dernier élément contient la valeur Nil. Dans le cas d'une liste vide le pointeur
de latête contient la valeur Nil. Une liste est définie par l'adresse de son premier élément.
Exemple :
er
Le 1 élément de la liste vaut 12 à l'adresse 3 (début de la liste chaînée)
eme
Le 2 élément de la liste vaut 14 à l'adresse 4 (car le pointeur de la cellule d’adresse 3 est
égal à 4)
eme
Le 3 élément de la liste vaut 10 à l'adresse 2 (car le pointeur de la cellule d’adresse 4 est
égal à 2)
Le 4e élément de la liste vaut 24 à l'adresse 1 (car le pointeur de la cellule d’adresse 2 est égal
à 1)
Si P a pour valeur 3 Si P a pour valeur 2
P^.Info a pour valeur 12P^.Info a pour valeur 10
P^.Suivant a pour valeur 4 P^.Suivant a pour valeur 1
3.1. Traitements de base d'utilisation d'une liste chaînée simple
Il faut commencer par définir un type de variable pour chaque élément de la chaîne. En
langagealgorithmique ceci se fait comme suit :
Type Element = Structure
valeur : entier
Suivant : Element
Fin structure
Type Liste = ^Element
Variables Tete, P : Liste
Typedefstructelement {
Intvaleur;
element *Suivant;
};
typedef element *Liste;
int main()
{
ListeTete,P;
}
20
Programmation et structures de données
1MI
Les traitements des listes sont les suivants :
Créer une liste.
Ajouter un élément.
Supprimer un élément.
Modifier un élément.
Parcourir une liste.
Rechercher une valeur dans une liste.
4.LES PILES
La pile est une structure de données, qui permet de stocker les données dans l’ordre LIFO
(Last In First Out = Dernier Entré Premier Sorti). L’insertion des données se fait donc
toujours au début de la liste(sommet de la pile) (i.e. par le haut de la pile), donc le premier
élément de la liste est le dernier élément inséré, sa position est donc en haut de la pile.
Pour permettre les opérations sur la pile, nous allons sauvegarder certains éléments Le
premier élément de la pile, qui se trouve en haut de la pile, va nous permettre de réaliser
l'opération de récupération des données situées en haut de la pile.
Pour réaliser cela, une autre structure sera utilisée (ce n'est pas obligatoire, des variables
peuvent êtreutilisées). Voici sa composition :
typedefstruct pile {
Element *debut;
int taille;
};
typefedstruct pile Pile ;
Le pointeur début contiendra l'adresse du premier élément de la liste. La variable taille
contient le nombre d'éléments.
21
Programmation et structures de données
1MI
Quatre opérations abstraites sont dé_nies sur le type Pile :
empiler : Pile X E →Pile
depiler : Pile →Pile
sommet : Pile →E
est- vide? : Pile →booleen
Le rôle de l'opération empiler est d'ajouter un élément en sommet de pile, celui de dpiler de
supprimer
le sommet de pile et celui de sommet de renvoyer l'élément en sommet de pile. En_n,
l'opérationest - vide? indique si une pile est vide ou pas.
5. LES FILES
La File diffère de la Pile dans sa façon de gérer les données. En effet, la file permet de stocker
les données dans l’ordre FIFO (First In First Out = Premier Entré Premier Sorti). L’insertion
des données se fait aussi par en haut de la File, mais la sortie ne se faut plus par le haut
comme pour la Pile mais par le bas.
Pour manipuler une File, nous sauvegardons son premier élément, son dernier élément ainsi
que sa taille (nombre d’éléments qu’elle contient).
Pour réaliser cela, une autre structure sera utilisée (ce n'est pas obligatoire, des variables
peuvent être utilisées). Voici sa composition :
typedefstructfile{
Element *debut;
Element *fin;
int taille;
};
typefedstruct file File ;
Le pointeur début contiendra l'adresse du premier élément de la liste.
Le pointeur fin contiendra l'adresse du dernier élément de la liste. La variable taille contient le
nombre d'éléments.
22
Programmation et structures de données
1MI
Quatre opérations sont dé_nies sur le type File :
enfiler : File X E →File
defiler : File →File
dernier : File →E
est- vide? : File →booleen
L’Opération enfiler a pour rôle d'ajouter un élément en queue de file, et l'opération defiler
supprimel'élément en tête de file. dernier retourne le dernier élément de la file et estvide?indique si une file estvide ou pas. Notez que les signatures de ces opérations sont, au
mot «File» près, identiques à celles desopérations du type abstrait Pile. Ce sont bien les
axiomes qui vont différencier ces deux types abstrait
6. Manipulation des listes, Piles et files
6.1.Initialisation
Nous pouvons modéliser un nœud de la liste liée en utilisant une structure comme Suit:
typedef struct node {
int val;
struct node * next;
} node_t;
La structure de nœud comporte deux membres:
• Les données qui stockent les informations
• Un pointeur suivant qui contient l'adresse du prochain noeud.
Notez que nous définissons la structure de manière récursive, ce qui est possible dans C.
Désignons notre type de nœud node_t.
Maintenant, nous pouvons utiliser les nœuds. Créons une variable locale qui pointe vers le
premier élément de la liste (appelé tête ou Head (sommet)).
node_t * head = NULL;
head = (node_t*) malloc (sizeof (node_t));
if (head == NULL) {
return 1;
}
head->val = 0;
head->next = NULL;
nous pouvons mettre dans le champ val du noeud head la taille de la liste (nombre d’éléments)
6.2.Ajouter un nœud à la fin de la liste chainée
Pour itérer sur tous les membres de la liste chainée, nous utilisons un pointeur appelé current.
Nous l'établissons pour commencer à partir de la tête, puis à chaque étape, nous avançons le
pointeur vers l'élément suivant dans la liste, jusqu'à l’arrivée au dernier élément.
void push_fin (node_t *head, int val)
{
node_t *current = head;
while (current->next != NULL) {
current = current->next;
}
/* Nous ajoutons un nouveau élément */
current->next = (node_t*)malloc(sizeof(node_t));
current->next->val = val;
current->next->next = NULL;
23
Programmation et structures de données
head->val=head->val+1; /* On ajoute 1 à la taile de la liste*/
}
Ajouter un nœud au début de la liste
void push_debut (node_t *head, int val) {
node_t *new_node;
new_node = (node_t*)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = head->next;
head->next = new_node;
head->val=head->val+1; /* On ajoute 1 à la taile de la liste*/
}
Suppression du dernier nœud de la liste
int remove_last (node_t * head)
{
/* le cas d'un seul élément dans la liste */
if (head->next == NULL)
return 0;
/* aller vers le dernier élément */
node_t * current = head;
while (current->next->next != NULL) {
current = current->next;
}
/* on pointe sur le dernier élément*/
free(current->next);
current->next = NULL;
head->val=head->val-1; /*On change la taille de la liste par -1*/
return 0;
}
Suppression du premier nœud de la liste
int Pop(node_t* head)
{
if(head->next == NULL)
return 0;
node_t *front = head->next;
head->next = head->next->next;
front->next = NULL;
/* is this the last node in the list */
if(front == head)
head = NULL;
free(front);
head->val=head->val-1; /*On change la taille de la liste par -1*/
return 0;
}
24
1MI
Programmation et structures de données
Supprimer un nœud spécifique (par son valeur par exemple)
int remove_by_val(node_t *head,int valeur){
node_t *current =head;
node_t *temp_node=NULL;
while (current->next!=NULL)
{
if (current->next->val==valeur)
{
temp_node= current;
current->next =temp_node->next->next;
}
current= current->next;
}
return 0;
}
Imprimer la liste
void print_list(node_t *head)
{
node_t * current = head->next;
if (head->next==NULL)
printf("il n'ya aucun noeud dans la liste \n");
else{
printf("la liste contient %d elements \n",head->val);
while (current != NULL) {
printf("%d\n", current->val);
current = current->next;}
}
}
25
1MI
Programmation et structures de données
Programme de test global:
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
int val;
struct node * next;
} node_t;
/*Ajout à la fin*/
void push_fin (node_t *head, int val)
{
node_t *current = head;
while (current->next != NULL) {
current = current->next;
}
/* Nous ajoutons un nouveau élément */
current->next = (node_t*)malloc(sizeof(node_t));
current->next->val = val;
current->next->next = NULL;
head->val=head->val+1;
}
/*Ajout au début*/
void push_debut (node_t *head, int val) {
node_t *new_node;
new_node = (node_t*)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = head->next;
head->next = new_node;
head->val=head->val+1;
}
/*Suppression du dernier élément*/
int remove_last (node_t * head)
{
/* le cas d'un seul élément dans la liste */
if (head->next == NULL)
return 0;
/* aller vers le dernier élément */
node_t * current = head;
while (current->next->next != NULL) {
current = current->next;
}
/* on pointe sur le dernier élément*/
free(current->next);
current->next = NULL;
26
1MI
Programmation et structures de données
head->val=head->val-1;
return 0;
}
/*Suppression du premier élément*/
int Pop(node_t* head)
{
if(head->next == NULL)
return 0;
node_t *front = head->next;
head->next = head->next->next;
front->next = NULL;
/* is this the last node in the list */
if(front == head)
head = NULL;
free(front);
head->val=head->val-1;
return 0;
}
int remove_by_val(node_t *head,int valeur){
node_t *current =head;
node_t *temp_node=NULL;
while (current->next!=NULL)
{
if (current->next->val==valeur)
{
temp_node= current;
current->next =temp_node->next->next;
}
current= current->next;
}
return 0;
}
void print_list(node_t *head)
{
node_t * current = head->next;
if (head->next==NULL)
printf("il n'ya aucun noeud dans la liste \n");
else{
printf("la liste contient %d elements \n",head->val);
while (current != NULL) {
printf("%d\n", current->val);
current = current->next;}
}
}
int main()
{
27
1MI
Programmation et structures de données
node_t * head = NULL;
head = (node_t*) malloc (sizeof (node_t));
head->val = 0;
head->next = NULL;
push_fin(head,3);
print_list(head);
printf("****************** \n");
push_fin(head,9);
print_list(head);
printf("****************** \n");
push_fin(head,10);
print_list(head);
printf("****************** \n");
push_debut(head,8);
print_list(head);
printf("****************** \n");
push_debut(head,15);
print_list(head);
printf("****************** \n");
remove_by_val(head,9);
print_list(head);
printf("****************** \n");
Pop(head);
print_list(head);
printf("****************** \n");
Pop(head);
print_list(head);
printf("****************** \n");
Pop(head);
print_list(head);
printf("****************** \n");
Pop(head);
print_list(head);
printf("****************** \n");
Pop(head);
print_list(head);
}
28
1MI
Résultats d’exécution du programme
la liste contient 1 elements
3
******************
la liste contient 2 elements
3
9
******************
la liste contient 3 elements
3
9
10
******************
la liste contient 4 elements
8
3
9
10
******************
la liste contient 5 elements
15
8
3
9
10
******************
la liste contient 5 elements
15
8
3
10
******************
la liste contient 4 elements
8
3
10
******************
la liste contient 3 elements
3
10
******************
la liste contient 2 elements
10
******************
il n'ya aucun noeud dans la liste
******************
il n'ya aucun noeud dans la liste
Téléchargement