Structures de Données Et Algorithmes: Nadi Tomeh Tomeh@
Structures de Données Et Algorithmes: Nadi Tomeh Tomeh@
Structures de Données Et Algorithmes: Nadi Tomeh Tomeh@
CM1
Nadi Tomeh
[email protected]
Licence 2 Informatique
Institut Galilée, Université Sorbonne Paris Nord
15 octobre 2020
Point administratif
2. Récursivité
5. Pile et File
Introduction 10
Algorithmes
Introduction 11
Algorithmes
Introduction 12
Exemple : le tri
Le problème de tri :
I Entrée : une séquence de n nombres ha1 , a2 , . . . , an i
I Sortie : une permutation de la séquence de départ ha10 , a20 , . . . , an0 i
telle que a10 ≤ a20 ≤ . . . ≤ an0
Exemple :
I Entrée : h31, 41, 59, 26, 41, 58i
I Sortie : h26, 31, 41, 41, 58, 59i
Introduction 13
Tri par insertion
Introduction 14
Tri par insertion
Insertion Sort
5 2 4 6 1 3
2 5 4 6 1 3
2 4 5 6 1 3
2 4 5 6 1 3
1 2 4 5 6 3
1 2 3 4 5 6
Introduction 16
Insertion sort
Insertion-Sort(A)
1 for j = 2 to A.length
2 key = A[j]
3 // Insert A[j] into the sorted sequence A[1 . . j − 1].
4 i = j −1
5 while i > 0 and A[i] > key
6 A[i + 1] = A[i]
7 i = i −1
8 A[i + 1] = key
Introduction 17
Pseudo-code
Objectifs :
Décrire les algorithmes de manière à ce qu’ils soient compris par des
humains.
Introduction 18
Pseudo-code
Quelques règles
Structures de blocs indiquées par l’indentation
Boucles (for, while, repeat ) et conditions (if, else, elseif) comme
en C.
Le compteur de boucle garde sa valeur à la sortie de la boucle
En sortie d’un for, le compteur a la valeur de la borne max+1.
i =1
for i = 1 to Max while i ≤ Max
⇔
Code Code
i = i +1
Commentaires indiqués par //
Affectation (=) et test d’égalité (==) comme en C.
Introduction 19
Pseudo-code
Introduction 20
Trois questions récurrentes face à un algorithme
Insertion-Sort(A)
1 for j = 2 to A.length
2 key = A[j]
3 i = j −1
4 while i > 0 and A[i] > key
5 A[i + 1] = A[i]
6 i = i −1
7 A[i + 1] = key
Introduction 24
Complexité de Insertion-Sort
n(n − 1)
T (n) ≤
2
Finalement, T (n) = O(n2 )
(borne inférieure ?)
Introduction 25
Structures de données
Introduction 26
Types de données abstraits
Introduction 27
Exemple : file à priorités
Données gérées : des objets avec comme attributs :
I une clé, munie d’un opérateur de comparaison selon un ordre total
I une valeur quelconque
Opérations :
I Création d’une file vide
I Insert(S, x) : insère l’élément x dans la file S.
I Extract-Max(S) : retire et renvoie l’élément de S avec la clé la
plus grande.
Introduction 28
Structures de données et algorithmes en pratique
La résolution de problème algorithmiques requiert presque toujours
la combinaison de structures de données et d’algorithmes
sophistiqués pour la gestion et la recherche dans ces structures.
D’autant plus vrai qu’on a à traiter des volumes de données
importants.
Quelques exemples de problèmes réels :
I Routage dans les réseaux informatiques
I Moteurs de recherche
I Alignement de séquences ADN en bio-informatique
Introduction 29
Un exemple (B. Boigelot)
Première approche :
I Un indice i variant de 2 à N − M + 1
I Un indice j variant de 1 à i − 1
I Pour tout k ∈ [0, . . . , M − 1], on teste si S[i + k] = S[j + k].
Efficacité : le nombre de comparaisons à effectuer est égal à :
M(N − M + 1)(N − M)
M · (1 + 2 + . . . + (N − M)) =
2
≈ 4, 5.1021 pour N = 3 · 109 et M = 1000
≈ 143.000 ans au rythme de 109 opérations/s.
Introduction 30
Une meilleure solution
1. On construit une table à N − M + 1 lignes et M colonnes dont la
k-ème ligne contient la sous-séquence de longueur M commençant à
la position k dans S :
ACTG
CTGC
TGCG
GCGA
CGAC
..
.
2. On trie les lignes de cette table par ordre lexicographique ;
3. On parcourt la table triée afin de déterminer si elle contient deux
lignes consécutives identiques
Introduction 31
Efficacité
Construction de la table : M(N − M + 1) opérations de copie.
Tri par ordre lexicographique (algorithme de tri rapide, voir partie
3) :
8
≤ N ln N opérations de comparaison en moyenne
3
Détection de lignes consécutives :
4
≤ (N − M) opérations de comparaison en moyenne
3
En supposant des coûts identiques pour toutes les opérations, on obtient :
8 4 1
N(M + ln N + ) − M(M + )
3 3 3
≈ 3, 179.10 opérations pour N = 3.109 et M = 1000.
12
Introduction 32
Remarques
Introduction 33
Plan
2. Récursivité
5. Pile et File
Factorial(n)
1 if n == 0
2 return 1
3 return n · Factorial(n − 1)
Introduction 35
Algorithmes récursifs
Factorial(n)
1 if n == 0
2 return 1
3 return n · Factorial(n − 1)
Introduction 36
Exemple de récursion multiple
F0 = 0
F1 = 1
∀n ≥ 2 : Fn = Fn−2 + Fn−1
Algorithme :
Fibonacci(n)
1 if n ≤ 1
2 return n
3 return Fibonacci(n − 2) + Fibonacci(n − 1)
Introduction 37
Exemple de récursion multiple
Fibonacci(n)
1 if n ≤ 1
2 return n
3 return Fibonacci(n − 2) + Fibonacci(n − 1)
Introduction 38
Exemple de récursion multiple
Fibonacci(n)
1 if n ≤ 1
2 return n
3 return Fibonacci(n − 2) + Fibonacci(n − 1)
Introduction 39
Vitesse d’exécution
Nombre d’opérations pour calculer Fibonacci(n) en fonction de n
Results
Empiriquement :
60
Ruby
Python
50 Scheme
C
Time (seconds)
40 C-wiz
Java
C-gcc
30
20
10
0
20 25 30 35 40 45 50
n
© 2006 (Carzaniga)
Antonio Carzaniga
Trace d’exécution :
fibonacci1(k)
fibonacci1(k 2) fibonacci1(k 1)
(Boigelot)
p
1+ 5
Temps de calcul : O('n), où ' = .
2
Preuve ?
Introduction 32 41
Complexité
Fibonacci(n)
1 if n ≤ 1
2 return n
3 return Fibonacci(n − 2) + Fibonacci(n − 1)
T (0) = 2, T (1) = 2
T (n) = T (n − 1) + T (n − 2) + 2
Introduction 42
Complexité
Comment croı̂t Fn avec n ?
T (n) ≥ Fn = Fn−1 + Fn−2
Puisque Fn ≥ Fn−1 ≥ Fn−2 ≥ . . ., on a :
√
n ( 2)n
Fn ≥ 2Fn−2 ≥ 2(2Fn−4 ) ≥ 2(2(2Fn−6 )) ≥ 2 2 −1 F2 =
2
si n ≥ 2 est pair et
√ √
n−1 ( 2)n ( 2)n
Fn ≥ 2Fn−2 ≥ 2(2Fn−4 ) ≥ 2(2(2Fn−6 )) ≥ 2 2 F1 = √ ≥
2 2
si n ≥ 1 est impair.
Et donc √
( 2)n (1.4)n
T (n) ≥ ≈
2 2
T (n) croı̂t exponentiellement avec n
Fibonacci-Iter(n)
1 if n ≤ 1
2 return n
3 else
4 pprev = 0
5 prev = 1
6 for i = 2 to n
7 f = prev + pprev
8 pprev = prev
9 prev = f
10 return f
Introduction 44
Vitesse d’exécution
Complexité : O(n) Results
60
Ruby
Python
50 Scheme
C
Time (seconds)
40 C-wiz
Java
C-gcc
30 PythonSmart
20
10
0
0 20 40 60 80 100
n
© 2006 (Carzaniga)
Antonio Carzaniga
Introduction 45
Tri par fusion
Idée d’un tri basé sur la récursion :
on sépare le tableau en deux sous-tableaux de la même taille
on trie (récursivement) chacun des sous-tableaux
on fusionne les deux sous-tableaux triés en maintenant l’ordre
Le cas de base correspond à un tableau d’un seul élément.
merge-sort(A, p, r )
1 if p < r
2 q = b p+r
2 c
3 merge-sort(A, p, q)
4 merge-sort(A, q + 1, r )
5 merge(A, p, q, r )
merge
2 4 5 7 1 2 3 6
merge
2 5 4 7 1 3 2 6
merge
5 2 4 7 1 3 2 6
1 2 3 4 5 6 7 8
initial array
Introduction
[Examples when n is a power of 2 are most stra
47
Fonction merge
Merge(A, p, q, r ) :
Entrée : tableau A et indice p, q, r tels que :
I p ≤ q < r (pas de tableaux vides)
I Les sous-tableaux A[p . . q] et A[q + 1 . . r ] sont ordonnés
Sortie : Les deux sous-tableaux sont fusionnés en un seul
sous-tableau ordonné dans A[p . . r ]
Idée :
Utiliser un pointeur vers le début de chacun des sous-tableaux ;
Déterminer le plus petit des deux éléments pointés ;
Déplacer cet élément vers le tableau fusionné ;
Avancer le pointeur correspondant
Introduction 48
Fusion : algorithme
Merge(A, p, q, r )
1 n1 = q − p + 1 ; n2 = r − q
2 Soit L[1..n1 + 1] et R[1..n2 + 1] deux nouveaux tableaux
3 for i = 1 to n1
4 L[i] = A[p + i − 1]
5 for j = 1 to n2
6 R[j] = A[q + j]
7 L[n1 + 1] = ∞ ; R[n2 + 1] = ∞ // Sentinels
8 i=1 ;j=1
9 for k = p to r
10 if L[i] ≤ R[j]
11 A[k] = L[i]
12 i = i +1
13 else
14 A[k] = R[j]
15 j = j +1
Introduction 49
Merge Sort
Fusion : illustration
Illustration of Merge
L R
1 2 ... n1 n1+1 1 ... n2 n2+1
p q q+1 r
Introduction 50
Vitesse d’exécution
5
x 10
2.5
Insertion Sort
Merge Sort
2
Complexity
1.5
0.5
0
0 50 100 150 200 250 300 350 400 450 500
n
Introduction 51
Remarques
Introduction 52
Note sur l’implémentation de la récursivité
Trace d’exécution
Trace de: la factorielle
d’exécution
factorial(n)
factorial(n 1)
factorial(2)
factorial(1)
Chaque appel
Temps récursif
de calcul nécessite
: O(n) de mémoriser
(en supposant le contexte
des opérations arithmétiques en
temps constant!).
d’invocation
Espacemémoire
L’espace mémoire utilisé
utilisé :est donc O(n) (n appels récursifs)
O(n).
Avantages :
I Le contexte d’invocation ne doit pas être mémorisé et donc l’espace
mémoire nécessaire est réduit
I Les procédures récursives terminales peuvent facilement être
converties en procédures itératives
Introduction 54
Version récursive terminale de la factorielle
Factorial2(n)
1 return Factorial2-rec(n, 2, 1)
Factorial2-rec(n, i, f )
1 if i > n
2 return f
3 return Factorial2-rec(n, i + 1, f · i)
Introduction 55
Récursivité en C
Types abstraits Implantation et utilisation Récursivité
Structures récursives
Struct 15/24
Types abstraits Implantation et utilisation Récursivité
Struct 19/24
Types abstraits Implantation et utilisation Récursivité
Struct 19/24
Types abstraits Implantation et utilisation Récursivité
Struct 19/24
Types abstraits Implantation et utilisation Récursivité
Struct 20/24
Types abstraits Implantation et utilisation Récursivité
Struct 20/24
Types abstraits Implantation et utilisation Récursivité
Struct 20/24
Types abstraits Implantation et utilisation Récursivité
Struct 20/24
Types abstraits Implantation et utilisation Récursivité
Struct 22/24
Types abstraits Implantation et utilisation Récursivité
Struct 23/24
Types abstraits Implantation et utilisation Récursivité
Struct 24/24
Plan
2. Récursivité
5. Pile et File
Outils d’analyse 84
Comment mesurer les temps d’exécution ?
Expérimentalement :
On écrit un programme qui implémente l’algorithme et on l’exécute
sur des données
Problèmes :
I Les temps de calcul vont dépendre de l’implémentation : CPU, OS,
langage, compilateur, charge de la machine, OS, etc.
I Sur quelles données tester l’algorithme ? Results
60
Ruby
Python
50 Scheme
C
Time (seconds)
40 C-wiz
Java
C-gcc
30
20
10
0
20 25 30 35 40 45 50
n
© 2006 Antonio Carzaniga (Carzaniga)
Outils d’analyse 85
Comment mesurer les temps d’exécution ?
Sur papier :
Développer un modèle de machine (“Random-access machine”,
RAM) :
I Opérations executées les unes après les autres (pas de parallélisme)
I Opérations de base (addition, affectation, branchement, etc.)
prennent un temps constant
I Appel de sous-routines : temps de l’appel (constant) + temps de
l’exécution de la sous-routine (calculé récursivement)
Calculer les temps de calcul = sommer le temps d’exécution associé
à chaque instruction du pseudo-code
Outils d’analyse 86
Chapter 2 Getting Started
Analyse du tri par insertion
I NSERTION -S ORT .A/ cost times
1 for j D 2 to A:length c1 n
2 key D AŒj ! c2 n!1
3 // Insert AŒj ! into the sorted
sequence AŒ1 : : j ! 1!. 0 n!1
4 i D j !1 c4 P! 1
n
5 while i > 0 and AŒi! > key
n
c5 t
PjnD2 j
6 AŒi C 1! D AŒi! c6 .t ! 1/
PjnD2 j
7 i D i !1 c7 j D2 .tj ! 1/
8 AŒi C 1! D key c8 n!1
tj = The running
nombre de time of the
fois que la algorithm
conditionisdu thewhile
sum ofestrunning
testée.times for each sta
ment executed;
Temps exécutiona T
statement
(n) (pour thatun
takes ci steps
tableau detotaille
execute
n) and executes
donné par : n times w
contribute ci n to the total running time.6 To computen T .n/,
n the running time
I NSERTION
T (n) -S= ORTc1 n on
+ can
2 (ninput ofc4n(nvalues,
− 1) + we
c5 sum thec6 products of the cost
X X
− 1) + tj + (tj − 1)
times columns, obtaining j=2 j=2
n
n
X n
X
X
+c7 (tj − 1) + c8 (n − 1)
T .n/ D c1 n C c2j=2
.n ! 1/ C c4 .n ! 1/ C c5 tj C c6 .tj ! 1/
j D2 j D2
Outils d’analyse n 87
Qu’est ce que l’on compte ?
Outils d’analyse 88
Analyse du tri par insertion
Meilleur cas :
le tableau est trié ⇒ tj = 1.
Le temps de calcul devient :
T (n) = c1 n + c2 (n − 1) + c4 (n − 1) + c5 (n − 1) + c8 (n − 1)
= (c1 + c2 + c4 + c5 + c8 )n − (c2 + c4 + c5 + c8 )
Outils d’analyse 89
Analyse du tri par insertion
Pire cas :
le tableau est trié par ordre décroissant ⇒ tj = j.
Le temps de calcul devient :
n(n + 1)
T (n) = c1 n + c2 (n − 1) + c4 (n − 1) + c5 −1
2
n(n − 1) n(n − 1)
+c6 + c7 + c8 (n − 1)
2 2
c5 c6 c7 c5 c6 c7
= ( + + )n2 + (c1 + c2 + c4 + − − + c8 )n
2 2 2 2 2 2
−(c2 + c4 + c5 + c8 )
Outils d’analyse 90
Analyse de la recherche d’un élément dans un tableau trié
1000*N
9
4*N2
8
N3
0.01*2N
7
0
100 200 300 400 500 600 700 800 900 1000
N
Outils d’analyse 92
Pourquoi est-ce important ?
Taille maximale du problème qu’on peut traiter en un temps donné :
T(n) en 1 seconde en 1 minute en 1 heure
n 1 × 106 6 × 107 3.6 × 109
400n 2500 150000 9 × 106
2n2 707 5477 42426
n4 31 88 244
2n 19 25 31
Trois notations :
I Grand-O : f (n) ∈ O(g (n)) ≈ f (n) ≤ g (n)
I Grand-Omega : f (n) ∈ Ω(g (n)) ≈ f (n) ≥ g (n)
I Grand-Theta : f (n) ∈ Θ(g (n)) ≈ f (n) = g (n)
Outils d’analyse 94
Notation grand-O
Asymptotic notation
O-notation
O(g (n)) = {f (n)|∃c > 0, ∃n0 ≥ 1 tels que 0 ≤ f (n) ≤ cg (n), ∀n ≥ n0 }
O.g.n// D ff .n/ W there exist positive constants c and n0 su
0 " f .n/ " cg.n/ for all n # n0 g :
cg(n)
f(n)
n
n0
!-notation
Ω(g (n)) = {f (n)|∃c > 0, ∃n0 ≥ 1 tels que 0 ≤ cg (n) ≤ f (n), ∀n ≥ n0 }
!.g.n// D ff .n/ W there exist positive constants c and n0 such
0 ! cg.n/ ! f .n/ for all n " n0 g :
f(n)
cg(n)
n
n0
f(n)
c1g(n)
n
n0
450
2n
n3
400
n2
350
n.log(n)
300 n
250
log(n)
200
150
100
50
0
5 10 15 20 25 30 35 40 45 50
Outils d’analyse 98
Quelques propriétés
Outils d’analyse 99
Comment calculer la complexité en pratique ?
prefixAverages(X ) :
Entrée : tableau X de taille n
Pi
j=1 X [j]
Sortie : tableau A de taille n tel que A[i] = i
prefixAverages(X )
prefixAverages2(X )
1 for i = 1 to X . length
1 s =0
2 a=0
2 for i = 1 to X . length
3 for j = 1 to i
3 s = s + X [i]
4 a = a + X [j]
4 A[i] = s/i
5 A[i] = a/i
5 return A
6 return A
Complexité : Θ(n)
Complexité : Θ(n2 )
Factorial(n)
1 if n = = 0
2 return 1
3 return n · Factorial(n − 1)
T (0) = c0
T (n) = T (n − 1) + c1
= c1 n + c0
⇒ T (n) ∈ Θ(n)
Fibonacci :
T (1) = c0
T (n) = T (n − 1) + T (n − 2) + c1 pour n > 1
T (1) = c0
T (n) = T (dn/2e) + T (bn/2c) + c1 n + c2 pour n > 1
Tour de Hanoï :
T (1) = c0
T (n) = 2T (n − 1) + c1 pour n > 1
Méthodes “manuelles” :
I Téléscopage (plug-and-chug)
I Arbre de récursion
I ...
Méthodes systématiques :
I Le théorème maître (récurrences diviser-pour-régner)
I Equations caractéristiques (récurrences linéaires)
I ...
Synthèse : calcul de complexité en pratique
2. Récursivité
5. Pile et File
Dans ce cours :
Principalement des ensembles dynamiques (dynamic sets), amenés à
croı̂tre, se rétrécir et à changer au cours du temps.
Les objets de ces ensembles comportent des attributs.
Un de ces attributs est une clé qui permet d’identifier l’objet, les
autres attributs sont la plupart du temps non pertinents pour
l’implémentation de la structure.
Certains ensembles supposent qu’il existe un ordre total entre les
clés.
Struct 5/24
Types abstraits Implantation et utilisation Récursivité
Struct
Les types structurés sont un moyen privilégié de définir des
types abstraits : ce sont des types complexes construits à partir
de types “plus simples” :
struct nomStructure { typedef struct{
type champ1 nomChamp1; type champ1 nomChamp1;
type champ2 nomChamp2; type champ2 nomChamp2;
... ...
}; } nomType ;
typedef nomStructure nomType ;
Color randomColor(void){
return (Color){myRand(0xffffff+1)};
}
Struct 8/24
Types abstraits Implantation et utilisation Récursivité
typedef struct {
Color grayScale(Color c){
int red; int green; int blue;
int s;
}Color;
s=(c.red+c.blue+c.green)/3;
Color res = {s,s,s};
Color randomColor(void){
return res;
Color c={myRand(256), myRand(256), myRand(256)};
}
return c;
}
Color mixColors(Color c1, Color c2){
Color res;
Color newColorRGB(int r, int g, int b){
res.red=(c1.red+c2.red)/2;
Color c={r,g,b};
res.green=(c1.green+c2.green)/2;
return c;
res.blue=(c1.blue+c2.blue)/2;
}
return res;
}
void printRGB(Color c){
printf("[%d,%d,%d] ",c.red, c.green, c.blue);
void inverseColor(Color *c){
}
c->red=255-c->red;
c->green=255-c->green;
void printHexa(Color c){
c->blue=255-c->blue;
printf("\#%x ", (c.red<<16) + (c.green<<8) + c.blue);
}
}
SArray t = newEmptySArray();
int i,j, up=20, taille=100;
srandom(time(NULL));
printSArray(t);
printf("t vide? %d, t plein? %d\n",isEmpty(t),isFull(t));
randomSArray(taille, &t, up);
printf("t vide? %d, t plein? %d\n",isEmpty(t),isFull(t));
printSArray(t);
printf("indice de %d dans t: %d\n", 1, search(1,t));
for(i=0;i<up;i++){
j=search(i,t);
printf("verification: get(search(%d,t),t): %d\n", i,j==-1?-1:get(j,t) );
}
while( (i=search(5, t)) != -1 )
delete(i, &t);
printf("longueur de t: %d\n", getLength(t));
printSArray(t);
}
Struct 11/24
Types abstraits Implantation et utilisation Récursivité
void printSArray(SArray t){ void insertPosition(int elem, SArray *t, int i){
printTab(t.tab, t.lg); ...
} }
Struct 12/24
Types abstraits Implantation et utilisation Récursivité
Ou alors...
SArray newEmptySArray(void){
SArray res;
res.lg=0;
if( (res.tab=malloc(MAX SIZE*sizeof(int))) == NULL )
erreur("Allocation ratée!");
return res;
}
...
Struct 13/24
Plan
2. Récursivité
5. Pile et File
Pop(S)
Stack-Empty(S)
Push(S, x)
1 1 ififS.top
Stack-Empty(S)
== 0
1 if S.top == S. length 2 error “underflow”
2 error “overflow” 2 return true
elsereturn
3 3 else S. top = S. top − 1
false
3 S. top = S.top + 1 4 return S[S. top + 1]
4 S[S. top] = x
ComplexitéPush(S,
en temps x) et en espace : O(1) Pop(S)
(Inconvénient : L’espace occupé
1 S.top = S.top + 1 ne dépend pas du nombre d’objets)
1 if Stack-Emp
2 S[S.top] = x 2 error “und
3 else S.top = S
Structures de données 193
10.2 Linked lists 237
Rappel : liste simplement et doublement liée
prev key next
(a) L:head 9 16 4 1
(b) L:head 25 9 16 4 1
Structure de données composée d’une séquence d’éléments de liste.
(c)
Chaque élément x de25 la liste est9 composé16:
L:head 1
I d’un contenu utile x.data de type arbitraire (par exemple une clé),
I d’un pointeur
Figure 10.3 x. (a)next
A doubly linked
vers list L representing
l’élément the dynamic
suivant dansset la 9; 16g. Each element in
séquence
f1; 4;
the list is an object with attributes for the key and pointers (shown by arrows) to the next and previous
I Doublement liée : d’un pointeur x. prev vers l’élément précédent dans
objects. The next attribute of the tail and the pre! attribute of the head are NIL , indicated by a diagonal
slash. The attribute L: head points to the head. (b) Following the execution of L IST-I NSERT.L; x/,
la séquence
where x: key D 25, the linked list has a new object with key 25 as the new head. This new object
Soit L unepoints
listeto the
liée
old head with key 9. (c) The result of the subsequent call L IST-D ELETE.L; x/, where x
I L. headpoints to the object with key 4.
pointe vers le premier élément de la liste
I Doublement liée : L.tail pointe vers le dernier élément de la liste
elements. In the remainder of this section, we assume that the lists with which we
Le dernier are working are
élément unsorted un
possède and doubly linked.x.next vide (noté NIL)
pointeur
Searching
Doublement liée : aLe
linked list
premier élément possède un pointeur x.prev
vide The procedure L IST-S EARCH .L; k/ finds the first element with key k in list L
by a simple linear search, returning a pointer to this element. If no object with
key k appears in the list, then the procedure returns NIL. For the linked list in
Structures de données Figure 10.3(a), the call L IST-S EARCH .L; 4/ returns a pointer to the third element, 194
ecution of L IST-I NSERT.L; x/,
heImplémentation
new head. This newd’uneobject pile à l’aide d’une liste liée
L IST-D ELETE.L; x/, where x
S est une liste simplement liée (S.head pointe vers le premier
à l’aide d’une liste liée
élément de la liste)
ément dewith
at the lists la which
liste we Stack-Empty(S)
liée (S.head pointe
9 vers le14premier 1 if S. head = = NIL
de (noté NIL) 2 return true
3 else return false
pointeur x.prev
ack-Empty(S)
4
Pop(S)
ment with key
if S.head k in list L
== NIL 1 if Stack-Empty(S)
ement. If notrue
object with
Push(S,
return x) 2 error “underflow”
(b) Q 13 25 3 4 5 6 15
7 68 99 810 411 17
12
(b) Q 3 Q:tail
5 D3 Q:head15D 76 9 8 4 17
1 2 3 D
Q:tail 4 3 5 Q:head
6 7 8 D 97 10 11 12
(c) Q 3 Q:tail
5 D3 15 6 D97 8 4 17
Q:head
1 2 3 4 5 6 7 8 9 10 11 12
Dequeue(Q) → 15
(c) Q 13 25 3 4 5 6 15
7 68 99 810 411 17
12
Q:tail D 3 Q:head D 8
(c) Q 3 5 15 6 9 8 4 17
Q:tail D 3 Q:head D 8
Figure 10.2 A queue implemented using an array QŒ1 : : 12!. Queue elements appear o
lightly shaded D 3 (a) TheQ:head
positions.
Q:tail queue hasD5 8elements, in locations QŒ7 : : 11!. (b) The con
of the queue after the calls E NQUEUE.Q; 17/, E NQUEUE.Q; 3/, and E NQUEUE.Q; 5/
Figure 10.2 ofA the
configuration queue implemented
queue using
after the call an array
D EQUEUE .Q/QŒ1returns theQueue
: : 12!. elements
key value ap
15 forme
Structures de données lightly shaded positions. (a) The queue has 5 elements, in locations QŒ7 : : 11!. (b)
198 T
Enqueue et Dequeue
Enqueue(Q,x) Dequeue(Q)
1 Q[Q. tail] = x 1 x = Q[Q. head]
2 if Q. tail = = Q. length 2 if Q.head == Q. length
3 Q. tail = 1 3 Q. head = 1
4 else Q. tail = Q.tail + 1 4 else Q. head = Q. head + 1
5 return x
remove-first(Q) remove-last(Q)
1 if (Q. size == 0) 1 if (Q. size == 0)
2 error 2 error
3 x = Q. head.next 3 x = Q.tail.prev
4 Q. head.next = Q.head.next.next 4 Q. tail.prev = Q. tail.prev .prev
5 Q. head.next.prev = Q. head 5 Q. tail.prev .next = Q. head
6 Q. size = Q. size − 1 6 Q. size = Q. size − 1
7 return x 7 return x
Pile et File en C
Implémentation d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
max 5
P cur 0
tab
14
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
push(7)
max 5
P cur 1
tab
15
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
push(3)
max 5
P cur 2
tab
16
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
push(8)
7 3 8 ??? ???
max 5
P cur 3
tab
17
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
pop()
max 5 8
P cur 2
tab
18
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
push(5)
7 3 5 ??? ???
max 5
P cur 3
tab
19
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
pop()
max 5 5
P cur 2
tab
20
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
pop()
max 5 3
P cur 1
tab
21
Fonctionnement d’une pile
Représentation contiguë d’une pile Avec un tableau
Pile Tas
pop()
max 5 7
P cur 0
tab
1 int pop(stack* P) {
2 if (P->cur == 0) {
3 printf("Pile vide !\n");
4 return -1;
5 }
6 P->cur--;
7 return P->tab[P->cur];
8 }
9
23
Implémentation d’une pile en C
Représentation contiguë d’une pile Avec un tableau dynamique
1 int pop(stack* P) {
2 if (P->cur == 0) {
3 printf("Pile vide !\n");
4 return -1;
5 }
6 P->cur--;
7 return P->tab[P->cur];
8 }
9
24
Implémentation d’une file
Représentation contiguë d’une file Avec un tableau
1 typedef struct {
2 unsigned int max; // capacité max
3 unsigned int cur; // nombre d’éléments
4 unsigned int first; // premier élément
5 int * tab;
6 } queue ;
25
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
max 5
cur 0
F first 0
tab
26
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
push(7)
max 5
cur 1
F first 0
tab
27
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
push(5)
max 5
cur 2
F first 0
tab
28
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
push(8)
7 5 8 ??? ???
max 5
cur 3
F first 0
tab
29
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
pop()
max 5
cur 2 7
F first 1
tab
Pile Tas
push(6)
??? 5 8 6 ???
max 5
cur 3
F first 1
tab
31
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
push(2)
??? 5 8 6 2
max 5
cur 4
F first 1
tab
32
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
pop()
??? ??? 8 6 2
max 5
cur 3 5
F first 2
tab
33
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
push(9)
9 ??? 8 6 2
max 5
cur 4
F first 2
tab
Pile Tas
pop()
9 ??? ??? 6 2
max 5
cur 3 8
F first 3
tab
35
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
pop()
max 5
cur 2 6
F first 4
tab
36
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
pop()
max 5
cur 1 2
F first 0
tab
37
Fonctionnement d’une file
Représentation contiguë d’une file Avec un tableau
Pile Tas
pop()
max 5
cur 0 9
F first 1
tab
38
Implémentation d’une file en C
Représentation contiguë d’une file Avec un tableau
1 int pop(queue* F) {
2 int res;
3 if (F->cur == 0) {
4 printf("File vide !\n");
5 return -1;
6 }
7 res = F->tab[F->first];
8 F->first = (F->first+1) % F->max; // incrémentation "cyclique"
9 F->cur--;
10 return res;
11 }
12 void push(queue* F, int val) {
13 if (F->cur == F->max) {
14 printf("File pleine !\n");
15 return;
16 }
17 F->tab[(F->first+F->cur) % F->max] = val;
18 F->cur++;
19 }
39
Implémentation d’une file en C
Représentation contiguë d’une file Avec un tableau dynamique
40
Piles et files avec des listes chaı̂nées
Représentation chaînée des piles et des files
Il est aussi possible d’implémenter efficacement une pile ou une file
avec une liste chaı̂née
il n’y a pas de contraintes de taille comme avec un tableau.
La pile est le plus simple :
push consiste à insérer un élément en début de liste,
pop lit le contenu du premier élément et le supprime,
_ les opérations se font bien en Θ (1).
Pour la file c’est un peu plus compliqué :
il faut insérer les éléments à un bout et les supprimer à l’autre,
on ne sait pas reculer d’un élément, juste passer au suivant.
_ on insère à la fin (nécessite un pointeur supplémentaire) et
on retire du début.
61
Piles et files avec des listes chaı̂nées
Représentation chaînée des piles et des files
Implémentation d’un file
queue.c
1 typedef struct { // nouvelle structure de file
2 cell* beg; // pointeur sur la première case
3 cell* end; // pointeur sur la dernière case
4 } queue ;
5
6 void push(queue* F, int v) {
7 cell* new = (cell* ) malloc(sizeof(cell ));
8 new->val = v;
9 new->next = NULL;
10 if (F->end == NULL) { // si la file est vide
11 F->beg = new; // le dernier est aussi le premier élément,
12 F->end = new;
13 } else { // sinon :
14 F->end->next = new; // - ajout de l’élément à la fin
15 F->end = new; // - on met à jour la fin
16 }
17 }
62
Piles et files avec des listes chaı̂nées
Représentation chaînée des piles et des files
Implémentation d’un file
queue.c
1 int pop(queue* F) {
2 int res;
3 cell* tmp;
4 if (F->beg == NULL) {
5 printf("File vide !\n");
6 return -1;
7 } else if (F->beg == F->end) { // s’il n’y a qu’une case
8 F->end = NULL; // la file sera vide à la fin
9 }
10 res = F->beg->val; // on sauvegarde la valeur
11 tmp = F->beg; // on sauvegarde le pointeur
12 F->beg = F->beg->next; // on avance le début d’une case
13 free(tmp); // on libère la case extraite
14 return res;
15 }
63
Plan
2. Récursivité
5. Pile et File
Remove-At-Rank :
I O(n) pour une opération individuelle, où n est le nombre de
composantes du vecteur
I Θ(n2 ) pour n opérations de retrait en début de vecteur
I Θ(n) pour n opérations de retrait en fin de vecteur
// crée une liste dont le 1er élément est e et dont la suite est nxt;
// erreur si l’allocation mémoire de la nouvelle cellule échoue.
Rlist cons(Element e, Rlist nxt);
int main(void){
Rlist rl = newEmptyRlist();
printRlist(rl,"%d");
rl = cons(1,rl);
rl = cons(2,cons(3,rl));
printRlist(rl,"%d");
printf("%d\n",car(rl));
printf("%d\n",car(cdr(rl)));
printRlist(cdr(rl),"%d");
printRlist(cdr(cdr(rl)),"%d");
rl = cdr(rl);
printRlist(rl,"%d");
printf("%d\n",car(cdr(cdr(rl))));
return 0;
}
Struct
Listes Listes chaı̂nées en C Piles
int main(void){
Rlist rl = newEmptyRlist();
printRlist(rl,"%d"); ---------------> [ ]
rl = cons(1,rl);
rl = cons(2,cons(3,rl));
printRlist(rl,"%d"); ---------------> [ 2 3 1 ]
printf("%d\n",car(rl)); ------------> 2
printf("%d\n",car(cdr(rl))); -------> 3
printRlist(cdr(rl),"%d"); ----------> [ 3 1 ]
printRlist(cdr(cdr(rl)),"%d"); -----> [ 1 ]
rl = cdr(rl);
printRlist(rl,"%d"); ---------------> [ 3 1 ]
printf("%d\n",car(cdr(cdr(rl)))); --> erreur!
return 0;
}
Struct
Listes Listes chaı̂nées en C Piles
Struct
Listes Listes chaı̂nées en C Piles
Struct
Listes Listes chaı̂nées en C Piles
Struct
Listes Listes chaı̂nées en C Piles
4 17 1
Struct
Listes Listes chaı̂nées en C Piles
Struct
Listes Listes chaı̂nées en C Piles
Struct