Algorithmique
Structures de donnes
Florent Hivert
Ml : Florent.Hivert@lri.fr Page personnelle : http://www.lri.fr/hivert
2 de 52
La plupart des bons algorithmes fonctionnent grce une mthode astucieuse pour organiser les donnes. Nous allons tudier quatre grandes classes de structures de donnes : Les structures de donnes squentielles (tableaux) ; Les structures de donnes linaires (liste chanes) ; Les arbres ; Les graphes.
3 de 52
4 de 52
Dnition
Un tableau est une structure de donne T qui permet de stocker un certain nombre dlments T [i] reprs par un index i. Les tableaux vrient gnralement les proprits suivantes : tous les lments ont le mme type de base ; le nombre dlments stocks est x ; laccs et la modication de llment numro i est en temps constant (1), indpendant de i et du nombre dlments dans le tableau.
5 de 52
Tableau en C
On suppose dclar un type elem pour les lments. Espace mmoire ncessaire au stockage dun lment exprim en mots mmoire (octets en gnral) : sizeof(elem). dnition statique : elem t[taille]; dnition dynamique en deux temps (dclaration, allocation) : #include <stdlib.h> elem *t; ... t = (elem*) malloc(taille*sizeof(elem)); ladresse de t[i] est not t + i. Calcule par Addr(t[i]) = Addr(t[0]) + sizeof(elem) i
6 de 52
Oprations de base
Hypothses : tableau de taille max_taille allou lments 0 i < taille max_taille initialiss
7 de 52
On essaye dinsrer un lment dans un tableau o taille = max_taille Il ny a plus de place disponible. Comportements possibles : Erreur (arrt du programme, exception) R-allocation du tableau avec recopie, cot : (taille)
8 de 52
R-allocation (2)
Problme : On ajoute 1 par 1 n lments. On suppose que lon ralloue une case supplmentaire chaque dbordement. Cot (nombre de copies dlments) :
n
i=
i=1
n(n + 1) (n2 ) 2
n b
bi = b
i=1
k(k + 1) (n2 ) 2
9 de 52
C =n+
i=1
Ki = n +
Km 1 (n + K m ) K 1
10 de 52
C =n+
i=1
Ki = n +
n K Km 1 n+ =n K 1 K 1 K 1
Quelques valeurs : K
K K 1
Interprtation : Si lon augmente la taille de 10% chaque tape, chaque nombre sera recopi en moyenne 11 fois. Si lon double la taille chaque tape, chaque nombre sera en moyenne recopi deux fois.
11 de 52
Bilan
Retenir (Nombre de copies)
Dans un tableau de taille n, cot de lajout dun lment dans le pire des cas : Cot en temps n, Cot en espace (K 1)n .
En, moyenne sur un grand nombre dlments ajouts : Cot en temps K , K 1 Cot en espace K .
On dit que lalgorithme travaille en temps constant amortis (Constant Amortized Time (CAT) en anglais).
12 de 52
Compromis Espace/Temps
Quand K augmente, la vitesse augmente mais la place mmoire gaspille ( (K 1)n) augmente aussi. Le choix de la valeur de K dpend donc du besoin de vitesse par rapport au cot de la mmoire.
Retenir
Cest une situation trs classique : dans de nombreux problmes, il est possible daller plus vite en utilisant plus de mmoire. Exemple : on vite de faire plusieurs fois les mme calculs en stockant le rsultat.
13 de 52
En pratique . . .
On utilise void *realloc(void *ptr, size_t size); Extrait des sources du langage Python Fichier listobject.c, ligne 41-91 :
/* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
14 de 52
15 de 52
Retenir
Une variable dynamique est anonyme : (adresse, type, valeur) . On y accde grce un pointeur. Un pointeur p qui repre (ou pointe vers) une VD dadresse a et de type T est de type T (lire che T ) ; a pour valeur ladresse a de la VD.
16 de 52
T a v T
x le lien dynamique entre le pointeur p et la VD quil repre est illustr par une che p
T T v
17 de 52
laccs aucune VD pour le pointeur p de type T est illustr par une croix
T p
NULL est une valeur commune tous les pointeurs, ceux du type T comme ceux des autres types.
18 de 52
La taille dun pointeur est xe lors de la compilation, elle ne dpend pas du type T . Cest la principale limitation quand la mmoire disponible dans une machine. 32 bits, espace adressable 4 Gio (gibioctets) 109 . 64 bits, espace adressable 16 Eio (exbioctets) 1018 .
19 de 52
Retenir
Durant lexcution du programme, laction dallocation allouer(p) provoque :
1
la cration dune nouvelle VD de type T et de valeur indtermine, par rservation dune nouvelle zone de mmoire ; laectation p de ladresse de cette VD.
T p ? T
== = ===
allouer(p)
20 de 52
Utilisations
Retenir
Si p repre une VD, cette variable est note p.
T la VD de type T et de valeur v repre par p est note p p p v T
Toutes les oprations licites sur les variables et les valeurs de type T sont licites sur la variable p et la valeur p.
21 de 52
Retenir
Si le pointeur p repre une VD, laction de dsallocation explicite dsallouer(p) met n lexistence de la VD p et rend disponible lespace mmoire quelle occupait. Aprs laction de dsallocation, la valeur de p est indtermine.
T p v T T p
== = = ====
dsallouer(p)
22 de 52
== = ===
allouer(p)
Sil nexiste pas dautre pointeur dessus, la mmoire de la VD en rouge est perdue ! Note : certain langage (Java, Python, . . .) utilise un composant particulier appel ramasse miettes (Garbage Collector en anglais) pour rcuprer la mmoire ainsi perdue.
23 de 52
== = = ====
T
dsallouer(p)
24 de 52
Variable dynamique en C
Retenir
Dclaration dun pointeur p de type T : T *p; Allocation dune VD pointe par p : p = (T *) malloc(sizeof(T)) ; note : en cas dchec de lallocation malloc retourne NULL. Accs la VD et sa valeur : *p = ...; ... = (*p) + 1; Dsallocation de la VD pointe par p : free(p);
25 de 52
Les pointeurs en C
Retenir
Tout type de pointeur supporte lopration daectation = peux tre utilis comme type de retour dune fonction Note : ajout dun pointeur un entier (en cas de variable dynamique multiple ; tableau) Pour deux pointeurs de mme type : test dgalit ==, de dirence != Note : comparaison <,<=,>,>= (en cas de variable dynamique multiple ; tableau)
26 de 52
Le programme : char *p, *q p = (char *) malloc(sizeof(char)); *p = A; q = (char *) malloc(sizeof(char)); *q = B; *p = *q; printf("%i, %i\n", p == q, *p == *q); ache : 0, 1
27 de 52
28 de 52
type structur
Il est souvent pratique de regrouper logiquement plusieurs variables en une seule variable compose. On parle alors de structure ou denregistrement.
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 direntes variables vi sont appeles champs de v elles sont repres par un identicateur de champ si v est une variable de type structur T possdant le champ ch, alors la variable v .ch est une variable comme les autres : (type, adresse, valeur)
29 de 52
Syntaxe
Dclaration de type structur : nom_de_type = structure: nom_du_champ_1 : type_du_champ_1; nom_du_champ_2 : type_du_champ_2; ... Dclaration de variable structure : v: nom_de_type;
30 de 52
31 de 52
struct s_date { char nom_jour[9]; // lundi, mardi, ..., dimanche int num_jour; // 1, 2, ..., 31 int mois; // 1, 2, ..., 12 int annee; } struct s_date date = {"vendredi", 21, 10, 2011};
32 de 52
Retenir
Toute opration valide sur une variable de type type_du_champ_i est valide sur v.nom_du_champ_i. De plus, laectation v = w est valide. Elle est quivalente aux aectations v.nom_du_champ_1 = w.nom_du_champ_1 v.nom_du_champ_2 = w.nom_du_champ_2 ...
33 de 52
34 de 52
Ide
35 de 52
Chanages dynamiques
a1
a2
a3
Dans le schma, trois types sont distinguer : le type des lments de la suite : le type des pointeurs : le type des lments de la liste dynamique, composition des deux types prcdents :
36 de 52
Retenir
Une liste chane est obtenue partir du type cellule dnie par cellule = structure: val: element next : ^cellule liste = ^cellule
En C : struct s_cell { element val; struct s_cell * next; }; typedef struct s_cell cell; // Cellule typedef struct s_cell *list; // Liste Chane
37 de 52
Pointeur et structure
Syntaxe
Accs aux donnes dune liste chane : VD pointe par lst : champ val de cell : *lst cell.val
38 de 52
On a : p = NULL ; p val = a1 ; p next = NULL ; p next val = a2 ; p next next = NULL ; p next next val = a3 ; p next next next = NULL. Soit, en convenant de noter f p p rptitions de loprateur f : p( next)k1 = NULL, pour 1 k 3 ; p( next)k1 val = ak , pour 1 k 3 ; p( next)3 = NULL.
39 de 52
40 de 52
Les notions sur les suites nies passent aux listes dynamiques quelles implantent : longueur, concatnation, position... Calcul itratif :
int longueur(list lst) { int k = 0; list q = lst; while (q != NULL) { q = q->next; k++; } return k; }
Calcul rcursif :
int longueur(list lst) { if (lst == NULL) return 0; else return 1 + longueur(lst->next); }
41 de 52
list insertion_en_tete(element x, list lst) { list res = alloue_cellule(); res->val = x; res->next = lst; return res; }
42 de 52
la n
void insertion_en_tete(element x, list *plst) { list tmp = alloue_cellule(); tmp->val = x; tmp->next = *plst; *plst = tmp; }
43 de 52
list insertion_en_queue(element x, list lst) { list res = alloue_cellule(); if (lst == NULL) { res->val = x; res->next = NULL; return res; } else { res->val = lst->val; res->next = insertion_en_queue(x, lst->next); return res } }
44 de 52
void insertion_en_queue(element x, list *plst) { list tmp = alloue_cellule(); tmp->val = x; tmp->next = NULL; if (*plst == NULL) *plst = tmp; else { list cur = *plst; while (cur->next != null) cur = cur->next; cur->next = tmp; } }
45 de 52
le pointeur p repre la LDSC avec une fausse tte qui implante la suite a1 , a2 , . . . , an
lst
a1 ?
a2
an
Intrts : en mode avec mutation ; vite davoir distinguer les cas de llment de tte ou de la liste vide dans les oprations dinsertion et de suppression.
46 de 52
a1
a2
an
Intrts : en mode avec mutation ; ajout en queue sans parcours de la LDSC ; concatnation sans parcours des LDSC. dnir, aprs la dclaration du type Liste, par : struct s_list_tq { struct s_cell *first, *last; }
47 de 52
an
Intrts : en mode avec mutation ; ajout en queue et suppression en tte sans parcours de la LDSC ; concatnation sans parcours des LDSC.
48 de 52
a1
a2
an
Intrts : en mode avec mutation ; marches avant et arrire ; ajout en queue et suppression en tte sans parcours de la LDDC ; concatnation sans parcours des LDDC.
49 de 52
50 de 52
Applications
Implantation des types de donnes abstraits : piles (dernier entr - premier sorti) les dattente (premier entr - premier sorti) double-queues ensembles, tables dassociations Algorithmes de retour sur trace, essais/erreurs (backtracking)
51 de 52
choix dun candidat avec suppression dans la liste (chaque candidat ne peux tre choisi quune seul fois) retour en arrire par re-insertion du candidat sa place pour choisir un autre candidat
52 de 52
Suppression de b de la liste
a choix
Le pointeur choix contient toute linformation ncessaire pour revenir la position de dpart ; il sut de faire :
choix->next->prev = choix; choix->prev->next = choix;