Anda di halaman 1dari 109

Option informatique :

la deuxi`eme annee
Laurent Ch

eno
ete
Lyc ee Louis-le-Grand, Paris
Table des mati`eres
I Arbres 13
1 Arbres binaires 15
1.1 Denitions et notations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.1 Denition formelle dun arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.2 Denition des arbres binaires en Caml . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.3 Une indexation des elements constitutifs dun arbre . . . . . . . . . . . . . . . . . 16
1.2 Notion de profondeur dans un arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.2.1 Denitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.2.2 Calcul de la profondeur en Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Squelette dun arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.1 Un exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.2 Denition du squelette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.3 Le squelette comme une classe dequivalence . . . . . . . . . . . . . . . . . . . . . 19
1.3.4

Ecriture en Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4 Combinatoire des arbres et squelettes binaires . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.1 Nuds et feuilles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.2 Profondeur et taille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.3 Denombrement des squelettes binaires . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.5 Exercices pour le chapitre 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2 Parcours dun arbre 27
2.1 Parcours en largeur dabord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.1.1 Description de lordre militaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.1.2 Programmation Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2 Parcours en profondeur dabord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2.1 Parcours prexe, inxe, suxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2.2 Programmation en Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2.3 Probl`eme inverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.3 Exercices pour le chapitre 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3 Arbres de recherche 31
3.1 Denition dun arbre binaire de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.1 Denition generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.2 Cas particulier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2 Recherche dun element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.1 Position du probl`eme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.2 Recherche dans un arbre binaire de recherche . . . . . . . . . . . . . . . . . . . . . 32
3.2.3

Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3 Structure dynamique de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.1 Ajout dun element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.2 Suppression dun element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.3 Application au tri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3
4 TABLE DES MATI
`
ERES
3.3.4 Le probl`eme de lequilibrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.4 Exercices pour le chapitre 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4 Tri et tas 37
4.1 Generalites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.1 Files de priorite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.2 Tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.3 Implementation des tas `a laide de tableaux . . . . . . . . . . . . . . . . . . . . . . 38
4.2 Percolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.1 Description de lalgorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.2 Programmation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2.3

Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.2.4 Application : creation dun tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.3 Le tri par les tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.3.1 Programmation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.3.2

Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5 Arbres n-aires et expressions arithmetiques 45
5.1 Arbres n-aires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.1.1 Denition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.1.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.1.3 Proprietes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.1.4 Parcours dun arbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2 Expressions arithmetiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.1 Une denition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.2 Syntaxe concr`ete et syntaxe abstraite . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2.3 Expressions et arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.3 Derivation formelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.3.1 Derivation guidee par la structure darbre . . . . . . . . . . . . . . . . . . . . . . . 50
5.3.2 Simplication : une premi`ere approche . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.4 Exercices pour le chapitre 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
II Automates 57
6 Automates nis deterministes ou non deterministes 59
6.1 Automates nis deterministes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.1 Presentation informelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.1.2 Presentation mathematique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.1.3 Transitions et calculs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.1.4 Langage reconnu par un automate ni deterministe . . . . . . . . . . . . . . . . . . 61
6.2 Implementation en Caml dun afd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.3 Automates nis non deterministes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.3.1 Presentation informelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.3.2 Denition mathematique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.4 Implementation en Caml dun afnd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.5 Determinisation dun afnd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.5.1 Algorithme de determinisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.5.2 Programmation en Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.6 Exercices pour le chapitre 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
TABLE DES MATI
`
ERES 5
7 Langages rationnels et automates 75
7.1 Langages rationnels et expressions reguli`eres . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7.1.1 Denition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
7.1.2 Expressions reguli`eres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
7.2 Le theor`eme de Kleene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
7.2.1 Des langages rationnels aux automates . . . . . . . . . . . . . . . . . . . . . . . . . 78
7.2.2 Des automates aux langages rationnels . . . . . . . . . . . . . . . . . . . . . . . . . 79
7.3 Langages non rationnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.3.1 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.3.2 Le lemme de letoile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.4 Exercices pour le chapitre 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
III Corrige de tous les exercices 87
1 Exercices sur Arbres binaires 89
2 Exercices sur Parcours dun arbre 93
3 Exercices sur Arbres de recherche 97
5 Exercices sur Arbres n-aires 101
6 Exercices sur Automates nis 103
7 Exercices sur Langages rationnels et automates 107
Table des gures
1.1 Premiers exemples darbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2 Indexation dun arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.3 Ambigute de lindexation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4 Construction du squelette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.5 Taille et profondeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.6 Squelettes darbres complets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.1 Un arbre pour lexemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.2 Ambig uite de la description inxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1 Un arbre binaire de recherche sur N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2 Arbre obtenu par suppression du 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.3 Arbre obtenu par suppression du 7 puis du 5 . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1 Une le de priorite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.2 Un tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.3 Un tas avec sa numerotation des nuds . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.4 Un arbre `a percoler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.5 Letape intermediaire de la percolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.6 Le tas obtenu par percolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.1 Un exemple darbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.2 Un autre arbre n-aire de meme parcours prexe . . . . . . . . . . . . . . . . . . . . . . . . 47
6.1 Un premier exemple dautomate ni deterministe . . . . . . . . . . . . . . . . . . . . . . . 59
6.2 Deux automates pour un meme langage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.3 Un automate ni non deterministe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.4 Un afnd pour les mots qui nissent par c/ . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
6.5 Un afnd pour les mots nissant par c/c/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.6 Lautomate determinise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.7 Un afnd `a la determinisation co uteuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.1 Automates pour les expressions reguli`eres atomiques . . . . . . . . . . . . . . . . . . . . . 78
7.2 Automate pour la somme de deux expressions reguli`eres . . . . . . . . . . . . . . . . . . . 78
7.3 Automate pour le produit de deux expressions reguli`eres . . . . . . . . . . . . . . . . . . . 79
7.4 Automate pour letoile dune expression reguli`ere . . . . . . . . . . . . . . . . . . . . . . . 79
7.5 Avant la suppression de letat r . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
7.6 Apr`es la suppression de letat r . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
7.7 Automate `a 2 etats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
7.8 Quel est le langage reconnu par cet automate ? . . . . . . . . . . . . . . . . . . . . . . . . 81
7.9 On a supprime letat 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
7.10 Apr`es suppression des etats 2 et 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7.11 On recommence en supprimant letat 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7.12 Apr`es suppression des etats 2 et 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7
Liste des programmes
1.1 Denition du type arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2 Calcul de la profondeur dun arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Nombre de nuds, de feuilles dun arbre, taille dun squelette . . . . . . . . . . . . . . . 20
2.1 Parcours dun arbre binaire en ordre militaire . . . . . . . . . . . . . . . . . . . . . . . . 28
2.2 Parcours dun arbre binaire en ordres prexe, inxe et suxe . . . . . . . . . . . . . . . . 29
2.3 Reconstitution dun arbre binaire ` a partir de sa description en ordre prexe . . . . . . . . 29
2.4 Reconstitution dun arbre binaire ` a partir de sa description en ordre suxe . . . . . . . . 30
3.1 Recherche sequentielle dans une liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2 Recherche dans un arbre binaire de recherche . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3 Recherche dans un arbre binaire de recherche sur N . . . . . . . . . . . . . . . . . . . . . 33
3.4 Ajout dun element dans un arbre binaire de recherche . . . . . . . . . . . . . . . . . . . 33
3.5 Suppression dun element dans un arbre binaire de recherche . . . . . . . . . . . . . . . . 35
3.6 Tri ` a laide darbres binaires de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1 Percolation recursive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2 Percolation iterative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.3 Reorganisation dun arbre en tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.4 Le tri par tas (heap sort) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.1 Nombre de nuds et feuilles dun arbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2 Profondeur dun arbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.3 Parcours prexe et suxe dun arbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.4 Reconstitution dun arbre n-aire `a partir de son parcours prexe . . . . . . . . . . . . . . 48
5.5 Conversions arbres dexpression/expressions arithmetiques . . . . . . . . . . . . . . . . . 49
5.6

Evaluation des expressions arithmetiques . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.7 Impressions prexe et suxe des expressions . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.8 Impression inxe des expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.9 Derivation formelle des expressions arithmetiques . . . . . . . . . . . . . . . . . . . . . . 52
5.10 Simplication des expressions algebriques . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.1 Reconnaissance dune chane par un afd . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.2 Quelques fonctions utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.3 Reconnaissance dune chane par un afnd . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.4 Fonctions utiles sur les ensembles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
6.5 La determinisation des automates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
9
Liste des exercices
Exercice 1.1 Indexation dun arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Exercice 1.2 Sous-arbres de profondeur donnee . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Exercice 1.3 Calcul du squelette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Exercice 1.4 Generation des squelettes darbres binaires . . . . . . . . . . . . . . . . . . . . . . 24
Exercice 1.5 Squelette darbre complet de taille donnee . . . . . . . . . . . . . . . . . . . . . . . 24
Exercice 1.6 Test de completude . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Exercice 1.7 Test dequilibrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Exercice 2.1 Reconstitution `a partir de lordre militaire . . . . . . . . . . . . . . . . . . . . . . . 30
Exercice 2.2 Conversions prexe/suxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Exercice 3.1 Une autre structure darbre de recherche . . . . . . . . . . . . . . . . . . . . . . . . 35
Exercice 3.2 Balance et equilibrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Exercice 3.3 Taille dun arbre AVL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Exercice 3.4 Arbres 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Exercice 5.1 Reconstitution dun arbre n-aire ` a partir du parcours suxe . . . . . . . . . . . . . 55
Exercice 5.2 Impression inxe des expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Exercice 6.1 Quelques automates simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Exercice 6.2 Determinisation dun automate simple . . . . . . . . . . . . . . . . . . . . . . . . . 71
Exercice 6.3 Preuve de la determinisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Exercice 6.4 Ajout dun etat mort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Exercice 6.5 Determinisation dun afd ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Exercice 6.6 Minimisation dun afd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Exercice 7.1 Langages rationnels, intersection et complementaire . . . . . . . . . . . . . . . . . 84
Exercice 7.2

Equivalence des expressions reguli`eres . . . . . . . . . . . . . . . . . . . . . . . . . 84
Exercice 7.3 Le langage des facteurs des mots dun langage . . . . . . . . . . . . . . . . . . . . 84
Exercice 7.4 Reconnaissance dun meme langage . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Exercice 7.5 Exemples de langages non rationnels . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Exercice 7.6 Expressions reguli`eres decrivant des langages donnes . . . . . . . . . . . . . . . . . 85
11
Premi`ere partie
Arbres
13
Chapitre 1
Arbres binaires
1.1 Denitions et notations
1.1.1 Denition formelle dun arbre binaire
Commencons par une denition tr`es mathematique.
Denition 1.1 (Arbres binaires) On consid`ere deux ensembles de valeurs 1 (valeurs des feuilles) et
(valeurs des nuds). Un arbre binaire sur ces ensembles est deni de fa con recursive comme suit. Toute
feuille, element de 1, est un arbre.

Etant donnes une valeur n de nud (n ), et deux arbres p et d,
(n, p, d) est un nouvel arbre, de racine n, de ls gauche p, de ls droit d.
La denition que nous avons donnee ici permet de distinguer le type des informations portees respective-
ment par les nuds et les feuilles dun arbre.
On utilise dhabitude, au lieu decritures comme ) pour une simple feuille, ou encore, pour donner
un exemple plus complexe, (n
1
, (n
2
, )
21
, )
22
), (n
3
, )
31
, (n
4
, )
41
, )
42
))), la representation graphique quon
trouvera dans la gure suivante.
f n
1

n
2

f
21

`
`
`
f
22

n
3

f
31

`
`
`
n
4

f
41

`
`
`
f
42
Fig. 1.1: Premiers exemples darbres
Dans cette representation, les feuilles sont dessinees `a laide de carres, les nuds par des cercles. Notons
que certains auteurs utilisent les expressions nuds externes pour les feuilles et nuds internes pour ce
que nous avons appele les nuds.
La representation graphique introduit la notion de haut et de bas, et bien s ur les informaticiens ayant la
tete un peu `a lenvers, tous nos arbres auront leurs feuilles en bas et leur racine en haut. . .
Pour illustrer nos denitions, tentons de decrire avec notre nouveau vocabulaire le deuxi`eme arbre de la
gure ci-dessus. Sa racine est le nud n
1
, qui a deux ls, les arbres de racines n
2
et n
3
. Le sous-arbre
15
16 CHAPITRE 1. ARBRES BINAIRES
gauche de racine n
2
a pour ls gauche et droit deux feuilles, tandis que le sous-arbre droit de racine n
3
a
respectivement pour ls gauche et droit une feuille et un nouveau sous-arbre de racine n
4
qui ` a son tour
a pour ls gauche et droit deux feuilles.
Le plus souvent, on se permettra labus de langage qui consiste `a citer un nud en pensant ` a larbre (le
sous-arbre) dont il est racine. Ainsi n
2
designera-t-il tout aussi bien le nud precis qui porte ce nom que
tout le sous-arbre qui ladmet pour racine.
Remarquons pour terminer que toute feuille gure necessairement en bas de larbre, puisquelle ne peut
avoir de ls. Enn, on dit que c est p`ere de / aussi bien quand / est une feuille qui est un ls (droit ou
gauche) de c et quand / est la racine du sous-arbre ls droit ou gauche de c.
1.1.2 Denition des arbres binaires en Caml
En Caml, on denit un type ` a deux param`etres qui sont les types respectifs des feuilles et des nuds, `a
laide de linstruction suivante :
Programme 1.1 Denition du type arbre binaire
type (f,n) arbre_binaire =
| Feuille of f
| Nud of n * (f,n) arbre_binaire * (f,n) arbre_binaire ;;
On denira les deux arbres de lexemple ci-dessus `a laide dinstructions comme
let f = Feuille("f")
and a = Nud("n1", Nud("n2",Feuille("f21"),Feuille("f22")),
Nud("n3",Feuille("f31"),Nud("n4",Feuille("f41"),Feuille("f42")))) ;;
1.1.3 Une indexation des elements constitutifs dun arbre
Nous allons maintenant denir une indexation des elements constitutifs dun arbre (feuilles et nuds) ` a
laide de mots sur lalphabet 0, 1.
Denition 1.2 (Mots binaires) On appelle mot binaire toute suite eventuellement vide de 0 ou de 1. Autre-
ment dit, un mot binaire est ou bien le mot vide, note c, ou bien le resultat de la concatenation dun mot
binaire et dun 0 ou dun 1.
`
A tout mot binaire est naturellement associe un entier naturel, dont le mot choisi est une ecriture en base
2. Par exemple, le mot binaire 10010 est associe `a lentier 18. Par convention, le mot vide c sera associe
`a , et on notera N

= N . Nous noterons par un di`ese (;) cette application des mots binaires
vers N

: ainsi ecrirons-nous ;10010 = 18.


On peut alors numeroter les elements dun arbre en leur associant un mot binaire. La r`egle est fort simple,
et peut senoncer ainsi.
Denition 1.3 (Indexation) On consid`ere un arbre binaire. Sil sagit dune feuille, on lindexe par le mot
vide c. Si en revanche il sagit dun nud (n, p, d), on commence par indexer sa racine n par le mot vide c, et
par eectuer lindexation de tous les elements de larbre p et de larbre d. Enn, on ajoute devant lindex de
chaque element de larbre p (resp. d) un 0 (resp. un 1).
On retrouvera dans la gure suivante le deuxi`eme arbre de la gure 1.1 page precedente o` u chaque element
est indexe `a sa gauche par un mot binaire.
Lindexation ainsi eectuee discrimine eectivement les feuilles de larbre, ce qui fait lobjet du theor`eme
suivant.
Theor`eme 1.1
Dans lindexation precedente, si )
1
et )
2
sont deux feuilles distinctes dun meme arbre et i
1
, i
2
les mots
binaires associes, on a i
1
,= i
2
.
1.2. NOTION DE PROFONDEUR DANS UN ARBRE 17
n
1

0 n
2

00 f
21

`
`
`
01 f
22

`
`
`
`
1 n
3

10 f
31

`
`
`
11 n
4

110 f
41

`
`
`
111 f
42
Fig. 1.2: Indexation dun arbre binaire
4 La demonstration se fait par recurrence structurelle.
Pour un arbre reduit `a une feuille, le resultat est clair.
Soit c = (n, p, d) un arbre. Soit )
1
et )
2
deux feuilles de cet arbre.
Ou bien )
1
et )
2
sont des feuilles du meme sous-arbre p de c. Dans ce cas leurs index i
1
et i
2
sont
obtenus `a partir des index i

1
et i

2
quelles portent dans larbre p grace aux relations i
1
= 0i

1
et
i
2
= 0i

2
. Comme par hypoth`ese de recurrence i

1
,= i

2
, on a bien i
1
,= i
2
.
Ou bien )
1
et )
2
sont des feuilles du meme sous-arbre d de c. Dans ce cas on obtient de meme
i
1
= 1i

1
,= 1i

2
= i
2
.
Ou bien )
1
est une feuille de p et )
2
une feuille de d. Mais alors i
1
commence par un 0 et i
2
par un
1, et donc i
1
,= i
2
. 3
En revanche, il faut faire attention `a ce quon peut avoir m
1
= m
2
, comme dans le cas de la
gure 1.3, o` u les feuilles f
41
et f
31
ont pour index respectifs 010 et 10 qui sont bien dierents,
certes, mais pourtant 010 = 10 = 2.
n
1

0 n
2

00 f
21

`
`
`
01 n
4

010 f
41

`
`
`
011 f
42

`
`
`
`
1 n
3

10 f
31

`
`
`
11 f
32
Fig. 1.3: Ambigute de lindexation
1.2 Notion de profondeur dans un arbre
1.2.1 Denitions
On appelle profondeur dun nud ou dune feuille dun arbre le nombre daretes quil faut traverser pour
descendre de la racine de larbre au nud ou la feuille vise(e).
18 CHAPITRE 1. ARBRES BINAIRES
Dune fa con plus mathematique, on peut dire que la profondeur dun element dun arbre est la longueur
du mot binaire qui lindexe dans lindexation decrite plus haut.
La profondeur de larbre est denie comme etant le maximum des profondeurs de ses elements, ou encore,
puisque les feuilles sont sous les nuds, comme le maximum des profondeurs de ses feuilles.
1.2.2 Calcul de la profondeur en Caml
Bien s ur, le calcul de la profondeur est aise `a laide dun programme recursif :
Programme 1.2 Calcul de la profondeur dun arbre
let rec profondeur = function
| Feuille(_) -> 0
| Nud(_,g,d) -> 1 + (max (profondeur g) (profondeur d)) ;;
On aura note que linformation portee par les nuds et feuilles de larbre ne joue aucun role dans le
calcul de la profondeur, evidemment.
1.3 Squelette dun arbre binaire
1.3.1 Un exemple
Considerons `a nouveau larbre de la gure 1.1 page 15. On peut commencer par eacer toute linformation
portee par ses nuds et par ses feuilles. On obtient ainsi un arbre dessine `a laide de cercles et de carres.
Si on supprime purement et simplement les feuilles, on obtient un squelette o` u gurent les seuls nuds,
comme dans la gure 1.4.
n
1

n
2

f
21

`
`
`
f
22

n
3

f
31

`
`
`
n
4

f
41

`
`
`
f
42

`
`
`

`
`
`

`
`
`

`
`
`

`
`
`

Fig. 1.4: Construction du squelette


Si bien entendu le passage du premier au second stade est destructif (on a eace linformation portee), en
revanche le passage du second au dernier est reversible, comme diraient les thermodynamiciens : il sut
en eet dajouter des feuilles `a tous les endroits possibles, cest-`a-dire sous tous les nuds qui ont 0 ou 1
ls.
1.3.2 Denition du squelette
Denition 1.4 (Squelettes binaires) Un squelette (darbre) binaire est deni de facon recursive comme suit.
Le mot vide c est un squelette binaire.

Etant donnes deux squelettes p et d, (p, d) est un nouveau squelette,
de ls gauche p, de ls droit d.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES 19
Avec cette denition assez formelle , tout squelette est un mot sur lalphabet des trois caract`eres (,
) et la virgule ,. Par exemple, le squelette de la gure precedente est ((, ), (, (, ))). Mais bien s ur tout mot
ne represente pas un squelette, comme par exemple le mot ((, , )).
On pref`erera neanmoins evidemment utiliser la representation geometrique des squelettes darbres.
1.3.3 Le squelette comme une classe dequivalence
Le passage dun arbre binaire sur des ensembles et 1 `a son squelette se denit sans probl`eme `a laide
dune induction structurelle (voir lexercice 1.3 page 24). Legalite des squelettes denit sur lensemble des
arbres binaires une relation dequivalence, qui denit ce quon appelle souvent la geometrie dun arbre
binaire.
1.3.4

Ecriture en Caml
Il sut pour travailler sur les squelettes en Caml de denir un nouveau type de la fa con suivante :
type squelette = Vide | Jointure of squelette * squelette ;;
1.4 Combinatoire des arbres et squelettes binaires
1.4.1 Nuds et feuilles
Nous commencons par un resultat assez simple :
Theor`eme 1.2
Soit c un arbre binaire, et : son squelette. Soit respectivement n, j, n

le nombre de nuds de c, le nombre


de feuilles de c, et le nombre de nuds de :. Alors n = n

= j 1.
4 Legalite n = n

est evidente.
Considerons larbre intermediaire entre c et :, cest-`a-dire oublions linformation portee par les nuds
et les feuilles. Par denition meme dun arbre binaire, tout nud de c a exactement 2 ls qui sont
soit une feuille soit un nouveau nud. Inversement, toute feuille et tout nud sauf la racine admet un
nud-p`ere. Ainsi 2n est le nombre de nuds et feuilles qui ne sont pas `a la racine de larbre, ou encore
2n = n + j 1, ce qui fournit legalite demandee. 3
On aurait pu aussi demontrer ce theor`eme `a laide dune induction structurelle :
4 Si c est une feuille, le resultat est clair car n = 0 et j = 1.
Sinon, c = (r, p, d). Par recurrence, on sait que les nombres n
g
et j
g
(resp. n
d
et j
d
) de nuds et
feuilles de p (resp. de d) verient n
g
= j
g
1 et n
d
= j
d
1. Or c a pour feuilles les feuilles de p et
celles de d, donc j = j
g
+j
d
et pour nuds les nuds de p et ceux de d `a quoi il faut ajouter le nud
r lui-meme, donc n = 1 +n
g
+n
d
. L`a encore on a bien n = 1 +j
g
1 +j
d
1 = j
g
+j
d
1 = j 1.
3
Personnellement, je pref`ere la premi`ere demonstration.
1.4.2 Profondeur et taille
Taille dun arbre ou dun squelette binaire
La notion de taille dun arbre varie selon les auteurs, helas : daucuns comptent les nuds et les feuilles,
dautres seulement les nuds, dautres encore seulement les feuilles. Mais gr ace au theor`eme 1.2 on passe
aisement de lune `a lautre.
Nous choisirons ici la denition suivante.
Denition 1.5 (Taille dun arbre) On appelle taille dun arbre binaire c et on note [c[ la taille de son
squelette, cest-`a-dire le nombre de ses nuds.
20 CHAPITRE 1. ARBRES BINAIRES
On calcule aisement le nombre de nuds et/ou de feuilles dun arbre binaire et la taille dun squelette ` a
laide de programmes recursifs tr`es simples.
Programme 1.3 Nombre de nuds, de feuilles dun arbre, taille dun squelette
(* calculs sur les arbres binaires *)
let rec nb_nuds = function
| Feuille(_) -> 0
| Nud(_,g,d) -> 1 + (nb_nuds g) + (nb_nuds d) ;;
let rec nb_feuilles = function
| Feuille(_) -> 1
| Nud(_,g,d) -> (nb_feuilles g) + (nb_feuilles d) ;;
(* calcul sur les squelettes binaires *)
type squelette = Vide | Jointure of squelette * squelette ;;
let rec taille = function
| Vide -> 0
| Jointure(g,d) -> 1 + (taille g) + (taille d) ;;
Encadrement de la profondeur dun arbre
On se rappelle que la profondeur dun arbre est la profondeur maximale de ses nuds et feuilles. Il est
donc clair quon dispose du
Lemme 1.1 Si / est la profondeur dun arbre binaire, son squelette est de profondeur / 1.
On se doute bien quun arbre binaire peut etre tr`es profond, il sut de descendre toujours ` a gauche `a
partir de la racine, par exemple. Il est plus interessant de prouver que pour une taille xee, sa profondeur
est minoree. La gure 1.5 montre deux squelettes de meme taille et de profondeurs minimale et maximale.
Cest ce que precise le theor`eme suivant :

`
`
`

`
`
`

`
`
`

`
`
`

Fig. 1.5: Taille et profondeur


Theor`eme 1.3
Soit : un squelette binaire non vide, de taille n et de profondeur /. Alors lg n| / n 1.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES 21
qui a pour corollaire le
Theor`eme 1.4
Soit c un arbre binaire non reduit `a une feuille, de taille n (il a donc n nuds) et de profondeur /. Alors
1 +lg n| / n.
Rappelons quen informatique lg designe le logarithme en base 2, cest-`a-dire que lg n = ln n, ln 2, et que
r| designe la partie enti`ere de r.
4 Nous demontrons le theor`eme 1.3 page precedente par induction structurelle.
Soit donc : = (p, d) un squelette. Notons n sa taille, / sa profondeur, et n
g
et /
g
(resp. n
d
et /
d
) la
taille et la profondeur de p (resp. de d).
Si p et d sont vides, n = 1 et / = 0 : lencadrement est correct.
Si p est vide, mais pas d, n = 1 + n
d
et / = 1 + /
d
. Or on sait par hypoth`ese de recurrence que
lg n
d
/
d
n
d
1. On en deduit que / n
d
= n 1. La majoration est bien prouvee. En outre,
puisque n
d
1, on a 1 +lg n
d
| = 1 + lg n
d
| = lg(2n
d
)| lg(n
d
+ 1)| = lg n|, ce qui fournit la
minoration souhaitee.
Si d est vide, mais pas p, on raisonne de fa con analogue.
Si enn ni d ni p nest vide, on a n = 1 + n
d
+ n
g
et / = 1 + max(/
d
, /
g
). La recurrence permet alors
decrire les majorations : / 1 + max(n
d
, n
g
) 1 + max(n 1, n 1) = n. Pour ce qui est de la
minoration, on ecrit dabord que /
d
lg n
d
| et /
g
lg n
g
|.
Mais legalite entre entiers naturels n = 1+n
d
+n
g
montre que n
d
ou n
g
est plus grand que (n1),2|.
Alors dapr`es lhypoth`ese de recurrence, max(/
d
, /
g
)
_
lg
n1
2
|
_
. Ainsi a-t-on / 1 +
_
lg
n1
2
|
_
.
Dans le cas o` u n est pair, n = 2j + 2, on a ecrit / 1 +lg(j + 1)| = lg(2(j + 1))| = lg n|.
Dans le cas o` u n est impair, n = 2j + 1, on a ecrit / 1 +lg j| = lg(2j)| = lg(2j + 1)| = lg n|.
Cette derni`ere egalite fait lobjet du lemme suivant. 3
Lemme 1.2 Pour tout entier naturel j 1, on a lg(2j + 1)| = lg(2j)|.
4 On a bien s ur linegalite lg(2j + 1)| lg(2j)|.
Posons / = lg j|. On a 2
k
j 2
k+1
1, do` u 2j + 1 2
k+2
1 < 2
k+2
. Ainsi lg(2j + 1) < / + 2,
et lg(2j + 1)| / + 1 = lg(2j)|, ce qui conclut. 3
Arbres complets
On appelle arbre complet un arbre de profondeur / et de taille n = 2
k
1. On trouvera dans la gure 1.6
page suivante les premiers arbres complets, ou plutot leurs squelettes.
Donnons une caracterisation des arbres complets.
Theor`eme 1.5
Un arbre binaire est complet si et seulement si toutes ses feuilles sont `a la meme profondeur.
4 Soit en eet c un arbre complet, de taille n = 2
k
1 et de profondeur /. On sait quil y a au
moins une feuille `a la profondeur /. Supposons un moment quune autre feuille soit `a une profondeur
strictement plus petite que /. On pourrait la remplacer par un nud do` u pendraient deux feuilles, de
profondeur au plus egale `a /. Larbre ainsi etendu serait de taille n + 1 (on ajoute un seul nud, on
retranche une feuille et en ajoute deux nouvelles), et toujours de profondeur /. Mais le theor`eme 1.4
arme / 1 + lg(n + 1) = 1 + /, ce qui fournit la contradiction souhaitee.
Montrons maintenant la reciproque : il sut pour cela de compter le nombre de nuds dun arbre dont
toutes les feuilles sont `a profondeur /. Ceci ne pose pas de probl`eme particulier, il sut de remarquer
que chaque nud interne a deux ls, et on trouve eectivement 2
k
1 nuds. 3
Remarquons quun arbre complet de taille n = 2
k
1 poss`ede n + 1 = 2
k
feuilles (de profondeur /).
22 CHAPITRE 1. ARBRES BINAIRES

`
`
`

`
`
`

`
`
`

`
`
`

`
`
`

>
>
>
>
>
>
>

`
`
`

`
`
`

Fig. 1.6: Squelettes darbres complets


Arbres equilibres
Un arbre sera dit equilibre quand ses feuilles se repartissent sur au plus deux niveaux seulement.
On verra plus loin dans ce cours linteret que peut avoir pour un arbre cet equilibrage : ce sera le crit`ere
essentiel decacite des algorithmes de recherche `a laide de structures darbres.
Theor`eme 1.6 (Caracterisation des arbres equilibres)
Un arbre binaire c de taille n et de profondeur / est equilibre si lune ou lautre des conditions equivalentes
suivantes est veriee :
(1) toute feuille de c est de profondeur / ou / 1 ;
(2) larbre obtenu `a partir de c en supprimant toutes ses feuilles de profondeur / est complet.
Un arbre equilibre verie la condition / = 1 +lg n|.
Bien entendu, quand on dit quon supprime des feuilles dun arbre, on entend par l` a que lon remplace
leurs nuds-p`eres par des feuilles.
4 Lequivalence entre (1) et (2) est `a peu pr`es evidente.
Montrons simplement quon a bien, pour un arbre equilibre c, la relation / = 1 +lg n|.
Soit pour cela c

larbre complet obtenu par suppression dans c des feuilles de profondeur /. La taille de
c

est n

, il poss`ede n

+ 1 feuilles, et donc 1 n n

+ 1. La profondeur de c

est / 1, donc
n

= 2
k1
1. Alors 1 n (2
k1
1) 2
k1
, et 2
k1
n 2
k
1. On a bien lg n| = / 1. 3
1.4.3 Denombrement des squelettes binaires
Il va de soi que denombrer les arbres binaires eux-memes na pas de sens, puisquaussi bien les ensembles
des valeurs qui habillent nuds et feuilles peuvent etre innis.
Il est donc naturel de sinteresser ici aux squelettes darbres binaires.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES 23
Une recurrence naturelle
Pour compter les squelettes de taille n, on sappuie sur le fait quun tel squelette est constitue dune racine
et de deux sous-arbres dont la somme des tailles vaut n 1, ce qui conduit `a une formule du genre :
o
n
=

o
i
o
n1i
,
o` u o
k
designe le nombre de squelettes de taille /. Une convention simpose donc : o
0
= 1. On en deduit
immediatement le theor`eme qui suit.
Theor`eme 1.7
Le cardinal o
n
de lensemble des squelettes binaires de taille n verie la recurrence
n 1, o
n
=
n1

i=0
o
i
o
n1i
, (1.1)
sous reserve de la convention o
0
= 1.
Le tableau suivant fournit les premiers termes de cette suite.
n 0 1 2 3 4 5 6 7 8 9 10
o
n
1 1 2 5 14 42 132 429 1430 4862 16796
Une formule plus close
Les informaticiens utilisent frequemment ce quils appellent des fonctions generatrices. Pour lexemple
qui nous interesse, il sagit de poser, pour tout (complexe) : (veriant certaines conditions dont nous
nous occuperons plus tard)
o(:) =
+

k=0
o
k
:
k
,
en esperant bien s ur quil ny a pas de probl`eme de convergence.
La recurrence qui fait lobjet de lequation 1.1 se traduit, dapr`es la denition du produit de Cauchy de
deux series enti`eres, et grace `a la condition o
0
= 1, par lequation
o(:) = 1 + :o
2
(:). (1.2)
(Le decalage n n 1 de la somme de 1.1 est traduit par le facteur : devant o
2
(:).)
On sinteresse donc naturellement `a lequation du second degre
A = 1 + :A
2
(1.3)
qui a pour solution A =
1

1 4:
2:
(on choisit cette solution pour que faisant tendre : vers 0 on
obtienne une limite egale `a o
0
= 1).
Si on demande, pour se rassurrer (il est vrai que pour linstant on sest vraiment peu soucie de rigueur
mathematique), `a Maple de calculer le developpement limite `a lordre 8 de A, on obtient :
A = 1 + : + 2 :
2
+ 5 :
3
+ 14 :
4
+ 42 :
5
+ 132 :
6
+ 429 :
7
+ 1430 :
8
+ O
_
:
9
_
. (1.4)
Ces considerations conduisent ` a prendre en quelque sorte le probl`eme `a lenvers.
Posons
)(:) =
_
1, si : = 0 ;
1

14z
2z
, si 0 ,= [:[ < 1,4.
On montre alors facilement que ) est de classe (

sur ]1,4, 1,4[, et quelle verie `a la fois lequation 1.3


et la condition )(0) = 1.
24 CHAPITRE 1. ARBRES BINAIRES
Or il se trouve que lon sait calculer son developpement limite `a lorigine ` a tout ordre. Les coecients de
ce developpement limite verieront alors necessairement lequation 1.1. Ce seront bien les termes de la
suite (o
n
) !
On trouve de cette fa con, au prix dun calcul que tout hypo-taupin sait mener sans diculte, le resultat
qui senonce sous la forme du
Theor`eme 1.8 (Denombrement des squelettes binaires)
Le nombre o
n
de squelettes binaires de taille n, qui est aussi le nombre darbres binaires portant n nuds
(internes) vaut
o
n
=
1
n + 1
_
2n
n
_
.
1.5 Exercices pour le chapitre 1
Exercice 1.1 Indexation dun arbre binaire

Ecrire une fonction Caml


indexation : (f,n) arbre_binaire -> (string,string) arbre_binaire
qui remplace toute linformation des nuds et feuilles de larbre fourni en argument par le mot binaire
correspondant ` a lindexation decrite `a la section 1.1.3 page 16.
Exercice 1.2 Sous-arbres de profondeur donnee

Ecrire une fonction Caml


liste_`a_profondeur : (f,n) arbre_binaire -> int -> (f,n) arbre_binaire list
qui prend en arguments un arbre binaire c et un entier n et qui renvoie la liste (eventuellement vide) de
tous les sous-arbres de c dont la racine est `a la profondeur n dans c.
Exercice 1.3 Calcul du squelette

Ecrire une fonction Caml


deshabille : (f,n) arbre_binaire -> squelette
qui prend en argument un arbre binaire et qui renvoie son squelette.
Exercice 1.4 Generation des squelettes darbres binaires

Ecrire une fonction Caml


engendre_`a_profondeur : int -> int -> squelette list
qui prend en arguments deux entiers n et j et qui renvoie la liste des squelettes de taille n et de profondeur
j. Dans le cas o` u n = 0, la valeur de j ne sera pas prise en compte.
En deduire une fonction
engendre : int -> squelette list
qui renvoie la liste de tous les squelettes dont la taille est fournie en argument.
Exercice 1.5 Squelette darbre complet de taille donnee

Ecrire une fonction Caml


squelette_complet : int -> squelette
qui prend en argument une taille n et renvoie le squelette complet de taille n sil existe, et declenche une
erreur sinon.
1.5. EXERCICES POUR LE CHAPITRE 1 25
Exercice 1.6 Test de completude

Ecrire une fonction Caml


est_complet : (f,n) arbre_binaire -> bool
qui prend en argument un arbre binaire et qui dit si oui ou non il est complet.
Exercice 1.7 Test dequilibrage

Ecrire une fonction Caml


est_equilibre : (f,n) arbre_binaire -> bool
qui prend en argument un arbre binaire et qui dit si oui ou non il est equilibre.
Chapitre 2
Parcours dun arbre
Ce court chapitre a pour but dexpliciter dierentes methodes utilisees pour lister les elements dun arbre
de facon non ambig ue, de telle sorte quon puisse reconstituer sa structure `a laide de cette seule liste.
On verra que la distinction faite dans les arbres binaires entre feuilles et nuds permet de resoudre
facilement ce probl`eme, quand au contraire il faut davantage deort pour donner une description non
ambig ue dun squelette darbre binaire.
Dans ce qui suit, on utilisera comme exemple privilegie celui de larbre qui est dessine dans la gure 2.1,
et dont les feuilles sont des entiers, les nuds des caract`eres.
a

`
`
`
2

`
`
`
d

`
`
`
5

`
`
`
6
Fig. 2.1: Un arbre pour lexemple
2.1 Parcours en largeur dabord
2.1.1 Description de lordre militaire
Le premier type de parcours que nous allons ecrire parat sans doute le plus naturel, meme si ce nest pas
le plus simple `a programmer.
Certains lappellent le parcours militaire dun arbre, puisquil fait penser ` a laxiome militaire bien connu
qui donne la priorite au plus ancien dans le grade le plus eleve. Il sut dimaginer quen descendant dans
larbre on descend dans la hierarchie, et quon dispose les ls du plus ancien au plus jeune, pour faire le
rapprochement.
27
28 CHAPITRE 2. PARCOURS DUN ARBRE
On peut egalement decrire cet ordre de parcours en disant quon liste les nuds et feuille par ordre
croissant de profondeur, et de gauche ` a droite pour une profondeur donnee. Cest pourquoi dautres
lappellent le parcours en largeur dabord.
Dans le cas de notre exemple de la gure 2.1 page precedente, ce parcours secrit donc :
c / c 1 2 3 d c 6 4 5.
La r`egle de reconstitution est simple : le premier element ecrit est la racine de larbre.
`
A chaque fois quon
dessine un nud on dessine les deux aretes pendantes qui en proviennent, et au fur et ` a mesure de la
lecture, on remplit les trous ainsi constitues, de gauche `a droite. . .
Reste `a programmer ce parcours en Caml.
2.1.2 Programmation Caml
Nous aurons tout dabord ` a denir le type qui correspond ` a la description de notre arbre. Il sagira dune
liste delements qui seront ou bien des feuilles ou bien des nuds, ce qui secrit par exemple ainsi en
Caml :
type (f,n) listing_darbre = F of f | N of n ;;
Le programme 2.1 permet alors de parcourir dans lordre militaire un arbre donne en argument.
Programme 2.1 Parcours dun arbre binaire en ordre militaire
let parcours_militaire a =
let rec parcours_rec nuds_pendants = match nuds_pendants with
| [] -> []
| Feuille(f) :: reste
-> (F f) :: (parcours_rec reste)
| Nud(n,g,d) :: reste
-> (N n) :: (parcours_rec (reste @ [ g ; d ]))
in
parcours_rec [a] ;;
On peut appliquer ce programme ` a notre arbre exemple, et voici le resultat :
#parcours_militaire exemple ;;
- : (int, char) listing_darbre list =
[N a; N b; N c; F 1; F 2; F 3; N d; N e; F 6; F 4; F 5]
En revanche, la reconstruction de larbre ` a partir dune telle liste est un probl`eme beaucoup plus ardu. . .
2.2 Parcours en profondeur dabord
Nous envisageons maintenant dautres methodes de parcours qui sont plus proches de la structure na-
turellement recursive des arbres, ce qui facilitera la programmation, et qui justie quon les pref`erera au
parcours militaire.
Lidee des trois parcours qui suivent est la meme, et nous fera descendre tout en bas de larbre sur sa
gauche avant de sinteresser aux feuilles plus ` a droite : cest ce quon appelle un parcours en profondeur
dabord.
2.2.1 Parcours prexe, inxe, suxe
Ces trois parcours sappuient sur la structure recursive des arbres : on applique recursivement le parcours
aux sous-arbres gauche et droit, et cest le moment o` u on liste le nud-p`ere qui caracterise ces trois
dierents parcours.
Dans le parcours prexe dun nud (n, p, d), on commence par lister n, puis on parcourt le sous-arbre p
et enn le sous-arbre d.
2.2. PARCOURS EN PROFONDEUR DABORD 29
On obtient ainsi, dans le cas de notre arbre exemple, la sequence
c / 1 2 c 3 d c 4 5 6.
Dans le parcours inxe dun nud (n, p, d), on commence par parcourir le sous-arbre gauche, puis on liste
n, et on termine par le sous-arbre d.
On obtient pour notre exemple la sequence
1 / 2 c 3 c 4 c 5 d 6.
Dans le parcours suxe (on dit aussi postxe), enn, on commence par parcourir les deux sous-arbres p
et d et on termine en listant n, ce qui, pour notre exemple, fournit la sequence
1 2 / 3 4 5 c 5 d c c.
2.2.2 Programmation en Caml
Ces trois parcours se pretent tout `a fait bien ` a une programmation recursive, et on obtient immediatement
le programme 2.2, qui met dailleurs en evidence la ressemblance de ces trois algorithmes de parcours.
Programme 2.2 Parcours dun arbre binaire en ordres prexe, inxe et suxe
let rec parcours_prefixe = function
| Feuille(f) -> [F f]
| Nud(n,g,d) -> [N n] @ (parcours_prefixe g) @ (parcours_prefixe d) ;;
let rec parcours_infixe = function
| Feuille(f) -> [F f]
| Nud(n,g,d) -> (parcours_infixe g) @ [N n] @ (parcours_infixe d) ;;
let rec parcours_suffixe = function
| Feuille(f) -> [F f]
| Nud(n,g,d) -> (parcours_suffixe g) @ (parcours_suffixe d) @ [N n] ;;
2.2.3 Probl`eme inverse
`
A la dierence du parcours en largeur dabord, il nest pas tr`es dicile de proceder `a la reconstitution
de larbre initial ` a partir de sa description prexe, comme le montre le programme 2.3.
Programme 2.3 Reconstitution dun arbre binaire ` a partir de sa description en ordre prexe
let recompose_prefixe l =
let rec recompose = function
| (F f) :: reste -> Feuille(f), reste
| (N n) :: reste -> let g, reste = recompose reste
in
let d, reste = recompose reste
in
Nud(n,g,d),reste
| [] -> failwith "Description prefixe incorrecte"
in
match recompose l with
| a,[] -> a
| _ -> failwith "Description prefixe incorrecte" ;;
Contrairement `a ce que certains simaginent parfois, le parcours suxe dun arbre ne fournit pas la
description symetrique du parcours inxe, et il ne sut pas dappliquer recompose prefixe au miroir
dune liste pour obtenir recompose suffixe.
Mais une approche directe conduit ` a la solution, qui consiste ` a construire larbre nal en faisant pousser
petit ` a petit larbre ` a partir de ses feuilles les plus basses `a gauche. Cest ce que fait le programme 2.4
page suivante.
30 CHAPITRE 2. PARCOURS DUN ARBRE
Programme 2.4 Reconstitution dun arbre binaire ` a partir de sa description en ordre suxe
let recompose_suffixe l =
let rec recompose ss_arbres liste = match ss_arbres,liste with
| a,(F f) :: reste
-> recompose (Feuille(f) :: a) reste
| d :: g :: a,(N n) :: reste
-> recompose (Nud(n,g,d) :: a) reste
| [ arbre ],[]
-> arbre
| _ -> failwith "Description suffixe incorrecte"
in
recompose [] l ;;
Il nous reste le probl`eme de la reconstitution dun arbre binaire ` a partir de sa description en ordre inxe.
Et l` a, surprise ! on saper coit que des trois methodes de parcours darbre que nous venons de decrire, cest
la seule qui soit ambig ue ! Cest-`a-dire quon peut tr`es bien trouver un autre arbre que celui qui a ete
propose dans la gure 2.1 page 27 avec pourtant le meme parcours inxe, `a savoir 1 / 2 c 3 c 4 c 5 d 6.
Par exemple, on veriera que larbre de la gure 2.2 a aussi ce parcours inxe.
c

`
`
`
2

`
`
`
3

`
`
`
5

`
`
`
6
Fig. 2.2: Ambig uite de la description inxe
2.3 Exercices pour le chapitre 2
Exercice 2.1 Reconstitution `a partir de lordre militaire

Ecrire une fonction Caml


recompose_militaire : (f,n) listing_darbre list -> (f, n) arbre_binaire
qui reconstitue un arbre binaire ` a partir de sa description en ordre militaire.
Exercice 2.2 Conversions prexe/suxe

Ecrire une fonction Caml qui ` a partir de la description prexe dun arbre produit la description suxe
(sans reconstruire larbre, bien s ur). Que pensez-vous de la fonction inverse ?
Chapitre 3
Arbres de recherche
3.1 Denition dun arbre binaire de recherche
3.1.1 Denition generale
On consid`ere un ensemble ordonne (1, _) de feuilles et une application : 1 N strictement croissante.
Cest-`a-dire que si )
1
)
2
alors ()
1
) < ()
2
).
Un arbre de recherche pour 1 est un arbre binaire sur les ensembles de feuilles et de nuds 1 et N qui
est ou bien une feuille ou bien un arbre (n, p, d) tel que pour toute feuille ) du sous-arbre gauche p on a
()) n et pour toute feuille ) du sous-arbre droit d on a n < ()).
Il est clair quon peut choisir pour valeur de n tout entier de lintervalle [`, i[, o` u ` est le maximum
des ()) sur les feuilles ) de p et i le minimum des ()) sur les feuilles ) de d. En general on choisit
n = `, mais nous verrons quil faut savoir saranchir de cette contrainte, et on veriera que tous les
resultats suivants nutilisent pas cette propriete.
Si on se rappelle la denition des parcours prexe, inxe et suxe dun arbre, on en deduit immedia-
tement par recurrence structurelle que les feuilles sont listees dans lordre croissant dans chacun de ces
parcours.
3.1.2 Cas particulier
On utilise le plus generalement 1 = N avec lidentite pour , et tous nos exemples seront construits sur
ce mod`ele.
On trouvera dans la gure 3.1 page suivante un premier exemple darbre de recherche sur N, qui nous
reservira dans la suite.
3.2 Recherche dun element
3.2.1 Position du probl`eme
Comme leur nom lindique, les arbres binaires de recherche servent `a la recherche dun element dune
famille : plus precisement, on se donne un ensemble de valeurs et on veut ecrire une fonction dapparte-
nance `a cet ensemble.
Une solution simple consiste `a utiliser une liste simple des elements de lensemble considere, et `a faire
une recherche dans cette liste, ce qui secrit en Caml comme dans le programme 3.1 page suivante.
Pas besoin dune reexion tr`es approfondie pour prouver que cet algorithme tourne en O(n), o` u n est la
taille de lensemble de valeurs-cibles.
31
32 CHAPITRE 3. ARBRES DE RECHERCHE
5

`
`
`
3

`
`
`
5

`
`
`
8

`
`
`
9

`
`
`
12
Fig. 3.1: Un arbre binaire de recherche sur N
Programme 3.1 Recherche sequentielle dans une liste
let rec recherche l x =
match l with
| [] -> failwith "

Element absent de la liste"


| t :: q -> t = x || recherche q x ;;
3.2.2 Recherche dans un arbre binaire de recherche
Les arbres binaires de recherche conduisent `a une solution tr`es simple du meme probl`eme, si on sait
construire un arbre dont lensemble des feuilles est lensemble de nos valeurs-cibles.
Cest ce que propose lalgorithme du programme 3.2.
Programme 3.2 Recherche dans un arbre binaire de recherche
let rec recherche phi arbre x =
match arbre with
| Feuille(f) -> x = f || failwith "

El ement absent"
| Nud(n,g,d) -> if phi x > n
then recherche phi d x
else recherche phi g x ;;
Bien s ur, ceci se simplie dans le cas dun arbre sur N et on obtient le programme plus simple 3.3 page
suivante.
3.2.3

Evaluation
Si on suit sur larbre donne dans la gure 3.1 la recherche de lelement 8, on se rend compte quon descend
dans larbre en choisissant `a chaque nud de descendre soit ` a droite soit ` a gauche par une comparaison :
ici, on descend successivement `a droite, `a gauche, `a droite et `a gauche.
Si on avait cherche la valeur 6 qui ne fait pas partie de lensemble des feuilles, on aurait utilise la descente
`a droite, `a gauche, `a gauche, et on serait arrive sur la feuille 7 ,= 6, ce qui decide de lechec.
On en deduit immediatement par une recurrence structurelle le theor`eme qui suit.
Theor`eme 3.1 (Co ut dune recherche dans un arbre binaire)
La recherche dans un arbre binaire de recherche se realise en un nombre de comparaisons au plus egal `a / +1,
o` u / est la profondeur de larbre.
3.3. STRUCTURE DYNAMIQUE DE RECHERCHE 33
Programme 3.3 Recherche dans un arbre binaire de recherche sur N
let rec recherche arbre x =
match arbre with
| Feuille(f) -> x = f || failwith "

El ement absent"
| Nud(n,g,d) -> if x > n then recherche d x
else recherche g x ;;
En utilisant les theor`emes 1.2 page 19 et 1.4 page 21, on en deduit le corollaire suivant.
Theor`eme 3.2 (Encadrement du co ut de la recherche dans un arbre binaire)
La recherche dun element dans un ensemble de n valeurs organisees en arbre binaire de recherche se realise
dans le cas le pire en un nombre c(n) de comparaisons qui verie :
2 +lg(n 1)| c(n) n.
Dans le cas particulier o` u larbre de recherche utilise est equilibre, on a legalite c(n) = 2 + lg(n 1)|,
ce qui garantit un co ut logarithmique pour notre recherche.
Toute la diculte est donc de construire un arbre equilibre de recherche, ce que nous etudions dans la
section suivante.
3.3 Structure dynamique de recherche
En pratique on veut maintenir une structure dynamique de lensemble des valeurs-cibles. Cest-`a-dire
quon veut pouvoir ajouter ou retrancher une valeur ` a cet ensemble. Il sagit donc pour nous dajouter
ou retrancher une feuille ` a un arbre binaire de recherche.
3.3.1 Ajout dun element
Lajout dun element r se realise un peu comme la recherche : on descend dans larbre jusqu` a arriver
`a une feuille. Ou bien cest lelement quon veut ajouter, il y est dej`a, et il ny a rien ` a faire. Ou bien
cest un element j dierent de r, ce qui signie que r nest pas encore dans larbre. On remplace alors la
feuille j par un arbre ((r), r, j) si (r) < (j) ou ((j), j, r) sinon.
Tout ceci se programme sans diculte en Caml : cest le programme 3.4.
Programme 3.4 Ajout dun element dans un arbre binaire de recherche
let rec ajout phi arbre x = match arbre with
| Feuille(y)
-> if x = y then Feuille(y)
else if phi x < phi y then Nud(phi x,Feuille(x),Feuille(y))
else Nud(phi y,Feuille(y),Feuille(x))
| Nud(n,g,d)
-> if phi x > n then Nud(n,g,ajout phi d x)
else Nud(n,ajout phi g x,d) ;;
La fonction ajout ainsi ecrite renvoie le nouvel arbre resultat. Il est immediat quelle tourne en O(/) o` u
/ est la profondeur de larbre.
3.3.2 Suppression dun element
La suppression dun element dans un arbre binaire de recherche na bien s ur de sens que si cet element
gure parmi les feuilles, sans quoi il ne se passe rien.
Il sut a priori de rechercher lelement considere, et de couper la feuille correspondante de larbre. Puis
on remplace le nud-p`ere par le fr`ere gauche ou droit qui subsiste.
34 CHAPITRE 3. ARBRES DE RECHERCHE
5

`
`
`
3

`
`
`
5

`
`
`
9

`
`
`
12
Fig. 3.2: Arbre obtenu par suppression du 7
Reprenant notre arbre de la gure 3.1 page 32, si on supprime lelement 7, on remplace le p`ere de la
feuille 7 par son ls droit, et on obtient bien un arbre de recherche qui repond au probl`eme quon setait
pose, comme le montre la gure 3.2.
Supprimons maintenant de ce nouvel arbre lelement 5. On remplace donc son p`ere par son fr`ere gauche,
et on obtient le nouvel arbre de la gure 3.3.
5

`
`
`
3

`
`
`
9

`
`
`
12
Fig. 3.3: Arbre obtenu par suppression du 7 puis du 5
Larbre obtenu est bien un arbre de recherche, et la suppression a bien ete eectuee. En revanche on
saper coit que la propriete cosmetique qui etait jusqu` a present conservee nest plus veriee : les valeurs
des nuds ne sont plus necessairement egales `a la feuille maximale du sous-arbre gauche. Ainsi, la racine
de notre arbre vaut-elle toujours 5, qui ne gure pourtant plus dans larbre. Mais on la dej`a dit, ce nest
pas un probl`eme.
On programme aisement cette suppression en Caml : cest le programme 3.5 page suivante.
Ce programme tourne l`a encore en O(/), o` u / est la profondeur de larbre.
3.3.3 Application au tri
Il sut de combiner les programmes precedents pour obtenir un tri.
On construit pour commencer un arbre constitue dune seule feuille contenant le premier element de la
liste ` a trier, auquel on ajoute successivement les autres elements. Il sut de lire les feuilles par un parcours
recursif de larbre pour obtenir la liste triee. Le co ut de cet algorithme de tri sobtient en sommant les
co uts des ajouts successifs. Si on peut sassurer que larbre reste equilibre tout au long de lalgorithme,
on aura un co ut de lordre de
lg 1 + lg 2 + + lg n = O(nlg n);
3.4. EXERCICES POUR LE CHAPITRE 3 35
Programme 3.5 Suppression dun element dans un arbre binaire de recherche
let rec suppression phi arbre x = match arbre with
| Feuille(y)
-> if x = y then failwith "Arbre vide"
else Feuille(y)
| Nud(n,g,d)
-> if phi x > n then
if d = Feuille(x) then g
else Nud(n,g,suppression phi d x)
else if g = Feuille(x) then d
else Nud(n,suppression phi g x,d) ;;
Programme 3.6 Tri `a laide darbres binaires de recherche
let tri_par_arbre_de_recherche liste =
let rec liste_feuilles = function
| Feuille(f) -> [ f ]
| Nud(n,g,d) -> (liste_feuilles g) @ (liste_feuilles d)
in
let rec ajoute_feuilles arbre l = match l with
| [] -> arbre
| t :: q -> ajoute_feuilles (ajout (function x -> x) arbre t) q
in
match liste with
| [] -> []
| t :: q -> liste_feuilles (ajoute_feuilles (Feuille t) q) ;;
sinon, il se pourrait que chaque ajout se fasse pour un co ut lineaire, et on retomberait alors sur un co ut
global quadratique, cest-` a-dire en O(n
2
).
3.3.4 Le probl`eme de lequilibrage
Tout le probl`eme est donc bien dassurer que larbre reste equilibre, ce qui nest pas garanti par nos
algorithmes trop rudimentaires. Il sut pour sen convaincre de considerer larbre obtenu par ajout
successif des elements 1, 2, . . . , 8, qui est tout sauf equilibre !
3.4 Exercices pour le chapitre 3
Exercice 3.1 Une autre structure darbre de recherche
Une autre solution pour les arbres de recherche consiste `a placer linformation ` a chercher aux nuds. On
ecrit donc le type
type a arbre_de_recherche =
| Vide
| Nud of a * a arbre_de_recherche * a arbre_de_recherche ;;
Ce ne sont plus les valeurs des feuilles du sous-arbre gauche qui seront plus petites que la racine, mais
celles de ses nuds.

Ecrire pour cette nouvelle structure les fonctions de recherche, dajout et de suppression dun element.
Exercice 3.2 Balance et equilibrage
On reprend la representation des arbres binaires de recherche denie dans lexercice precedent.

Ecrire la fonction mesure equilibrage qui prend un arbre de type a arbre_de_recherche et qui
renvoie en resultat un arbre de type (a * int) arbre_de_recherche obtenu en ajoutant ` a chaque
nud lentier /
g
/
d
o` u /
g
est la profondeur de son ls gauche et /
d
la profondeur de son ls droit. On
utilisera par convention 1 comme profondeur de Vide.
Un arbre sera dit AVL si on a toujours /
g
/
d
1, 0, +1.
36 CHAPITRE 3. ARBRES DE RECHERCHE
Exercice 3.3 Taille dun arbre AVL

Ecrire et demontrer les inegalites qui constituent lencadrement de la profondeur / dun arbre AVL en
fonction de sa taille n.
On montre quon peut utiliser ces arbres comme arbres de recherches, ce qui assure des operations ele-
mentaires (ajout et suppression dun element) toutes de co ut logarithmique, meme dans le pire des cas.
Il faut pour cela denir des fonctions dajout et de suppression dun element qui conserve la propriete
des arbres AVL.
Exercice 3.4 Arbres 23
Un arbre de recherche 23 est un arbre o` u linformation recherchee est aux feuilles, dont tout nud a 2
ou 3 ls, et dont toutes les feuilles sont `a la meme hauteur.
Proposer un type Caml pour ces arbres de recherche, et ecrire la fonction de recherche correspondante.
Montrer que la profondeur / des feuilles et le nombre n de ces feuilles verient un encadrement que lon
precisera.
L`a encore, on peut construire des algorithmes dajout et de suppression dun element sur un arbre 23,
ce qui en fait une structure de recherche `a co ut toujours logarithmique.
Chapitre 4
Tri et tas
4.1 Generalites
4.1.1 Files de priorite
Une le de priorite est un arbre binaire dont les feuilles et les nuds sont des entiers. Cest pourquoi,
dans la suite de ce chapitre, on ne parlera plus de nuds et de feuilles mais de nuds internes et de
nuds externes. On dessinera tous ces nuds de la meme facon : avec un cercle. La taille de la le sera
le nombre total de ses nuds, internes ou externes.
Mais une le de priorite doit egalement verier la propriete suivante : tout p`ere est plus grand que chacun
de ses ls. Si lon pref`ere, on peut dire que le long de tout chemin qui descend dans larbre de la racine
`a lun de ses nuds, on lit une suite decroissante dentiers.
On notera quen revanche il ny a pas de condition imposee sur des fr`eres.

Evidemment la racine dune
le de priorite est le plus grand entier present dans tout larbre.
La gure 4.1 montre un exemple de le de priorite.
12

`
`
`
3

`
`
`
7

`
`
`
6

Fig. 4.1: Une le de priorite


4.1.2 Tas
Un tas est un cas particulier de le de priorite, qui est equilibre, et dont les nuds externes de profondeur
maximale sont tous le plus `a gauche possible. On parle souvent dans cette situation darbre parfait.
On trouvera dans la gure 4.2 page suivante un exemple de tas.
En utilisant les resultats generaux etudies dans les chapitres precedents, on peut demontrer le theor`eme 4.1
page suivante.
37
38 CHAPITRE 4. TRI ET TAS
12

`
`
`
3

`
`
`
7

`
`
`
3

Fig. 4.2: Un tas


Theor`eme 4.1 (Proprietes des tas)
Soit T un tas de taille n. Sa profondeur / verie legalite / = lg n|. Parmi ses nuds externes, il y a
exactement n + 1 2
k
nuds `a profondeur egale `a /, les autres sont de profondeur / 1.
4 La profondeur dun arbre equilibre est connue depuis le theor`eme 1.6 page 22.
Comme larbre obtenu `a partir de notre tas en supprimant les nuds externes de profondeur / est complet
et de profondeur /1, il poss`ede 2
k
1 nuds, qui sont les nuds internes du tas et ses nuds externes
de profondeur / 1. Cest dire quil y a bien n (2
k
1) nuds externes de profondeur /. 3
4.1.3 Implementation des tas `a laide de tableaux
On pourrait bien entendu utiliser une structure darbre pour representer les tas, en denissant un type
Caml de la facon suivante :
type tas = Vide | Nud of int * tas * tas ;;
Il se trouve quil existe une implementation beaucoup plus simple et ecace, `a laide dun bete tableau.
Si en eet on veut decrire un tas, le plus simple est assurement de donner sa description dans un parcours
militaire. Il ny a pas dambig uite dans la mesure o` u seule la derni`ere ligne du tas peut etre incompl`ete.
Precisons ceci, en denissant une numerotation des nuds dun tas de fa con recursive : la racine est
numerotee 0. Si i est le numero dun nud interne, ses nuds ls gauche et droit sont numerotes respec-
tivement 2i + 1 et 2i + 2.
On trouvera dans la gure 4.3 le tas de lexemple precedent avec les numeros de chacun des nuds `a sa
gauche.
0 12

1 9

3 5

7 4

/
/
/ `
`
`
8 3

/
/
/ `
`
`
4 7

`
`
`
`
2 6

5 1

/
/
/ `
`
`
6 3

Fig. 4.3: Un tas avec sa numerotation des nuds


4.2. PERCOLATION 39
Le theor`eme 4.2 montre que la numerotation que nous venons de denir correspond eectivement ` a un
parcours militaire du tas.
Theor`eme 4.2 (Numerotation des nuds dun tas)
Pour la numerotation denie plus haut, on enum`ere les entiers de 0 `a n 1 en numerotant les nuds dans
lordre du parcours militaire dun tas de taille n.
4 Nous proc`edons par recurrence sur la profondeur / du tas.
Le resultat est clair pour un tas de profondeur nulle.
Supposons le acquis pour les tas de profondeur au plus egale `a / (/ 0) et considerons un tas T de
profondeur / + 1.
La denition dun tas montre quen supprimant dans T tous les nuds (externes) de profondeur / + 1,
on obtient un arbre complet, de taille 2
k+1
1. On a dit quil possedait 2
k
nuds externes, et dapr`es
lhypoth`ese de recurrence, elles portent les numeros 2
k
1 `a 2
k+1
2.
Posons : i 2i + 1 et j : i 2i + 2.
et j sont bien s ur injectives, et (N) et j(N) sont clairement disjoints par raison de parite.
Enn, pour tout entier i, (i), j(i), (i + 1) et j(i + 1) sont, dans cet ordre, des entiers consecutifs.
Il sut pour conclure dobserver que (2
k
1) = 2
k+1
1. La / + 1-i`eme ligne du tas porte donc des
numeros consecutifs qui debutent eectivement `a lentier qui suit 2
k+1
2, dernier numero porte par la
ligne de profondeur /. 3
On va donc implementer un tas de taille n sous la forme dun vecteur dentiers, et on usera des analogies
suivantes :
2i+1
est le ls gauche de
i
,
2i+2
est son ls droit,
(i1)/2
est son p`ere.
4.2 Percolation
4.2.1 Description de lalgorithme
On appelle percolation loperation qui consiste ` a reorganiser un arbre sous forme dun tas sachant que
les deux sous-arbres de la racine etaient dej`a des tas : il sagit donc de mettre `a sa place la racine.
Par exemple, on peut considerer larbre de la gure 4.4, et, apr`es percolation, on obtient le tas T de la
gure 4.6 page suivante.
6

`
`
`
3

`
`
`
7

`
`
`
1

Fig. 4.4: Un arbre ` a percoler


Lalgorithme de percolation est simple : on descend la valeur r inappropriee de la racine (dans notre
exemple r = 6) en cherchant sa nouvelle place dans larbre. Si r est plus grand que ses deux ls, cest
quil a trouve sa place, et on a ni, sinon, on echange r avec le plus grand de ses deux ls.
On trouvera dans la gure 4.5 page suivante letape intermediaire de la percolation, o` u on a entoure dun
carre la position courante de r.

Evidemment larbre obtenu nest un tas que dans la mesure o` u les deux ls gauche et droit de la racine
de larbre initial etaient eux-memes des tas : on na fait que replacer au bon endroit la racine.
40 CHAPITRE 4. TRI ET TAS
9

6
8

`
`
`
3

`
`
`
7

`
`
`
1

Fig. 4.5: Letape intermediaire de la percolation


9

`
`
`
3

`
`
`
7

`
`
`
1

Fig. 4.6: Le tas obtenu par percolation


4.2. PERCOLATION 41
4.2.2 Programmation
Utilisons limplementation par vecteur dun tas pour programmer cette percolation, ce qui fait lobjet des
programmes 4.1 et 4.2, dans les deux versions recursive et iterative.
Programme 4.1 Percolation recursive
let percolation_recursive tas =
let fils_gauche i = try tas.(2 * i + 1) with _ -> -1
and fils_droit i = try tas.(2 * i + 2) with _ -> -1
and echange i j =
let a = tas.(i)
in
(tas.(i) <- tas.(j) ; tas.(j) <- a)
in
let rec percole_encore i =
let x,fg,fd = tas.(i),(fils_gauche i),(fils_droit i)
in
if x < fg && fg >= fd then
begin
echange i (2 * i + 1) ;
percole_encore (2 * i + 1)
end
else
if x < fd && fd >= fg then
begin
echange i (2 * i + 2) ;
percole_encore (2 * i + 2)
end
in
percole_encore 0 ;
tas ;;
Programme 4.2 Percolation iterative
let percolation_iterative tas =
let n = vect_length tas
and x = tas.(0)
and ix = ref 0
and fils_gauche i = try tas.(2 * i + 1) with _ -> -1
and fils_droit i = try tas.(2 * i + 2) with _ -> -1
in
while fils_gauche !ix > x || fils_droit !ix > x do
if fils_gauche !ix > fils_droit !ix then
begin
tas.(!ix) <- tas.(2 * !ix + 1) ;
ix := 2 * !ix + 1
end
else
begin
tas.(!ix) <- tas.(2 * !ix + 2) ;
ix := 2 * !ix + 2
end
done ;
tas.(!ix) <- x ;
tas ;;
On aura note comment dans les deux programmes on evite des comparaisons fastidieuses entre
indices et n pour verier quon nest pas sur un nud externe avant de calculer les ls en
comptant sur lerreur qui serait declenchee par un acc`es incorrect aux elements du vecteur et en
renvoyant alors une valeur, 1, inferieure `a tous les autres elements et qui termine donc la percolation.
En outre, pour le programme iteratif, on a choisi, plutot que de proceder `a des echanges dans le vecteur,
de ne recopier la valeur de x que tout `a la n, quand sa position nale a ete trouvee.
42 CHAPITRE 4. TRI ET TAS
4.2.3

Evaluation
Il est bien evident que notre algorithme de percolation tourne en O(/), o` u / est la profondeur de notre
arbre, donc en O(lg n), puisquil sagit dun tas.
4.2.4 Application : creation dun tas
Reorganisation

Etant donne un vecteur quelconque de n entiers naturels, on souhaite ecrire une procedure reorganise
qui permute ses elements de telle sorte que le vecteur resultant soit la representation dun tas.
represente a priori un arbre. On va, en commen cant par les niveaux de plus grande profondeur, remonter
en sassurant au fur et ` a mesure que les sous-arbres dont la racine est ` a profondeur i sont des tas. Pour
passer `a la profondeur i 1, il sura de percoler tous les nuds de cette profondeur.
Observons toutefois quil nest pas necessaire de percoler les nuds externes, qui ne posent evidemment
pas de probl`eme.
Or nous savons depuis le theor`eme 4.1 page 38 quels sont les nuds internes et les nuds externes, et il
sut donc de percoler `a rebours tous les nuds dont les indices varient de n,2| 1 `a 0. Cest ce que
fait le programme 4.3.
Programme 4.3 Reorganisation dun arbre en tas
let percolation tas i j =
let x = tas.(i)
and ix = ref i
and fils_gauche i = if 2 * i + 1 < j then tas.(2 * i + 1) else -1
and fils_droit i = if 2 * i + 2 < j then tas.(2 * i + 2) else -1
in
while fils_gauche !ix > x || fils_droit !ix > x do
if fils_gauche !ix > fils_droit !ix then
begin
tas.(!ix) <- tas.(2 * !ix + 1) ;
ix := 2 * !ix + 1
end
else
begin
tas.(!ix) <- tas.(2 * !ix + 2) ;
ix := 2 * !ix + 2
end
done ;
tas.(!ix) <- x ;
tas ;;
let reorganise tas =
let n = vect_length tas
in
for i = (n - n/2 - 1) downto 0 do percolation tas i n done ;
tas ;;
On a reecrit ici la fonction de percolation, en demandant que percolation tas i j ne percole
que le sous-arbre de tas dont la racine porte le numero i et dont les nuds sont de numeros
strictement plus petit que j.

Evaluation
Lalgorithme de reorganisation que nous avons ecrit a un co ut quil nest pas dicile devaluer, puisquon
applique la percolation ` a n,2 reprises pour des profondeurs qui ne depassent pas lg n. Il tourne donc en
O(nlg n).
4.3. LE TRI PAR LES TAS 43
4.3 Le tri par les tas
4.3.1 Programmation
Nous avons ici une nouvelle fa con de trier un vecteur de n entiers naturels. Une fois reorganise en tas,
le maximum du tableau est simplement la racine
0
de larbre. On lechange avec le dernier element
n1
,
et il ny a plus qu` a recommencer avec le sous-tableau [0..n 2]. En outre, il nest pas necessaire de
reorganiser compl`etement ce sous-tableau : il sut de proceder `a une percolation.
Cest ce qui conduit `a lalgorithme dit tri par tas ou, en anglais, heap sort, qui fait lobjet du pro-
gramme 4.4.
Programme 4.4 Le tri par tas (heap sort)
let tri_par_tas tas =
let n = vect_length tas
and echange p q =
let a = tas.(p)
in
( tas.(p) <- tas.(q) ; tas.(q) <- a )
in
reorganise tas ;
for i = n - 1 downto 1 do
echange 0 i ;
percolation tas 0 i
done ;
tas ;;
4.3.2

Evaluation
Nous avons tout ce quil faut pour evaluer le co ut de ce nouvel algorithme de tri. Nous avons dit que la
reorganisation en tas avait un co ut en O(nlg n) ; il reste ensuite n 1 percolations `a realiser, toutes de
co ut majore par lg n. Lalgorithme propose est donc bien un nouvel algorithme de tri en O(nlg n), ce que
nous savons etre optimal.
Chapitre 5
Arbres n-aires et expressions
arithmetiques
5.1 Arbres n-aires
5.1.1 Denition
Les arbres n-aires sont une generalisation des arbres binaires : on autorise cette fois les nuds `a posseder
un nombre quelconque de ls. On peut denir rigoureusement ces arbres de la facon suivante.
Denition 5.1 (Arbres n-aires) Soit 1 et des ensembles de valeurs de feuilles et de nuds. On denit
recursivement un arbre n-aire sur ces ensembles en disant que toute feuille ) 1 est un arbre n-aire, et que
si n , si j est un entier, j 1, et si enn c
1
, c
2
, . . . , c
p
sont des arbres n-aires, alors (n, c
1
, . . . , c
p
) est
aussi un arbre n-aire. Dans ce dernier cas on dit que n est le nud p`ere de chacun des c
i
, que les c
i
sont des
sous-arbres fr`eres, ls du nud n.
On represente bien entendu graphiquement les arbres n-aires, dune fa con analogue ` a ce quon a fait pour
les arbres binaires, comme sur lexemple de la gure 5.1, qui represente larbre
(n
1
, (n
2
, )
1
, )
2
, )
3
), (n
3
, (n
4
, )
4
, )
5
))).
n
1
n
2
n
3
f
1
f
2
f
3
n
4
f
4
f
5
Fig. 5.1: Un exemple darbre n-aire
Notons quil nest pas demande aux nuds dun arbre n-aire davoir tous le meme nombre de ls.
45
46 CHAPITRE 5. ARBRES -AIRES ET EXPRESSIONS ARITHM

ETIQUES
5.1.2 Implementation
Une solution pour implementer les arbres n-aires en Caml consiste `a denir un nouveau type o` u les nuds
contiennent leur information propre et une liste darbres binaires :
type (f,n) arbre_n_aire =
| Feuille of f
| Nud of n * (f,n) arbre_n_aire list ;;
Larbre de lexemple de la gure 5.1 page precedente secrit alors
Nud("n1", [ Nud("n2", [ Feuille("f1"); Feuille("f2"); Feuille("f3") ]) ;
Nud("n3", [ Nud("n4" ,
[ Feuille("f4"); Feuille("f5") ] ) ] )
] )
5.1.3 Proprietes
On ne peut denir de la meme fa con que pour les arbres binaires la taille dun arbre n-aire, car il ny a
plus de relation automatique entre nombre de feuilles et nombre de nuds. Il conviendra donc de preciser
ces deux nombres `a chaque fois quon voudra parler de la taille dun arbre n-aire.
Programme 5.1 Nombre de nuds et feuilles dun arbre n-aire
let rec nb_feuilles = function
| Feuille(_) -> 1
| Nud(_,liste_fils)
-> it_list (fun n a -> n + (nb_feuilles a))
0
liste_fils ;;
let rec nb_nuds = function
| Feuille(_) -> 0
| Nud(_,liste_fils)
-> it_list (fun n a -> n + (nb_nuds a))
1
liste_fils ;;
En revanche, on denit de fa con analogue la profondeur dun nud ou dune feuille de larbre, ce qui fait
lobjet du programme 5.2.
Programme 5.2 Profondeur dun arbre n-aire
let rec profondeur = function
| Feuille(_) -> 0
| Nud(_,liste_fils)
-> 1 + it_list (fun M a -> max M (profondeur a))
0
liste_fils ;;
Nous avons utilise ici la fonction it list, qui fait partie de la biblioth`eque standard de Caml.
Son type est : (a -> b -> a) -> a -> b list -> a.
Lappel it_list f a [ b1 ; b2 ; ... ; bn ] sevalue en
f(. . . (f(f(a, b
1
), b
2
) . . .), b
n
)
5.1.4 Parcours dun arbre n-aire
On denit tr`es naturellement les parcours prexe et suxe dun arbre n-aire, et on peut ecrire facilement
les fonctions Caml correspondantes, ce qui fait lobjet du programme 5.3 page suivante.
En revanche, il est bien evident que cela naurait pas de sens de parler de parcours inxe : o` u placer la
racine dun arbre ` a 3 ls ?
5.2. EXPRESSIONS ARITHM

ETIQUES 47
Programme 5.3 Parcours prexe et suxe dun arbre n-aire
let rec parcours_prefixe = function
| Feuille(f) -> [ F f ]
| Nud(n,liste_fils)
-> it_list (fun l a -> l @ (parcours_prefixe a))
[N n]
liste_fils ;;
let rec parcours_suffixe = function
| Feuille(f) -> [ F f ]
| Nud(n,liste_fils)
-> (it_list (fun l a -> l @ (parcours_suffixe a))
[]
liste_fils) @ [ N n ] ;;
Un autre probl`eme apparat au moment de reconstituer un arbre ` a partir de son parcours prexe (ou
suxe, cest le meme probl`eme). En eet, si on reprend larbre exemple de la gure 5.1 page 45, son
parcours prexe secrit :
n
1
, n
2
, )
1
, )
2
, )
3
, n
3
, n
4
, )
4
, )
5
.
Mais on verie sans peine que cest aussi le parcours de larbre represente dans la gure 5.2.
n
1
n
2 f
3
n
3
f
1
f
2
n
4 f
5
f
4
Fig. 5.2: Un autre arbre n-aire de meme parcours prexe
On peut neanmoins lever lambigute, `a condition que tout nud portant une meme valeur n
k
donnee
ait le meme nombre de ls. Ce nombre de ls sappelle larite du nud, et on suppose donc quil existe
une fonction
arite : n -> int
Nous ecrivons par exemple la reconstitution de larbre `a partir de son parcours prexe dans le pro-
gramme 5.4 page suivante.
5.2 Expressions arithmetiques
5.2.1 Une denition
Nous allons maintenant donner une denition rigoureuse dune expression arithmetique. Nous con-
sid`ererons des expressions construites ` a laide des operations habituelles (addition, soustraction, mul-
tiplication, division et elevation `a une puissance), des constantes reelles, des variables, et des fonctions
(nous nous limiterons ici `a lexponentielle, son logarithme, et les sinus et cosinus).
Denition 5.2 (Expressions arithmetiques) On consid`ere un ensemble O doperations `a 2 arguments, par
exemple O = +, , , ,, ; un ensemble ( de constantes, par exemple ( = R; un ensemble 1 de variables,
48 CHAPITRE 5. ARBRES -AIRES ET EXPRESSIONS ARITHM

ETIQUES
Programme 5.4 Reconstitution dun arbre n-aire `a partir de son parcours prexe
let recompose_prefixe_naire arite l =
let rec recompose = function
| (F f) :: reste -> Feuille(f), reste
| (N n) :: reste
-> let liste_fils,reste = cherche_fils (arite n) reste
in
Nud(n,liste_fils),reste
| [] -> failwith "Description prefixe incorrecte"
and cherche_fils nb_fils reste =
if nb_fils = 0 then [],reste
else
let fils,reste = recompose reste
in
let autres_fils,reste = cherche_fils (nb_fils-1) reste
in
fils :: autres_fils,reste
in
match recompose l with
| a,[] -> a
| _ -> failwith "Description prefixe incorrecte" ;;
par exemple 1 = , 1, . . . , A, Y, 7 ; et un ensemble T de fonctions `a 1 argument, par exemple T =
sin, cos, ln, exp. On denit lensemble / des expressions arithmetiques correspondantes de facon recursive :
toute constante est une expression arithmetique : ( /;
toute variable est une expression arithmetique : 1 /;
si c O et si n et sont des expressions arithmetiques, alors (nc) est aussi une expression arithmetique ;
si ) T et si n est une expression arithmetique, alors )(n) est aussi une expression arithmetique.
5.2.2 Syntaxe concr`ete et syntaxe abstraite
En Caml, on introduit ainsi tr`es naturellement le type suivant :
type (c,v,o,f) expression =
| Constante of c
| Variable of v
| Terme of (c,v,o,f) expression * o * (c,v,o,f) expression
| Application of f * (c,v,o,f) expression ;;
Ainsi lexpression 2 + sin
2
(3 + A) est lecriture mathematique habituelle de lexpression arithmetique
(2 + (sin((3 + A)) 2)). Notons quon a lhabitude en mathematiques de se dispenser de certaines
parenth`eses quimpose pourtant notre denition.
Notre expression correspond ` a une valeur Caml de type (float,char,char,fonction) expression, o` u
le type fonction serait deni par
type fonction = Sin | Cos | Exp | Ln ;;
La valeur Caml secrirait :
Terme(Constante(2.0),
+,
Terme(Application(Sin,Terme(Constante(3.0),+,Variable(X))),
^,
Constante(2.0))) ;;
Comme on le constate aisement, passant de la denotation mathematique habituelle (la syntaxe concr`ete),
`a la notation Caml (la syntaxe abstraite), on complique grandement lecriture des expressions, mais on a
realise lessentiel de leur analyse, ce qui permet ensuite des manipulations bien plus faciles.
5.2. EXPRESSIONS ARITHM

ETIQUES 49
5.2.3 Expressions et arbres
Arbre dune expression arithmetique
On peut naturellement associer ` a une expression arithmetique un arbre n-aire : lensemble des valeurs
des feuilles est ( 1, lensemble des valeurs des nuds est O T. Ceci sexprime en Caml de la fa con
suivante :
type nud = F of fonction | O of char ;;
type feuille = N of float | V of char ;;
Notons que nous sommes ici dans le cas favorable o` u il existe une fonction darite (voir la section
precedente), ce qui permet de mettre bijectivement en relation les arbres dexpressions et leurs parcours
prexes ou suxes.
On peut facilement ecrire les fonctions de conversion dune expression en arbre et inversement, ce qui fait
lobjet du programme 5.5.
Programme 5.5 Conversions arbres dexpression/expressions arithmetiques
let rec arbre_dexpression = function
| Constante x -> Feuille (N x)
| Variable v -> Feuille (V v)
| Terme(a,o,b) -> let g = arbre_dexpression a
and d = arbre_dexpression b
in
Nud(O o, [ g ; d ])
| Application(f,a) -> Nud(F f, [ (arbre_dexpression a) ]) ;;
let rec expression_darbre = function
| Feuille (N x) -> Constante(x)
| Feuille (V x) -> Variable(x)
| Nud(O o, [ e ; f ])
-> Terme(expression_darbre e,o,expression_darbre f)
| Nud(F f, [ e ]) -> Application(f,expression_darbre e)
| _ -> failwith "Ce nest pas un arbre dexpression" ;;

Evaluation et impression dune expression arithmetique


On a dej`a vu en premi`ere annee comment evaluer une expression donnee par son ecriture suxe. On aura
remarque combien le programme ecrit alors ressemble `a celui qui permet la reconstitution dun arbre ` a
partir de son parcours suxe, et on naura pas eu la navete de sen etonner.
Plus generalement, larbre dune expression permet facilement devaluer lexpression ou encore de lim-
primer en ecriture prexe, inxe ou suxe.
Occupons nous pour commencer de levaluation. Il faut ici simplement ajouter ` a la semantique decrite
en premi`ere annee ce qui concerne les variables. En bref, il faut expliquer ce quon veut obtenir dans
levaluation dune variable. Pour cela, il nous faut denir la notion denvironnement dune expression.
Denition 5.3 (Environnement devaluation) On appelle environnement devaluation des variables dune
expression arithmetique sur les ensembles (, 1, T et O toute application de 1 dans (.
En Caml, un environnement devaluation des variables sera simplement une liste associative, cest-` a-dire
une liste de couples variables/valeurs de la forme (c:
i
, c|
i
). La biblioth`eque Caml fournit la fonction
assoc qui permet de chercher la valeur associee `a une variable, et quon pourrait dailleurs ecrire soi-meme
comme suit.
let rec assoc v env = match env with
| [] -> failwith "Variable absente de lenvironnement"
| (var,val) :: q -> if v = var then val else assoc v q ;;
Denition 5.4 (Semantique dune expression arithmetique) Soit / lensemble des expressions arithme-
tiques sur les ensembles (, 1, T et O. Soit un environnement devaluation des variables. On suppose quest
50 CHAPITRE 5. ARBRES -AIRES ET EXPRESSIONS ARITHM

ETIQUES
associee `a tout ) T une fonction

) de ( dans lui-meme, et `a tout o O une fonction o de (
2
dans (. On
denit alors recursivement levaluation dune expression :
si c (, alors cc|(c) = c ;
si 1, alors cc|() = () ;
si ) T, si n est une expression, alors cc|()(n)) =

)(cc|(n)) ;
si o O, si n et sont deux expressions, alors cc|((no)) = o(cc|(n), cc|()).
Levaluation est alors realisee par le programme 5.6.
Programme 5.6

Evaluation des expressions arithmetiques
let rec evaluation environnement = function
| Constante x -> x
| Variable v -> assoc v environnement
| Terme(a,o,b) -> let x = evaluation environnement a
and y = evaluation environnement b
in
( match o with
| + -> x +. y
| - -> x -. y
| / -> x /. y
| * -> x *. y
| ^ -> power x y
| _ -> failwith "Operation inconnue" )
| Application(f,a) -> let x = evaluation environnement a
in
( match f with
| Sin -> sin x
| Cos -> cos x
| Exp -> exp x
| Ln -> log x ) ;;
Les impressions prexe et suxe ne posent pas de probl`eme particulier. Rappelons que lexistence dune
fonction darite permet de se dispenser de tout parenthesage. On trouvera ces fonctions dans le pro-
gramme 5.7 page suivante.
Pour limpression inxe, en revanche, il est indispensable decrire des parenth`eses. La suppression des
parenth`eses quon necrit pas habituellement est un probl`eme dicile, qui necessite quon discute des
priorites des operateurs. Cest une diculte analogue quon rencontre quand on veut programmer le
passage de lecriture inxe ` a la syntaxe abstraite des expressions. Nous nous contenterons ici decrire
toutes les parenth`eses, y compris celles qui sont superues, ce qui est fait dans le programme 5.8 page 52.
5.3 Derivation formelle
5.3.1 Derivation guidee par la structure darbre
On peut egalement utiliser la structure quon a introduite ici des expressions arithmetiques pour ecrire
un programme de derivation formelle, utilisant les formules classiques de derivation :
(n + )

= n

(n )

= n

(n)

= n

+ n

(n,)

= n

, n

,
2
(n
v
)

= n
v

ln n + n
(v1)
n

(ln n)

= n

,n
(exp n)

= n

exp n (sin n)

= n

cos n (cos n)

= n

sin n
Traduisant mot ` a mot ces r`egles, on obtient facilement le programme 5.9 page 52.
Reprenant lexpression c = 2 + sin
2
(3 + A), on trouve comme derivee par rapport ` a A lexpression
0 + sin
2
(3 + A) 0 ln sin(3 + A) + sin
(21)
(3 + A) 2 (0 + 1) cos(3 + A). La derivee par rapport
`a Y donne lexpression 0 + sin
2
(3 + A) 0 ln sin(3 + A) + sin
(21)
(3 + A) 2 (0 + 0) cos(3 + A).
Il va de soi que ces expressions ne correspondent pas tout `a fait `a notre attente, et il convient de les
simplier au moins un peu, ce qui fait lobjet de ce qui suit.
5.3. D

ERIVATION FORMELLE 51
Programme 5.7 Impressions prexe et suxe des expressions
let impression_prefixe expr =
let a = arbre_dexpression expr
in
let rec imprime = function
| Feuille(N x) -> print_float x ; print_char
| Feuille(V x) -> print_char x ; print_char
| Nud(O o, [ e ; f ])
-> print_char o ; print_char ; imprime e ; imprime f
| Nud(F f, [ e ])
-> ( match f with
| Sin -> print_string "sin"
| Cos -> print_string "cos"
| Exp -> print_string "exp"
| Ln -> print_string "ln" ) ;
print_char ; imprime e
| _ -> failwith "Erreur impossible"
in
imprime a ;;
let impression_suffixe expr =
let a = arbre_dexpression expr
in
let rec imprime = function
| Feuille(N x) -> print_float x ; print_char
| Feuille(V x) -> print_char x ; print_char
| Nud(O o, [ e ; f ])
-> imprime e ; imprime f ; print_char o ; print_char
| Nud(F f, [ e ])
-> imprime e ;
( match f with
| Sin -> print_string "sin"
| Cos -> print_string "cos"
| Exp -> print_string "exp"
| Ln -> print_string "ln" ) ;
print_char
| _ -> failwith "Erreur impossible"
in
imprime a ;;
52 CHAPITRE 5. ARBRES -AIRES ET EXPRESSIONS ARITHM

ETIQUES
Programme 5.8 Impression inxe des expressions
let impression_infixe expr =
let a = arbre_dexpression expr
in
let rec imprime = function
| Feuille(N x) -> print_float x
| Feuille(V x) -> print_char x
| Nud(O o, [ e ; f ])
-> print_char ( ;
imprime e ; print_char ;
print_char o ;
print_char ; imprime f ;
print_char )
| Nud(O o, [ e ; f ])
-> print_char ( ;
imprime e ; print_char o ; imprime f ;
print_char )
| Nud(F f, [ e ])
-> ( match f with
| Sin -> print_string "sin"
| Cos -> print_string "cos"
| Exp -> print_string "exp"
| Ln -> print_string "ln" ) ;
print_char ( ; imprime e ; print_char )
| _ -> failwith "Erreur impossible"
in
imprime a ;;
Programme 5.9 Derivation formelle des expressions arithmetiques
let rec derivation expr x =
match expr with
| Constante(_) -> Constante(0.0)
| Variable(v) -> Constante(if v = x then 1.0 else 0.0)
| Terme(u,o,v)
-> let u = derivation u x
and v = derivation v x
in
( match o with
| + -> Terme(u,+,v)
| - -> Terme(u,-,v)
| * -> Terme(Terme(u,*,v),+,Terme(u,*,v))
| / -> Terme( Terme(u,/,v),
-,
Terme(Terme(u,*,v),
/,
Terme(v,^,Constante(2.0))))
| ^ -> Terme(expr,*,
Terme(Terme(v,*,Application(Ln,u)),
+,
Terme(v,*,Terme(u,/,u)))) )
| Application(f,u)
-> let u = derivation u x
in
match f with
| Sin -> Terme(u,*,Application(Cos,u))
| Cos -> Terme(u,*,
Terme(Constante(-1.0),
*,
Application(Sin,u)))
| Exp -> Terme(u,*,expr)
| Ln -> Terme(u,/,u) ;;
5.3. D

ERIVATION FORMELLE 53
5.3.2 Simplication : une premi`ere approche
Nous nous contentons ici dune simplication elementaire des expressions. Une simplication plus com-
pl`ete des expressions poserait de redoutables probl`emes de denition et nous nen parlerons pas davantage.
On obtient ainsi le programme 5.10 page suivante.
Et voil` a le resultat, sur le meme exemple que precedemment. On veriera sur cette session Caml que
toutes les simplications quon pouvait esperer ont bien ete realisees. En revanche, il ne fallait pas compter
sur la simplication de 2 sinc cos c en sin(2c), bien s ur. On pourrait quand meme essayer de reconnatre
dans une dierence legalite des deux termes, ou dans un quotient ou un produit legalite des facteurs, ce
qui permettrait des simplications supplementaires.
54 CHAPITRE 5. ARBRES -AIRES ET EXPRESSIONS ARITHM

ETIQUES
Programme 5.10 Simplication des expressions algebriques
let rec simplification = function
| Terme(u,+,v)
-> let u,v = (simplification u), (simplification v)
in
( match u,v with
| Constante(0.0),_ -> v
| _,Constante(0.0) -> u
| Constante(x),Constante(y) -> Constante(x +. y)
| _,_ -> Terme(u,+,v) )
| Terme(u,-,v)
-> let u,v = (simplification u), (simplification v)
in
( match u,v with
| _,Constante(0.0) -> u
| Constante(x),Constante(y) -> Constante(x -. y)
| _,_ -> Terme(u,-,v) )
| Terme(u,*,v)
-> let u,v = (simplification u), (simplification v)
in
( match u,v with
| Constante(0.0),_ -> Constante(0.0)
| _,Constante(0.0) -> Constante(0.0)
| Constante(1.0),_ -> v
| _,Constante(1.0) -> u
| Constante(x),Constante(y) -> Constante(x *. y)
| _,_ -> Terme(u,*,v) )
| Terme(u,/,v)
-> let u,v = (simplification u), (simplification v)
in
( match u,v with
| Constante(0.0),_ -> Constante(0.0)
| _,Constante(1.0) -> u
| Constante(x),Constante(y) -> Constante(x /. y)
| _,_ -> Terme(u,/,v) )
| Terme(u,^,v)
-> let u,v = (simplification u), (simplification v)
in
( match u,v with
| Constante(0.0),_ -> Constante(0.0)
| Constante(1.0),_ -> Constante(1.0)
| _,Constante(1.0) -> u
| Constante(x),Constante(y) -> Constante(power x y)
| _,Constante(-1.0) -> Terme(Constante(1.0),/,u)
| _,_ -> Terme(u,^,v) )
| Application(Exp,u)
-> let u = simplification u
in
( match u with
| Constante(x) -> Constante(exp(x))
| _ -> Application(Exp,u) )
| Application(Ln,u)
-> let u = simplification u
in
( match u with
| Constante(x) -> Constante(log(x))
| _ -> Application(Ln,u) )
| Application(Sin,u)
-> let u = simplification u
in
( match u with
| Constante(x) -> Constante(sin(x))
| _ -> Application(Sin,u) )
| Application(Cos,u)
-> let u = simplification u
in
( match u with
| Constante(x) -> Constante(cos(x))
| _ -> Application(Cos,u) )
| expr -> expr ;;
5.4. EXERCICES POUR LE CHAPITRE 5 55
Quoi quil en soit voici ce quon obtient :
#impression_infixe (simplification (derivation expr X) ) ;;
(sin((3.0 + X)) * (2.0 * cos((3.0 + X))))- : unit = ()
#impression_infixe (simplification (derivation expr Y) ) ;;
0.0- : unit = ()
5.4 Exercices pour le chapitre 5
Exercice 5.1 Reconstitution dun arbre n-aire `a partir du parcours suxe

Ecrire le programme qui permet de reconstituer un arbre n-aire `a partir de son parcours suxe, supposant
connue la fonction darite.
Exercice 5.2 Impression inxe des expressions

Ecrire un programme Caml qui g`ere une impression inxe des expressions sans parenth`eses inutiles.
On rappelle que est prioritaire par rapport ` a et ,, eux-memes prioritaires par rapport ` a + et .
Deuxi`eme partie
Automates
57
Chapitre 6
Automates nis deterministes ou
non deterministes
6.1 Automates nis deterministes
6.1.1 Presentation informelle
Un automate est un syst`eme qui reagit `a des stimuli. Ces stimuli peuvent etre representes de dierentes
mani`eres.
`
A chaque stimulus, lautomate peut se bloquer, ou bien passer de letat o` u il etait avant reception
`a un nouvel etat, voire rester dans le meme etat.
Nous nous interesserons dans ce cours tout particuli`erement aux automates qui reagissent aux caract`eres
dun alphabet. Si donc on consid`ere un automate dans un certain etat initial, on lui fait lire une chane
de caract`eres, cest-`a-dire quon le fait reagir successivement aux dierents caract`eres qui composent la
chane. Le processus peut sinterrompre avant la n de la chane : ou bien lautomate sest bloque, ou
bien tous les caract`eres sont lus, et on peut dire que lautomate est passe de son etat initial ` a un nouvel
etat, qui est evidemment fonction de la chane lue.
En general, on numerote les etats possibles de lautomate.
Lautomate est dit ni sil na quun nombre ni detats et si lalphabet (lensemble des stimuli) est lui
aussi ni.
Les transitions dun etat ` a lautre, sous leet des stimuli, sont representees par des `eches entre les etats
etiquetees par le nom du stimulus.
La gure 6.1 represente un automate ni.
1 2
33
b
a
b
a
a
b
Fig. 6.1: Un premier exemple dautomate ni deterministe
Cet automate a trois etats, notes 1, 2 et 3.
1 est letat initial (designe par le petit eclair).
3 est un etat dit etat dacceptation ou etat nal (il peut y en avoir plusieurs), puisquil est entoure de
deux cercles.
59
60 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
Partant de letat 1, la lecture de la chane c//c nous fait passer successivement aux etats 2, 3, 1 et enn 2.
Comme ce nest pas un etat nal, on dit que la chane nest pas reconnue par lautomate.
Si on lisait la chane c/cc, lautomate se bloquerait ` a larrivee du c dans letat 3. On dit que la chane
nest pas reconnue par lautomate `a cause du blocage, bien quon soit dans un etat nal.
Enn, la chane //ccc/ est reconnue par cet automate, et on peut montrer que lensemble des chanes
reconnues est lensemble de toutes les chanes sur les deux lettres c et / qui nissent exactement par
c/ : letat 2 correspond au moment o` u on a lu un c et o` u on attend un / pour passer `a letat nal 3 ;
letat 1 correspond ` a ce qui arrive quand apr`es avoir bien lu c/, on tombe sur un /, et que tout est donc
`a refaire. . .
6.1.2 Presentation mathematique
De facon plus rigoureuse on peut donner la
Denition 6.1 (Automates nis deterministes) Soit / un alphabet ni. Un automate ni deterministe
(en abrege afd) est un quadruplet (Q,
0
, T, ) o` u Q est un ensemble ni delements appeles etats,
0
est un
element de Q, appele etat initial, T est une partie non vide de Q, dont les elements sont appeles etats nals,
et o` u est une fonction de Q/ dans Q.
On notera que est une fonction, et non une application : elle nest pas necessairement denie pour tout
couple (, c) Q/.
Lautomate etant xe, si pour c / et pour deux etats et

on a (, c) =

, on dira quil existe une


transition de vers

sur c et on notera
c

.
Reprenant lautomate represente dans la gure 6.1 page precedente, on peut choisir / = c, /, Q =
1, 2, 3,
0
= 1, T = 3, et est denie par le tableau suivant :
c (, c)
1 a 2
1 b 1
2 a 2
2 b 3
3 a 2
3 b 1
6.1.3 Transitions et calculs
Denitions
On a dit quon notait
c

si (, c) =

: il sagit l` a dune transition toute banale. On peut generaliser


`a ce quon appellera un calcul.
Denition 6.2 (Mots) Soit / un alphabet ni. Un mot est une suite nie eventuellement vide delements
de /. Le mot vide est note . Un mot n de taille n est constitue des elements successifs n
0
, n
1
, . . . , n
n1
.
Lensemble des mots sur / est note /

.
Denition 6.3 (Calculs dun afd) Soit / un alphabet ni et (Q,
0
, T, ) un afd sur cet alphabet. Soit
et

deux etats de lautomate et n un mot non vide de longueur n. On dira quun calcul de lautomate fait
passer de `a

`a la lecture de n si il existe n 1 etats


1
, . . . ,
n1
tels que

w
0

1
w
1

w
n2

n1
w
n1

.
On notera ce calcul :
w

. Par convention on a

pour tout etat Q.
6.2. IMPL

EMENTATION EN CAML DUN AFD 61


Proprietes
On demontre aisement les deux proprietes suivantes :
(n
1
, n
2
) /
2
, (
1
,
2
,
3
) Q
3
, (
1
w
1

2
et
2
w
2

3
)
1
w
1
.w
2

3
,
o` u on a note n
1
.n
2
le mot resultat de la concatenation des mots n
1
et n
2
;
n /

, (,

) Q
3
, (
w

et
w

,
ce qui traduit le determinisme de lautomate.
6.1.4 Langage reconnu par un automate ni deterministe
On est en mesure de denir rigoureusement les mots reconnus par un afd.
Denition 6.4 (Mots acceptes par un afd)

Etant donne un alphabet / et un afd (Q,
0
, T, ), un mot
n /

est dit reconnu ou accepte par lautomate si il existe T tel que


0
w
. Dans les autres cas,
cest-`a-dire si lautomate se bloque pendant la lecture de n ou sil sarrete dans un etat non nal, on dit que
le mot est rejete par lautomate, ou encore quil nest pas reconnu.
Le langage dun afd est lensemble des mots quil reconnat : on le notera 1().
Notons dores et dej`a que deux automates distincts peuvent denir le meme langage. On veriera par
exemple que les automates de la gure 6.2 denissent le meme langage que celui de la gure 6.1 page 59.
Le premier dentre eux comporte en eet un etat (4) inaccessible, cest-`a-dire un etat tel que pour aucun
mot n on nait
0
w
. Le second ne comporte pas detat inaccessible, mais denit pourtant le meme
langage.
1 2
3 4
1 2
3 4 3 3
b a
a
b
a
a
b
b
b
b
a
b
a
b
b
a
Fig. 6.2: Deux automates pour un meme langage
Un afd est dit minimal si tout afd qui denit le meme langage a au moins autant detats. Il va de soi
quon pref`ere en general manipuler des afd minimaux. . .
6.2 Implementation en Caml dun afd
Pour representer les afd on pourra denir le type des etats de la facon suivante :
type etat_de_afd =
{ mutable est_terminal : bool ;
transitions : arrivee vect }
and arrivee = Blocage | OK of etat_de_afd ;;
62 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
Si q est un etat, q.est_terminal dit si oui ou non T, et q.transitions est un vecteur de 256
valeurs, correspondant aux 256 caract`eres dans le codage ascii. q.transitions.(i) vaudra Blocage sil
ny a pas de transition ` a partir de sur le caract`ere c de code ascii i, ou bien OK(q) si (, c) =

.
On programme aisement la reconnaissance dune chane, ce qui fait lobjet du programme 6.1.
Programme 6.1 Reconnaissance dune chane par un afd
exception

Echec ;;
type etat_de_afd =
{ mutable est_terminal : bool ;
transitions : arrivee vect }
and arrivee = Blocage | OK of etat_de_afd ;;
let lit_transition_afd q1 c =
match q1.transitions.(int_of_char c) with
| Blocage -> raise

Echec
| OK(q2) -> q2 ;;
let ecrit_transition_afd q1 c q2 =
q1.transitions.(int_of_char c) <- OK(q2) ;;
let reconna^t etat_de_depart cha^ne =
let rec transite etat i n =
if i = n then etat.est_terminal
else transite (lit_transition_afd etat cha^ne.[i]) (i+1) n
in
try
transite etat_de_depart 0 (string_length cha^ne)
with _ -> false ;;
Il est clair que cet algorithme de reconnaissance tourne en O(n), o` u n est la longueur de la chane de
caract`eres testee.
Indiquons au passage comment, par exemple, on entre la description de lafd de la gure 6.1 page 59.
let q1 = { est_terminal = false ; transitions = make_vect 256 Blocage }
and q2 = { est_terminal = false ; transitions = make_vect 256 Blocage }
and q3 = { est_terminal = true ; transitions = make_vect 256 Blocage } ;;
ecrit_transition_afd q1 a q2 ;;
ecrit_transition_afd q1 b q1 ;;
ecrit_transition_afd q2 a q2 ;;
ecrit_transition_afd q2 b q3 ;;
ecrit_transition_afd q3 a q2 ;;
ecrit_transition_afd q3 b q1 ;;
Lappel reconna^t q0 cha^ne renvoie true si et seulement si la chane est reconnue par lautomate dont
letat initial est q0.
6.3 Automates nis non deterministes
6.3.1 Presentation informelle
On trouvera dans la gure 6.3 page suivante un premier exemple dautomate ni non deterministe (afnd
en abrege).
On remarque quelques dierences avec les afd, ` a savoir essentiellement :
certaines `eches sont etiquetees par la lettre : il sagit de ce quon appellera donc des -transitions,
et lautomate passera tout seul en cas de besoin dun etat `a un autre etat par la voie dune telle
transition ;
on peut trouver plusieurs `eches issues dun meme etat et etiquetees de la meme lettre : cest ce
qui fait toute lambigute dun afnd, et explique quon parle de non-determinisme.
6.3. AUTOMATES FINIS NON D

ETERMINISTES 63
1 2
3 4
55
b
a
a
a
b
b

b
b
Fig. 6.3: Un automate ni non deterministe
On veriera sur cet exemple que les mots /, /// ou encore /cc sont reconnus par cet automate : les
parcours detats correspondants sont 15, 1415 ou 1555, 12345. On aura note quil ny a plus unicite. . .
6.3.2 Denition mathematique
Denition dun afnd
Denition 6.5 (Automates nis non deterministes) Soit / un alphabet ni. Un automate ni non deter-
ministe (en abrege afnd) est un quintuplet (Q,
0
, T, , ) o` u Q est un ensemble ni delements appeles etats,

0
est un element de Q, appele etat initial, T est une partie non vide de Q, dont les elements sont appeles
etats nals, et o` u (resp. ) est une application de Q/ (resp. Q) dans T(Q), ensemble des parties de Q.
On aura note quune transition ` a partir dun etat sur le caract`ere c se calcule par : (, c) est
lensemble des etats auxquels on peut aboutir par cette transition, et dans le cas o` u il ny a pas de
transition ` a partir de sur c.
Dune fa con analogue, () designe lensemble des etats atteints `a partir de par une -transition.
Certains auteurs sautorisent, pour les afnd, plusieurs etats initiaux, q
1
, q
2
, . . . , q
k
. Il sut,
pour se ramener `a notre denition, dajouter un unique etat initial q
0
et des -transitions de q
0
vers chacun des q
i
, 1 i k. Cest pourquoi nous avons choisi de considerer systematiquement
quil ny a quun etat initial pour chacun de nos automates.
Fermeture dun etat
Pour denir proprement les calculs queectue un afnd il nous faut maintenant denir ce quon appelle
la fermeture dun etat par -transition.
Denition 6.6 (Fermeture par -transition) Soit / un alphabet ni et (Q,
0
, T, , ) un afnd sur cet
alphabet. Pour tout etat Q on denit sa fermeture par -transition et on notera () la plus petite partie
de Q contenant et veriant :
_
q

(q)
(

) ().
De facon evidente, on montre le
Theor`eme 6.1 (Calcul des fermetures)
Soit /un alphabet ni et (Q,
0
, T, , ) un afnd sur cet alphabet. Soit un etat xe. On denit recursivement
les parties (1
n
) de Q en posant 1
0
= , et, pour n 1, 1
n
= 1
n1

K
n1
(

). La suite (1
n
) est
croissante et stationnaire (pour linclusion), de limite egale `a ().
64 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
4 La suite (1
n
) est evidemment croissante, et, comme Q est ni, elle est stationnaire. Soit 1 sa
limite. Bien s ur 1.
Soit

1. Il existe un indice j 0 tel que

1
p
. Mais alors (

) 1
p+1
1, et 1 verie donc
bien la propriete requise par (), ce qui montre que () 1.
Reciproquement, on montre par recurrence sur n que les 1
n
sont inclus dans (). 3
Intuitivement, () designe lensemble de tous les etats (dont ) qui peuvent etre atteints `a partir de
apr`es un nombre ni quelconque de -transitions.
Calculs dun afnd
On consid`ere ici un afnd (Q,
0
, T, , ) sur un alphabet /.

Etant donnes deux etats


1
et
2
et un caract`ere c, on notera
1


2
quand
2
(
1
), et on notera

1
c

2
quand il existe

1
(
1
) et un etat

2
(

1
, c) tels que
2
(

2
). Cest dire que dans les
transitions, on passera gratuitement par autant de -transitions quil est necessaire.
Avec ces denitions, on peut reprendre la meme denition que pour les afd de la notation
1
w

2
. Mais
cette fois lautomate netant plus deterministe, il ny a pas unicite de letat darrivee
2
.
Ici encore, un mot n est dit accepte par lautomate sil existe un etat nal T tel que
0
w
. Le
langage de lautomate est toujours lensemble des mots acceptes par lui.
Comparaison des afd et des afnd
Linteret des automates non deterministes est quil est beaucoup plus facile en general de concevoir un
afnd quun afd pour un langage donne, ce quon etudiera de plus pr`es dans le chapitre suivant. Lexemple
des mots sur c, / qui se terminent par c/ est explicite `a cet egard. Autant il nest pas evident que lafd
de la gure 6.1 page 59 convient, autant il est clair que lafnd de la gure 6.4 est une solution.
1 2 33
a b
b
a
Fig. 6.4: Un afnd pour les mots qui nissent par c/
En revanche il est beaucoup moins simple de programmer le fonctionnement dun afnd, et surtout, lal-
gorithme obtenu est beaucoup moins ecace. Cest ce quon va voir maintenant.
6.4 Implementation en Caml dun afnd
Dune fa con analogue ` a ce quon a pu faire pour un afd, on est amene `a denir le type suivant pour les
etats dun afnd :
type etat_de_afnd =
{ mutable est_final : bool ;
mutable table : etat_de_afnd list vect ;
mutable table_epsilon : etat_de_afnd list ;
numero : int } ;;
On a ajoute un numero ` a chaque etat, ce qui nous servira plus tard. En outre cette fois si transition il y
a sur un caract`ere donne, on fournit la liste des etats accessibles par cette transition. De meme y a-t-il
une liste des etats accessibles par -transitions.
La programmation de la reconnaissance, comme nous lavons dej`a dit, est plus dicile. Nous utiliserons
quelques fonctions auxiliaires simples qui font lobjet du programme 6.2 page ci-contre.
6.4. IMPL

EMENTATION EN CAML DUN AFND 65


Programme 6.2 Quelques fonctions utiles
let rec it_list f a l = match l with
| [] -> a
| t :: q -> it_list f (f a t) q ;;
let rec list_it f l a = match l with
| [] -> a
| t :: q -> f t (list_it q a) ;;
let rec exists predicat l = match l with
| [] -> false
| t :: q -> (predicat t) || (exists predicat q) ;;
let mem_etat q ql =
let n = q.numero
in
exists (function x -> x.numero = n) ql ;;
let rec union_etats ql1 ql2 = match ql2 with
| [] -> ql1
| q :: r -> let ql = union_etats ql1 r
in
if mem_etat q ql then ql
else q :: ql ;;
let union_listes_etats ll = it_list union_etats [] ll ;;
Nous avons ecrit les fonctions mem_ etat et union_ etats qui testent lappartenance dun etat ` a
une liste detats et calculent la reunion de deux listes detats sans utiliser la fonction de com-
paraison standard de Caml (=) qui pourrait boucler sur les structures recursives eventuellement
cycliques que sont les etats dun automate. Cest pour cela que nous avons utilise la numerotation des
etats.
Notons toutefois que les fonctions it_list, list_it, exists et map sont predenies en Caml.
Precisons que it_list f a [ x0 ; x1 ; ... ; xk ] sevalue en )(. . . ()()cr
0
)r
1
) . . .)r
k
, alors que
list_it f [ x0 ; x1 ; ... ; xk ] a sevalue en )r
0
()r
1
(. . . ()r
k
c) . . .)).
Maintenant, on peut ecrire la reconnaissance, qui utilise bien s ur une fonction de calcul des fermetures
par -transitions.
Nous avons ecrit pour cela une fonction de recherche dun point xe. pt_fixe attend deux
arguments : une fonction f : a -> a list et une liste l : a list et calcule la plus petite
liste l qui contient l et les images par f de chacun des elements de l.
Cet algorithme de reconnaissance prend en argument la liste des etats de depart (le plus souvent ce sera
[ q0 ]) et la chane `a reconnatre.
Remarquons que sa complexite est sans commune mesure avec lalgorithme utilise pour les automates
deterministes.
Indiquons pour nir comment, par exemple, on entre lautomate de la gure 6.3 page 63 en Caml :
let q1 = { numero = 1 ; est_final = false ;
table = make_vect 256 [] ; table_epsilon = [] }
and q2 = { numero = 2 ; est_final = false ;
table = make_vect 256 [] ; table_epsilon = [] }
and q3 = { numero = 3 ; est_final = false ;
table = make_vect 256 [] ; table_epsilon = [] }
and q4 = { numero = 4 ; est_final = false ;
table = make_vect 256 [] ; table_epsilon = [] }
and q5 = { numero = 5 ; est_final = true ;
table = make_vect 256 [] ; table_epsilon = [] } ;;
q1.table_epsilon <- [ q2 ] ;
q2.table_epsilon <- [ q3 ] ;
66 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
Programme 6.3 Reconnaissance dune chane par un afnd
type etat_de_afnd =
{ mutable est_final : bool ;
mutable table : etat_de_afnd list vect ;
mutable table_epsilon : etat_de_afnd list ;
numero : int } ;;
let lit_transition_afnd q1 c = q1.table.(int_of_char c) ;;
let ecrit_transition_afnd q1 c q2 =
let i = int_of_char c
in
q1.table.(i) <- union q1.table.(i) [ q2 ] ;;
let pt_fixe f l =
let rec etape res `a_faire traites =
match `a_faire with
| [] -> res
| q :: r -> if mem_etat q traites then
etape res r traites
else
let l = f q
in
etape (union_etats l res)
(union_etats l `a_faire)
(q :: traites)
in
etape l l [] ;;
let calcule_fermeture ql =
pt_fixe (function q -> q.table_epsilon) ql ;;
let reconnaissance_afnd etats cha^ne =
let n = string_length cha^ne
in
let rec avance ql i =
if i = n then ql
else
let c = int_of_char cha^ne.[i]
in
let ql =
union_listes_etats
(map
(function q -> q.table.(c))
ql)
in
avance (calcule_fermeture ql) (i+1)
in
let ql = avance (calcule_fermeture etats) 0
in
exists (function q -> q.est_final) ql ;;
6.5. D

ETERMINISATION DUN AFND 67


ecrit_transition_afnd q1 a q3 ;;
ecrit_transition_afnd q3 a q4 ;;
ecrit_transition_afnd q4 a q5 ;;
ecrit_transition_afnd q1 b q5 ;;
ecrit_transition_afnd q1 b q4 ;;
ecrit_transition_afnd q2 b q3 ;;
ecrit_transition_afnd q4 b q1 ;;
ecrit_transition_afnd q5 b q5 ;;
6.5 Determinisation dun afnd
On sinteresse ici au probl`eme de la determinisation dun automate ni non deterministe . Il sagit de
determiner un automate ni deterministe qui reconnat le meme langage : 1() = 1().
6.5.1 Algorithme de determinisation
Un exemple
Considerons lautomate non deterministe de la gure 6.5 qui reconnat bien s ur tous les mots sur
lalphabet c, / qui se terminent par la chane c/c/.
1 2 3 4 55
a b a b
b
a
Fig. 6.5: Un afnd pour les mots nissant par c/c/
Nous allons construire pas ` a pas un automate deterministe qui reconnat le meme langage. Ce nouvel
automate aura un ensemble detat egal `a T(Q), ensemble des parties de lensemble des etats de .
Pour chaque partie A =
1
, . . . ,
k
de Q, on denira les transitions de `a partir de A de la facon
suivante : `a la lecture dun caract`ere c, on aboutira ` a un etat qui est lensemble Y de tous les etats de Q
quon atteint ` a partir dun quelconque des etats qui composent A.
Pour notre exemple, le tableau suivant fournit quelques transitions de :
etat de depart c est lu / est lu
1 1, 2 1
1, 2 1 1, 3
2, 3 4 3
1, 2, 3 1, 2, 4 1, 3
2, 3, 4, 5 4 3, 5
. . . . . . . . .
Si on ecrit le tableau complet, il y aura 2
5
= 32 lignes `a ecrire. . . mais toutes ne sont pas utiles, car
certaines parties de Q ne correspondent pas ` a des etats de accessibles `a partir de letat initial 1.
On va donc reconstituer le tableau en ecrivant les lignes necessaires au fur et ` a mesure des besoins,
cest-`a-dire de leur apparition dans les deux colonnes de droites.
etat de depart c est lu / est lu
1 1, 2 1
1, 2 1 1, 3
1, 3 1, 2, 4 1
1, 2, 4 1, 2 1, 3, 5
1, 3, 5 1, 2, 4 1
68 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
Cette fois on na plus que 5 etats ! Les etats nals de sont ceux qui contiennent un etat nal de , ici
il sagit du seul etat 1, 3, 5.
On peut dessiner lautomate obtenu, ce qui est fait dans la gure 6.6.
1 12
13
124 135 135
b
a
b b
a
b
a
a
a
b
Fig. 6.6: Lautomate determinise
Eectivement, il est beaucoup moins aise de deviner sur cet afd le langage reconnu. . .
Explicitation de lalgorithme
Soit = (Q,
0
, T, , ) un afnd sur lalphabet /. On construit un afd sur le meme alphabet qui a
pour ensemble detats T(Q), pour etat initial lensemble (
0
). Ses etats nals sont les parties de Q qui
contiennent au moins un etat nal de .
Voici comment on construit les transitions de : soit A =
1
, . . . ,
k
un etat de lautomate et un
caract`ere c. Notons
Y =
_
1ik
(
i
)
lensemble de tous les etats auxquels on aboutit ` a partir dun des
i
par une transition de , puis
7 =
_
yY
(j)
la fermeture par -transitions de Y . Alors 7 est letat de auquel on aboutit depuis A par une transition
sur le caract`ere c.
On montre alors le
Theor`eme 6.2 (Correction de lalgorithme de determinisation)
Lautomate deterministe ainsi construit reconnat le meme langage que lautomate non deterministe .
6.5. D

ETERMINISATION DUN AFND 69


Complexite de la determinisation
Helas, la situation favorable de lexemple ci-dessus, o` u lautomate determinise a le meme nombre detats
que lafnd de depart, est exceptionnelle.
On dispose en eet du
Theor`eme 6.3 (Complexite de la determinisation)
Soit n 1 un entier naturel. Il existe un afnd `a n + 1 etats, tel que tout afd qui reconnat le meme
langage ait au moins 2
n
etats. La determinisation est donc un algorithme de co ut exponentiel.
4 Considerons, pour n xe, lautomate non deterministe de la gure 6.7 sur lalphabet / = c, /.
0 1 2 3 nn
a
b
a
a
b
a
b
a
b
a
b
...
Fig. 6.7: Un afnd `a la determinisation co uteuse
reconnat tous les mots qui ont au moins n lettres et qui se terminent par un c suivi de (n 1)
caract`eres c ou /.
Montrons que si est un afd qui reconnat le meme langage, alors a au moins 2
n
etats.
Soit
0
letat initial de .
`
A tout mot i de n lettres dans c, /, on peut associer letat de deni
par
0
m
. On obtient ainsi une application de lensemble /
n
des mots de n lettres dans lensemble Q
des etats de .
Nous allons montrer que cette application est injective. Alors le cardinal de Q vaudra au moins celui de
/
n
, qui est egal `a 2
n
, et la preuve sera terminee.
Supposons donc quon ait deux mots distincts i et i

de n lettres tels que


0
m
et
0
m

pour un
meme etat de .
Soit le plus long suxe commun `a i et i

. Comme i ,= i

, cest quon a i = nc et i

= n

/
(ou le contraire, bien s ur !). Notons que n et n

ont la meme longueur (eventuellement nulle) et que


est de longueur au plus egale `a n 1. Soit alors n un mot quelconque tel que n soit de longueur
exactement egale `a n 1.
Alors in = ncn est reconnu par les automates et donc , alors que i

n = n

/n ne lest pas.
Or
0
m
et
0
m

, donc
w

f
o` u
f
est un etat nal de lautomate puisque
0
mw

f
et in
est reconnu. Mais de meme
0
m

w

f
et i

n nest pas reconnu, donc


f
nest pas un etat nal : on a
trouve la contradiction esperee. 3
6.5.2 Programmation en Caml
La structure densemble de la biblioth`eque standard de Caml
Le module set de la biblioth`eque standard de Caml permet la gestion des parties dun ensemble muni
dune relation dordre. Voici une description des fonctions qui le composent :
typage le type a t est le type des ensembles delements du type a ;
set empty renvoie lensemble vide, cette fonction attend en argument une fonction de comparaison,
de type a -> a -> int qui renvoie 0 si les deux elements sont egaux, un entier negatif (resp.
positif) si le premier est plus petit (resp. grand) que le second, pour les entiers on pourra utiliser
set__empty (prefix -), pour les ensembles detats dun afnd (ce qui va nous interesser ici specia-
lement, bien s ur), nous pourrons utiliser set__empty compare_etats, o` u compare_etats q1 q2
70 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
renvoie q1.numero - q2.numero, enn, pour les ensembles densembles, on pourra utiliser, ce qui
va bientot devenir plus clair, set__empty set__compare ;
set is empty renvoie true si et seulement si son argument est lensemble vide ;
set mem est le test dappartenance : set__mem x E dit si r 1 ;
set add ajoute un element `a un ensemble : set__add x E renvoie lensemble r 1 ;
set remove realise loperation inverse : set__remove x E renvoie lensemble 1 r ;
set union realise lunion de deux ensembles ;
set inter realise lintersection de deux ensembles ;
set diff realise la dierence ensembliste ;
set equal teste legalite de deux ensembles ;
set compare prend en arguments deux ensembles et renvoie un entier qui nest nul que si les deux
ensembles sont egaux, et denit dans les autres cas une relation dordre sur lensemble des ensembles
de ce type, cette fonction est particuli`erement utile pour creer le type des ensembles densembles
dun type donne (voir la denition de set__empty) ;
set elements renvoie la liste des elements dun ensemble ;
set iter applique une meme fonction successivement aux elements dun ensemble, renvoie toujours () ;
set fold combine les elements dun ensemble : set__fold f E a renvoie ()r
n
. . . ()r
2
()r
1
c)) . . .), o` u
les r
i
sont les elements de lensemble 1.
Quelques preliminaires
Nous commencons, dans le programme 6.4 page suivante par denir quelques fonctions utiles pour la
suite.
taille ensemble utilise la fonction set__fold pour calculer le cardinal dun ensemble quelconque ;
set exists dit si le predicat est verie par au moins un des elements de lensemble teste (on a utilise le
declenchement dune exception en cas de succ`es pour eviter de parcourir tout lensemble et sortir
plus vite de la fonction set__iter) ;
compare etats permettra la comparaison de deux etats par le biais de leurs numeros, et sera la fonction
utilisee par set__empty pour nos ensembles detats, ainsi que nous lavons explique plus haut ;
set of list cree un ensemble `a partir dune liste detats en supprimant les doublons eventuels au pas-
sage ;
fermeture agit comme calcule_fermeture mais prend un ensemble detats et renvoie de meme un
ensemble detats, au lieu de travailler sur des listes.
La determinisation proprement dite
On suit tr`es exactement lalgorithme qui a ete developpe plus haut dans notre programme 6.5 page 72.
Cependant, ` a cause de la circularite des strutures utilisees, nous sommes contraints de construire dans
un premier temps lensemble des etats de lafd en gestation, puis, dans un second temps, on met ` a jour
les tables de transitions des etats ainsi crees.
La fonction ens_transition (lignes 1) attend un ensemble detats de depart de lafnd et le code ascii
dun caract`ere, et renvoie lensemble des etats de lafnd resultats de toutes les transitions correspondantes.
La fonction liste_etats_afd (lignes :8) prend en argument letat initial q0 de lafnd. On commence
(ligne :) par creer lensemble e0 des etats de sa fermeture, qui representera letat initial de lafd nal. On
cree alors (ligne :6) un ensemble eE0 forme du seul ensemble e0 (on note systematiquement les ensembles
densembles par un identicateur commen cant par eE). On appelle alors la fonction it`ere qui petit ` a petit
construit lensemble de tous les etats de lafd, ou plut ot de leurs representations en tant quensembles
detats de lafnd. Cest ce quon faisait `a la main en remplissant les colonnes de notre tableau.
La fonction cree_etats_afd (lignes oo) renvoie une liste de couples (c, ) o` u c est un ensemble detats
de lafnd et letat correspondant de lafd. Bien s ur, comme on la dej`a annonce, les tables de transition
6.6. EXERCICES POUR LE CHAPITRE 6 71
Programme 6.4 Fonctions utiles sur les ensembles
let taille_ensemble e =
set__fold (fun _ n -> n + 1) e 0 ;;
let set_exists predicat e =
try
set__iter
(function x
-> if predicat x then failwith "Gagne" else ())
e ;
false
with Failure "Gagne" -> true ;;
let compare_etats q1 q2 = q1.numero - q2.numero ;;
let set_of_list ql =
list_it set__add ql (set__empty compare_etats) ;;
let fermeture ens_etats =
set_of_list (calcule_fermeture (set__elements ens_etats)) ;;
ne sont pas encore correctes : on ne peut ecrire les transitions que quand on a ` a sa disposition tous les
etats.
La fonction m`aj_transitions (lignes 8) est justement chargee de mettre `a jour ces tables de transi-
tion. Elle utilise la fonction associe (lignes :6) qui prend en argument un ensemble detats de lafnd
et la liste de couples (c, ) decrite ci-dessus, et qui renvoie letat de lafd correspondant.
La fonction determinise (lignes 66o) ne pose alors plus de probl`eme.
6.6 Exercices pour le chapitre 6
Exercice 6.1 Quelques automates simples
Concevoir un automate sur lalphabet c, / qui accepte les chanes ayant un nombre pair de c.
Concevoir un automate sur lalphabet c, / qui accepte les chanes ayant au plus deux c consecutifs,
cest-`a-dire qui rejette toute chane contenant le mot ccc.
Concevoir un automate sur lalphabet = c, /, c, . . . , : qui accepte les chanes contenant le mot in)o.
Exercice 6.2 Determinisation dun automate simple
Reprendre le dernier des automates de lexercice precedent et le determiniser.
Exercice 6.3 Preuve de la determinisation
Rediger une demonstration du theor`eme 6.2 page 68.
Exercice 6.4 Ajout dun etat mort
Pour eviter les blocages dun afd, on peut ajouter un nouvel etat
m
dit etat mort : pour tout etat et
tout caract`ere c tel quil ny ait pas de transition depuis sur c, on ajoute la transition
c

m
. En outre
pour tout caract`ere c, on ajoute la transition
m
c

m
. Enn,
m
ne fait pas partie des etats nals.
Il est bien clair quainsi on ne change pas le langage reconnu par notre automate initial.
Soit un afd et le meme automate auquel on a ajoute un etat mort, comme on vient de lexpliquer.
On sait que 1() = 1().
Soit

(resp.

) lautomate obtenu ` a partir de (resp. ) en rendant nal tout etat non nal et
reciproquement. Comparer 1() = 1(), 1(

) et 1(

).
72 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
Programme 6.5 La determinisation des automates
i let ens_transition e i =
set_of_list
(set__fold
(fun q l -> (calcule_fermeture q.table.(i)) @ l)
e []) ; ;
6
let liste_etats_afd q0 =
S let rec it`ere eEproductifs eEdefinitifs =
p if set__is_empty eEproductifs then eEdefinitifs
io else
ii let eEnouveaux = ref (set__empty set__compare)
i in
i for i = 0 to 255 do
i set__iter
i (function e
i6 -> let e = ens_transition e i
i in
iS if not (set__is_empty e || set__mem e eEdefinitifs)
ip then eEnouveaux := set__add e !eEnouveaux)
o eEproductifs
i done ;
it`ere !eEnouveaux (set__union !eEnouveaux eEdefinitifs)
in
let e0 = set_of_list (calcule_fermeture [ q0 ] )
in
6 let eE0 = set__add e0 (set__empty set__compare)
in
S it`ere eE0 eE0 ; ;
p
o let cree_etats_afd q0 =
i let etat_afd e =
{ est_terminal = set_exists (function q -> q.est_final) e ;
transitions = make_vect 256 Blocage }
in
let eE = liste_etats_afd q0
6 in
set__fold
S (fun e l
p -> (e , (etat_afd e)) :: l)
o eE [] ; ;
i
let rec associe e l = match l with
| [] -> raise Not_found
| (e,q_afd) :: r
-> if set__equal e e then q_afd
6 else associe e r ; ;

S let m`aj_transitions q_afd e les_etats =


p for i = 0 to 255 do
o let e = ens_transition e i
i in
if not set__is_empty e then
q_afd.transitions.(i) <- OK (associe e les_etats)
done ; ;

6 let determinise q0 =
let les_etats = cree_etats_afd q0
S in
p map (function (e,q) -> m`aj_transitions q e les_etats) les_etats ;
6o associe (set_of_list (calcule_fermeture [ q0 ])) les_etats ; ;
6.6. EXERCICES POUR LE CHAPITRE 6 73
Exercice 6.5 Determinisation dun afd !
Que se passe-t-il quand on applique notre algorithme de determinisation `a un automate dej`a deterministe ?
Exercice 6.6 Minimisation dun afd
Soit un automate deterministe. Pour eviter tout probl`eme, on le suppose muni dun etat mort (voir
exercice 6.4).
On cherche `a construire un automate deterministe qui reconnaisse le meme langage mais qui ait un
nombre minimal detats. Lalgorithme que nous presentons ici sappelle lalgorithme de Hopcroft.
Pour cela, on introduit la notion detats equivalents de : deux etats
1
et
2
sont dits equivalents si
pour tout mot n, les deux calculs `a partir de
1
et
2
bloquent tous les deux, ou si, quand
1
w
et

2
w

, et

sont tous les deux nals ou tous les deux non-nals.


Il est bien evident quon peut alors tout simplement identier deux etats equivalents sans changer le
langage reconnu.
Plut ot que de chercher les etats equivalents, on se propose de determiner si deux etats ne sont pas
equivalents. Voici les deux r`egles que lon appliquera :
1. deux etats
1
et
2
dont lun est nal et lautre pas ne sont pas equivalents ;
2. si
1
et
2
sont dej` a connus non equivalents, si c est un caract`ere de lalphabet, et si

1
et

2
verient

1
c

1
et

2
c

2
, alors

1
et

2
sont non equivalents.
On va donc raner petit ` a petit la relation dequivalence : on maintiendra une partition en classes,
initialisee dapr`es la r`egle (1) `a deux parties, les etats nals dun c ote, et les autres. On applique ensuite
la r`egle (2) jusqu` a ce que la partition ne soit plus modiee : on cherchera si la lecture dun caract`ere
de lalphabet partage une des parties en deux sous-parties. Exemple : pour lautomate ci-dessous, sur
lalphabet c, /, on obtient les partitions successives suivantes.
1 2
3
4 55
a
b
b
a
b
b
a
a
b
a
On commence par 1, 2, 3, 4, 5 (r`egle 1).
La lecture dun c ne permet pas de separer les etats du premier groupe, mais la lecture dun / isole
letat 4.
On obtient donc 1, 2, 3, 4, 5.
Meme chose ensuite, o` u lon isole letat 2.
La partition nale est 1, 3, 2, 4, 5.
Cela correspond `a lautomate suivant :
74 CHAPITRE 6. AUTOMATES FINIS D

ETERMINISTES OU NON D

ETERMINISTES
1 2 4 55
a
b
b
b
a
a
b
a
Remarque : ces automates reconnaissent les mots sur c, / qui se terminent par c//.

Ecrire une fonction de minimisation en Caml.


Chapitre 7
Langages rationnels et automates
Dans tout ce chapitre, / designe un ensemble ni, appele alphabet.
7.1 Langages rationnels et expressions reguli`eres
7.1.1 Denition
Langages, operations sur les langages

Etant donne un alphabet /, on note /

lensemble des mots sur / : il sagit, rappelons-le, des suites


nies delements de lalphabet. Cet ensemble de mots est muni dune operation interne, la concatenation,
quon note parfois par un point, mais le plus souvent par simple juxtaposition : si n
1
et n
2
sont deux
mots, on notera aussi bien n
1
.n
2
que n
1
n
2
le mot obtenu par concatenation. Le mot vide est note .
Un langage sur lalphabet / est une partie de /

. Leur ensemble est note L(/) = T(/

). Notons que
est un langage particulier.
La concatenation des mots fait de /

un monode : cest-`a-dire que la concatenation est une loi de


composition interne associative.
Denition 7.1 (Operations sur les langages) On denit sur L(/) trois operations fondamentales :
lunion de deux langages 1
1
et 1
2
est tout simplement lensemble des mots qui appartiennent `a 1
1
ou `a 1
2
,
qui est bien s ur note 1
1
1
2
;
le produit note 1
1
1
2
de deux langages 1
1
et 1
2
est lensemble des mots obtenus par concatenation dun
mot de 1
1
et dun mot de 1
2
: 1
1
1
2
= n
1
n
2
, n
1
1
1
, n
2
1
2
;
letoile dun langage 1 est lensemble note 1

des mots obtenus par concatenation dun nombre ni


(eventuellement nul) de mots de 1,
1

= 1 n
1
n
2
n
n
, n 2, i, n
i
1;
on peut dire aussi que 1

est le sous-monode de /

engendre par 1.
Langages rationnels
Denition 7.2 (Langages rationnels) Lensemble des langages rationnels sur un alphabet / est note 1(/).
Il sagit de la plus petite partie de L(/) qui contienne le langage vide et les singletons, et qui soit stable pour
les trois operations listees ci-dessus, `a savoir lunion, le produit et letoile.
Exemples sur lalphabet / = c, / : est un langage rationnel ; /

est un langage rationnel (cest letoile


dune somme nie de singletons, puisque lalphabet est ni) ; lensemble des mots qui se terminent par
c/ est rationnel car il est produit des trois langages rationnels /

, c, /.
75
76 CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES
7.1.2 Expressions reguli`eres
Les denitions tr`es formelles precedentes ne permettent pas de verier rapidement quun langage est
rationnel, et on pref`ere decrire les langages rationnels `a laide de formules appelees expressions regu-
li`eres : tout langage rationnel peut etre decrit par une expression reguli`ere (il ny a pas du tout unicite),
et reciproquement les expressions reguli`eres ne decrivent de langages que rationnels.
On denit les expressions reguli`eres de la meme facon quon a pu denir des expressions arithmetiques :
on se donnera des constantes, des variables, des operations et des fonctions. En outre, la semantique des
expressions reguli`eres consistera en une application de lensemble des expressions reguli`eres sur 1(/).
Denition des expressions reguli`eres
Les informaticiens utilisent le plus souvent le mot motif pour decrire une expression reguli`ere (pattern
en anglais). Nous allons ainsi donner ici la description des dierents motifs sur un alphabet / xe.
Pour ecrire un motif non vide nous aurons ` a notre disposition des constantes (motifs constants) qui
seront les elements de lalphabet et la constante . Nous aurons aussi des operateurs binaires : la somme
(encore appelee union), que nous noterons [, et le produit (encore appele concatenation), qui sera notee
par simple juxtaposition. Il existera aussi un operateur unaire : letoile, notee de facon suxe. Enn, nous
nous autoriserons lusage de variables servant `a representer des sous-motifs.
Plus formellement :
Denition 7.3 (Expressions reguli`eres) Soit / un alphabet ni. On denit recursivement lensemble corre-
spondant c(/) des expressions reguli`eres de la facon suivante :
est une expression reguli`ere ;
et toute lettre de lalphabet sont des expressions reguli`eres, dites atomiques ;
si c
1
et c
2
sont des expressions reguli`eres, (c
1
[c
2
) et (c
1
c
2
) sont des expressions reguli`eres, appelees
somme et produit des expressions reguli`eres c
1
et c
2
;
si c est une expression reguli`ere, c est une expression reguli`ere, appelee etoile (ou etoilee) de c.
Lusage est de ne pas ecrire les parenth`eses que rendent inutiles les priorites suivantes : letoile est
prioritaire devant le produit, lui-meme prioritaire devant la somme.
Exemples dexpressions reguli`eres : ; c/[(c[c)/ = (c(/))[(((c[c))/).
Pour eviter de trop longs motifs, on pourra ajouter aux expressions atomiques des variables representant
des sous-motifs.
On ecrira ainsi par exemple : A = c[/[c[...[:[[1[...[7, B = 0[1[2[3[4[5[6[7[8[9 et A(A[B) sera un motif
qui represente les mots compses de lettres et de chires commencant par une lettre.
Semantique
Il est temps de donner la semantique des expressions reguli`eres :
Denition 7.4 (Semantique des expressions reguli`eres) On denit par induction structurelle une applica-
tion de c(/) sur 1(/), qui denit la semantique des expressions reguli`eres en associant `a chaque expression
reguli`ere un langage rationnel, de la fa con suivante :
le langage associe `a est le langage vide ;
`a est associe le langage constitue du seul mot vide ;
si c est une lettre de lalphabet, le langage associe est le singleton c ;
si c
1
et c
2
sont des expressions reguli`eres de langages associes 1
1
et 1
2
, le langage associe `a lexpression
(c
1
[c
2
) est la reunion 1
1
1
2
;
si c
1
et c
2
sont des expressions reguli`eres de langages associes 1
1
et 1
2
, le langage associe `a lexpression
(c
1
c
2
) est le produit 1
1
1
2
;
si c est une expression reguli`ere de langage associe 1, le langage associe `a lexpression c est letoile 1

du langage 1.
7.2. LE TH

EOR
`
EME DE KLEENE 77
4 De par la denition meme des langages rationnels, il est clair que tous les langages associes aux
expressions reguli`eres sont bien rationnels.
Pour montrer la reciproque, on remarque tout dabord que vide et tout singleton sont representes par
des expressions reguli`eres. Lensemble des langages associes aux expressions reguli`eres etant clairement
stable par union, produit et etoile, on en deduit quon a bien decrit tous les langages rationnels. 3
Comme les expressions reguli`eres seront representees par des chanes de caract`eres, les informaticiens ont
d u ajouter quelques notations particuli`eres : ainsi le symbole . sert-il ` a designer toute lettre de lalphabet,
cest si lon pref`ere lexpression somme de toutes les expressions atomiques sauf . En outre, on utilise le
symbole + (en notation suxe) pour representer une repetition au moins une fois dun motif : pour tout
motif A, A+ designera AA. De meme ? (toujours en notation suxe) representera une repetition zero
ou une fois dun motif : pour tout motif A, A? designera ([A). Enn, pour eviter toute ambigute, on
utilise un caract`ere dechappement, : c represente une suite quelconque de c, mais c represente un
c suivi du caract`ere etoile.
Expressions reguli`eres en Caml
Voici le type que lon peut utiliser pour les expressions reguli`eres non vides en Caml :
type expr_rat =
| Epsilon
| Mot of string
|

Etoile of expr_rat
| Somme of expr_rat list
| Produit of expr_rat list ;;
Pour eviter decrire c/c comme Produit(Lettre a , Produit(Lettre b , Lettre c), on a
prefere utiliser labreviation Mot pour le produit datomes. De meme, on fait usage de lassociativite
des operateurs pour ecrire Produit [ X ; Y ; Z] plut ot que Produit(X , Produit(Y,Z)).
Lexpression reguli`ere c/(c[/)/c qui represente les mots sur c, / dau moins quatre lettres, commen cant
par c/ et se terminant par /c, sera representee par lobjet Caml suivant :
Produit [ Mot "ab" ;

Etoile( Somme [ Mot "a" ; Mot "b" ] ) ; Mot "ba" ] ;;
Nous naborderons pas ici le delicat probl`eme du passage de la syntaxe concr`ete `a la syntaxe abstraite
des expressions reguli`eres, cest-`a-dire de lecriture dune fonction parseur : string -> expr_rat qui
serait utilisee par exemple ainsi :
#parseur "ab(a|b)*ba" ;;
- : expr_rat =
Produit [Mot "ab";

Etoile (Somme [Mot "a"; Mot "b"]); Mot "ba"]
#
7.2 Le theor`eme de Kleene
Nous demontrons ici un theor`eme fondamental, le theor`eme de Kleene, qui senonce ainsi :
Theor`eme 7.1 (Kleene)
Lensemble 1(/) des langages rationnels sur un alphabet ni / est exactement egal `a lensemble des langages
reconnus par des automates nis.
78 CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES
Ce theor`eme consiste en deux resultats dierents, pour lesquels nous donnerons des preuves constructives :
1. tout langage rationnel est reconnu par un automate ni : dans la sous-section 7.2.1, nous prou-
verons ce resultat en donnant une methode de construction dun automate ni non deterministe
qui reconnat un langage rationnel represente par une expression reguli`ere xee ;
2. le langage que reconnat un automate ni est rationnel : dans la sous-section 7.2.2 page suivante, nous
prouverons ce resultat en expliquant comment construire une expression reguli`ere qui represente le
langage reconnu par un automate ni deterministe xe.
Notons toutefois que le premier de ces deux resultats est le plus interessant, puisquon sait determiniser
un afnd, et quun automate ni deterministe permet de programmer facilement et ecacement la recon-
naissance des mots dun langage.
7.2.1 Des langages rationnels aux automates
Nous montrons ici que pour toute expression reguli`ere on peut construire un automate ni non determi-
niste ayant un unique etat initial et un unique etat nal qui reconnaisse le langage rationnel represente
par lexpression reguli`ere proposee : pour ce faire, nous raisonnerons par induction structurelle.
On laisse au lecteur la construction dun afnd pour le langage vide. . .
Pour le cas des expressions atomiques, on obtient tr`es facilement les automates de la gure 7.1.
c
Fig. 7.1: Automates pour les expressions reguli`eres atomiques
Soit c
1
et c
2
deux expressions reguli`eres, et
0
,
f
(resp.

0
,

f
) les etats initial et nal de lautomate
associe `a c
1
(resp. c
2
). On construira, conformement `a la gure 7.2, lautomate de la somme c
1
[c
2
en
ajoutant un etat initial duquel on m`enera deux -transitions vers
0
et

0
et un etat nal auquel arriveront
deux -transitions depuis
f
et

f
.
Automate pour e
1
Automate pour e
2

Fig. 7.2: Automate pour la somme de deux expressions reguli`eres


Soit c
1
et c
2
deux expressions reguli`eres, et
0
,
f
(resp.

0
,

f
) les etats initial et nal de lautomate
associe `a c
1
(resp. c
2
). On construira, conformement `a la gure 7.3 page ci-contre, lautomate du produit
c
1
c
2
en ajoutant un etat initial duquel on m`enera une -transition vers
0
et un etat nal auquel arrivera
une -transition depuis

f
; on ajoutera enn une -transition depuis
f
vers

0
.
Soit c une expression reguli`ere, et
0
,
f
les etats initial et nal de lautomate associe. On construira,
conformement ` a la gure 7.4 page suivante, lautomate de letoile c en ajoutant un etat initial Q
0
et un
etat nal Q
f
. De Q
0
on m`enera deux -transitions vers
0
et Q
f
. De Q
f
on m`enera une -transition vers
Q
0
, et enn une -transitions ira depuis
f
vers Q
f
.
7.2. LE TH

EOR
`
EME DE KLEENE 79
Automate pour e
1
Automate pour e
2

Fig. 7.3: Automate pour le produit de deux expressions reguli`eres
Automate pour e

Fig. 7.4: Automate pour letoile dune expression reguli`ere


Bien s ur, les automates ainsi construits sont trues de -transitions, mais elles disparatront dans la
determinisation quon ne manquera pas deectuer.
7.2.2 Des automates aux langages rationnels
Nous decrirons ici lalgorithme classique, dit par suppression des etats, qui permet de construire une
expression reguli`ere qui represente le langage reconnu par un automate deterministe ni.
Soit un tel automate, et
1
,
2
, . . . ,
k
ses etats nals. Notons
i
lautomate egal `a `a ceci pr`es que seul
letat
i
est considere comme etat nal. Dapr`es la denition des mots reconnus par , il est bien evident
que 1() =
k
_
i=1
1(
i
). Cest ce qui permet, dans la description de notre algorithme, de ne considerer
que le cas dautomates nis deterministes nayant quun unique etat initial
0
et un unique etat nal
f
.
En eet, si c
i
est une expression reguli`ere qui decrit le langage reconnu par
i
, une expression reguli`ere
solution du probl`eme pose est c
1
[c
2
[ [c
k
.
Lalgorithme de suppression des etats
Lidee est de supprimer petit `a petit tous les etats distincts de
0
et
f
, jusqu` a navoir plus quun
automate `a 2 etats. Il faudra cependant generaliser les transitions, et les etiqueter non plus avec des
lettres de lalphabet, mais avec des expressions reguli`eres.
Supposons par exemple quon soit dans la situation de la gure 7.5 page suivante. On souhaite supprimer
letat r. Pour chaque couple detats c, : tel quil existe une transition de c entrant dans r et une transition
vers : sortant de r, on proc`ede comme suit : si est lexpression reguli`ere qui etiquette la transition de
c vers r, 1 de r `a :, C de r vers r et 1 de c vers :, on ecrira une transition de c vers : etiquetee par
lexpression 1[C1. On obtient alors lautomate de la gure 7.6 page suivante.
Finalement, il ne restera plus quun etat initial et un etat nal : on se retrouve dans la situation de la
gure 7.7 page suivante. Le probl`eme est alors resolu, puisquune expression reguli`ere qui convient est la
80 CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES
e
s
x
C
A
B
D
Fig. 7.5: Avant la suppression de letat r
e
s
D|ACB
Fig. 7.6: Apr`es la suppression de letat r
suivante : 1(1[C1).
A D
B
C
Fig. 7.7: Automate `a 2 etats
Un exemple
Considerons lexemple de lautomate de la gure 7.8 page suivante.
On commence par sinteresser `a letat nal 3. On supprime letat 2, obtenant lautomate de la gure 7.9
page ci-contre.
On aura note que letiquette de la boucle sur letat initial est devenue c[/c.
On supprime alors letat 4, obtenant lautomate de la gure 7.10 page 82.
On peut maintenant appliquer la r`egle ci-dessus, et annoncer que le langage reconnu par ce dernier
automate est decrit par le motif suivant :
(c[/c)cc(/[c/[cc(c[/c)//).
Reprenons maintenant lautomate initial, en nous interessant `a letat nal 4. Apr`es suppression de letat 2,
nous obtenons lautomate de la gure 7.11 page 82.
On supprime encore letat 3 obtenant lautomate de la gure 7.12 page 82.
On ecrit lexpression reguli`ere qui represente le langage reconnu :
(c[/c)///c(//c[c(c[/c)//c).
Finalement voici une expression reguli`ere qui represente le langage reconnu par lautomate initial :
(c[/c)cc(/[c/[cc(c[/c)//)[(c[/c)///c(//c[c(c[/c)//c).
7.2. LE TH

EOR
`
EME DE KLEENE 81
1
2 3
4
3
4
b
a
b
a
a
b b
a
Fig. 7.8: Quel est le langage reconnu par cet automate ?
1
3
4
3
b
a|ba
a
bb
b
a
Fig. 7.9: On a supprime letat 2
Personne ne dit que lexpression reguli`ere ci-dessus est la plus simple possible. Sur notre exemple,
ce nest dailleurs pas du tout le cas, car voici une expression reguli`ere qui represente le meme
langage :
(a|b)bb(b|ab)(|a).
La simplication des expressions reguli`eres nest pas quelque chose de tr`es aise, meme si les exercices qui
se trouvent `a la n de ce chapitre peuvent donner quelques pistes dinspiration.
82 CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES
1
33
b|ab
a|ba
bb
aa
Fig. 7.10: Apr`es suppression des etats 2 et 4
1
3
44
b
a|ba
a
bb
b
a
Fig. 7.11: On recommence en supprimant letat 2
1 44
a|ba bba
a
bbba
Fig. 7.12: Apr`es suppression des etats 2 et 3
7.3. LANGAGES NON RATIONNELS 83
7.3 Langages non rationnels
Nous montrons ici que tout langage nest pas necessairement rationnel. Nous commencons par donner
deux exemples, pour lesquels nous demontrons `a la main quil ne sagit pas de langages rationnels, puis
nous demontrons un lemme general qui permet de discriminer une large classe de langages non rationnels.
7.3.1 Exemples
Montrons ` a la main que les deux langages 1
1
et 1
2
suivants sur lalphabet c, / ne sont pas rationnels :
1. 1
1
est le langage constitue des mots de la forme c
n
/
n
;
2. 1
2
est le langage constitue des mots de la forme c
n
/
p
avec n j.
Le langage 1
1
nest pas rationnel
Si 1
1
etait rationnel, on pourrait trouver un automate ni deterministe qui le reconnaisse. Soit i le
nombre de ses etats, et
0
son etat initial.
Soit n

la chane composee de / fois le caract`ere c. On denit letat

par
0
w

, ce qui a bien du sens,


puisque lautomate est deterministe, et quil ne peut pas se bloquer sur c

comme il accepte la chane


c

. Comme lautomate est ni, il existe deux entiers i et , tels que 0 i < , i tels que
i
=
j
. Cest
dire que
j1
a

i
: on a trouve une boucle dans lautomate. On en deduit que
0
a
i+k(ji)

i
pour tout
entier /.
Or on sait que c
i
/
i
est reconnu par lautomate. Ainsi a-t-on
i
b
i

f
o` u
f
est un etat nal. Mais alors
on aura pour tout entier /
0
a
i+k(ji)
b
i

f
, ce qui prouve que lautomate reconnat des mots qui ne sont
pas dans 1
1
: cest la contradiction recherchee.
Le langage 1
2
nest pas rationnel
Si 1
2
etait rationnel, on pourrait trouver un automate ni deterministe qui le reconnaisse. Soit i le
nombre de ses etats, et
0
son etat initial.
Soit n

la chane composee de / fois le caract`ere c. On denit letat

par
0
w

, ce qui a bien du sens,


puisque lautomate est deterministe, et quil ne peut pas se bloquer sur c

comme il accepte la chane


c

. Comme lautomate est ni, il existe deux entiers i et , tels que 0 i < , i tels que
i
=
j
. Cest
dire que
j1
a

i
: on a trouve une boucle dans lautomate. On en deduit que
0
a
i+k(ji)

i
pour tout
entier /.
On sait que c
j
/
j
est dans 1
2
: cest dire que
0
a
j
b
j

f
o` u
f
est un etat nal. On a donc
i
b
j

f
.
Mais alors on a aussi
0
a
i
b
j

f
, puisque
0
a
i

i
. On en deduit que lautomate accepte le mot c
i
/
j
qui
nappartient pourtant pas ` a 1
2
puisque i < , : cest la contradiction recherchee.
7.3.2 Le lemme de letoile
Lemme 7.1 (Lemme de letoile) Soit 1 un langage rationnel. Il existe un entier n tel que tout mot n de 1
de taille au moins egale `a n secrit sous la forme n = ::t o` u : est un mot non vide de taille au plus egale `a
n et o` u le motif ::t decrit des mots qui sont tous dans 1.
4 Soit en eet un automate ni deterministe reconnaissant 1, et soit n le nombre de ses etats,
0
son etat initial et T lensemble de ses etats nals.
Soit n un mot de 1 de taille superieure ou egale `a 1. Notons n

les prexes de n : n

est compose
des / premiers caract`eres de n. Denissons alors les etats

de lautomate en posant
0
w

. Ceci
a bien du sens car lautomate est deterministe et ne peut pas se bloquer sur un prexe dun mot quil
reconnat.
Comme n a au moins autant de lettres que detats, on est certain de pouvoir trouver deux indices i
et , tels que 0 i < , n avec
i
=
j
.
84 CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES
Soit alors : le prexe (eventuellement vide) de n forme des i premiers caract`eres de n; : le mot (non
vide) forme des , i caract`eres suivants ; et t le suxe (eventuellement vide) de n forme des caract`eres
suivants.
On a bien n = ::t. En outre
0
r

i
s

j
=
i
t

f
o` u
f
est un etat nal.
On aura bien alors
0
rs
p
t

f
pour tout entier j, ce qui ach`eve notre demonstration. 3
On aura note comment le lemme de letoile generalise les methodes que nous avons utilisees pour les deux
exemples ci-dessus.
7.4 Exercices pour le chapitre 7
Exercice 7.1 Langages rationnels, intersection et complementaire
Soit / un alphabet ni. En utilisant certains exercices du chapitre precedent, montrer que 1(/) est stable
par intersection et complementaire, cest-`a-dire que le complementaire (dans /

) dun langage rationnel


est un langage rationnel, et que lintersection de deux langages rationnels est un langage rationnel.
Exercice 7.2

Equivalence des expressions reguli`eres
On dira de deux expressions reguli`eres c
1
et c
2
quelles sont equivalentes, ce que nous noterons c
1
c
2
si elles decrivent le meme langage.
Montrer les formules suivantes, valables pour toutes expressions reguli`eres c
1
et c
2
:
(c
1
c
2
) [c
1
(c
2
c
1
)c
2
(c
1
[c
2
) c
1
(c
2
c
1
)
j 1, c
1
([c
1
[ [c
p
1
)(c
p+1
1
)
Exercice 7.3 Le langage des facteurs des mots dun langage
Soit 1 un langage rationnel et soit 1

le langage constitue de tous les mots qui sont des sous-chanes de


mots de 1. Montrer que 1

est aussi rationnel.


Exercice 7.4 Reconnaissance dun meme langage
Montrer que les deux afnd de la gure ci-dessous reconnaissent le meme langage.
1 2 3 1 2 3 3 3
a
b
a
a
b
b
a
a
b
a
b
Exercice 7.5 Exemples de langages non rationnels
Montrer que le langage sur c, / forme des mots de la forme c
n
/c
n
, o` u n 0, nest pas rationnel. Meme
question avec le langage sur le meme alphabet constitue des mots de la forme nn

o` u n

est le miroir du
mot n (les memes lettres, mais lues de droite `a gauche).
7.4. EXERCICES POUR LE CHAPITRE 7 85
Exercice 7.6 Expressions reguli`eres decrivant des langages donnes

Ecrire des expressions reguli`eres qui decrivent les langages suivants :


1. les mots sur c, / contenant au moins un c ;
2. les mots sur c, / contenant au plus un c ;
3. les mots sur c, / tels que toute serie de c ait une longueur paire (///cc/cccc, / et cccc/ convien-
nent, mais pas c//cc ni ccc) ;
4. les mots sur c, /, c tels que deux lettres consecutives sont toujours distinctes.
Troisi`eme partie
Corrige de tous les exercices
87
Chapitre 1
Corrige des exercices
Exercice 1.1
Voici une premi`ere solution :
let indexation arbre =
let rec prefixe zero_ou_un = function
| Feuille(f) -> Feuille(zero_ou_un ^ f)
| Nud(n,g,d) -> let g,d = (prefixe zero_ou_un g),(prefixe zero_ou_un d)
in
Nud((zero_ou_un ^ n),g,d)
in
let rec indexe = function
| Feuille(_) -> Feuille("")
| Nud(n,g,d) -> let g,d = (indexe g),(indexe d)
in
Nud("",(prefixe "0" g),(prefixe "1" d))
in
indexe arbre ;;
et en voici une seconde :
let indexation arbre =
let rec indexe a prefixe = match a with
| Feuille(_) -> Feuille(prefixe)
| Nud(_,g,d) -> let g = indexe g (prefixe ^ "0")
and d = indexe d (prefixe ^ "1")
in
Nud(prefixe,g,d)
in
indexe arbre "" ;;
Exercice 1.2
let liste_`a_profondeur arbre n =
let rec ajoute_`a_profondeur a k dej`a_trouves =
if k = 0 then a :: dej`a_trouves
else match a with
| Feuille(_) -> dej`a_trouves
| Nud(_,g,d) -> ajoute_`a_profondeur g (k - 1)
(ajoute_`a_profondeur d (k - 1) dej`a_trouves)
in
ajoute_`a_profondeur arbre n [] ;;
89
90 CHAPITRE 1. EXERCICES SUR ARBRES BINAIRES
Exercice 1.3
let rec deshabille = function
| Feuille(_) -> Vide
| Nud(_,g,d) -> Jointure((deshabille g),(deshabille d)) ;;
Exercice 1.4
On ecrit les deux fonctions sur le meme mod`ele. Il faudra simplement ajouter des tests supplementaires
pour le cas o` u lon sinteresse `a la profondeur.
On ecrit tout dabord une fonction qui recombine des squelettes pour des listes xees de sous-arbres
gauches et de sous-arbres droits possibles, ce qui secrit ainsi :
(* construit les squelettes dont les sous-arbres gauche et droit *)
(* decrivent les listes l1 et l2 *)
let rec recompose l1 l2 =
match l1 with
| [] -> []
| gauche :: q -> (map (function droit -> Jointure(gauche,droit)) l2)
@ (recompose q l2) ;;
La generation des squelettes de taille et profondeur xees secrit alors :
let rec engendre_`a_profondeur n p =
if n = 0 then [ Vide ]
else if p < 0 then []
else if p = 0 then if n = 1 then [ Jointure(Vide,Vide) ]
else []
else
begin
let resultat = ref []
in
for i = 0 to n-1 do
let liste_gauche = engendre_`a_profondeur i (p-1)
and liste_droite = engendre_`a_profondeur (n-i-1) (p-1)
in
resultat := !resultat @ (recompose liste_gauche liste_droite)
done ;
!resultat
end ;;
On fait de meme pour la generation de tous les squelettes de taille xee :
let rec engendre n =
if n = 0 then [ Vide ]
else
begin
let resultat = ref []
in
for i = 0 to n-1 do
let liste_gauche = engendre i
and liste_droite = engendre (n-i-1)
in
resultat := !resultat @ (recompose liste_gauche liste_droite)
done ;
!resultat
end ;;
91
Exercice 1.5
let rec squelette_complet n =
let pair n = n = 2 * (n/2)
in
if n = 0 then Vide
else if pair (n-1) then
Jointure((squelette_complet ((n-1) / 2)),
(squelette_complet ((n-1) / 2)))
else failwith "Taille incompatible avec la completude du squelette" ;;
Exercice 1.6
let est_complet a =
let rec feuilles_au_bon_niveau k = function
| Feuille(_) -> k = 0
| Nud(_,g,d) -> feuilles_au_bon_niveau (k-1) g
&& feuilles_au_bon_niveau (k-1) d
in
feuilles_au_bon_niveau (profondeur a) a ;;
Exercice 1.7
let est_equilibre a =
let rec feuilles_au_bon_niveau k = function
| Feuille(_) -> k = 0 || k = 1
| Nud(_,g,d) -> feuilles_au_bon_niveau (k-1) g
&& feuilles_au_bon_niveau (k-1) d
in
feuilles_au_bon_niveau (profondeur a) a ;;
Chapitre 2
Corrige des exercices
Exercice 2.1
Voil` a sans doute lexercice le plus dicile du chapitre.
Reechissons sur lexemple de larbre de la gure suivante :
a

`
`
`
c

`
`
`
3

`
`
`
`
`
d

`
`
`
5

`
`
`
6
Son parcours militaire est : 1 = c/d1cc62345.
Je propose lalgorithme suivant :
1. remplacer 1 par son miroir (ici 54326cc1d/c), quon va lire element par element par la suite ;
2. preparer une pile vide ;
3. si lelement ) lu est une feuille, lempiler dans la pile , et reprendre `a letape 3 ;
4. si lelement n lu est un nud, retirer de la pile ses deux derniers elements, r et j, et empiler dans
la pile larbre (n, r, j), puis reprendre ` a letape 3 ;
5. sinon, ne doit contenir quun element qui est larbre resultat.
Dans notre exemple, on commence par empiler les feuilles 5, 4, 3, 2 , 6 : la pile contient donc dans cet
ordre 6; 2; 3; 4; 5. Vient alors le nud c : on retire de la pile ses deux plus anciens elements, cest-`a-dire 4
et 5. On construit larbre (c, 5, 4) quon empile. La pile contient alors (c, 5, 4); 6; 2; 3.
On lit alors le nud c, on depile donc 2 et 3, construit larbre (c, 2, 3) quon empile. La pile contient
(c, 2, 3); (c, 5, 4); 6.
On lit encore la feuille 1, quon empile, puis le nud d. On depile (c, 5, 4) et 6, et construit (d, (c, 5, 4), 6)
quon empile. La pile contient ici (d, (c, 5, 4), 6); 1; (c, 2, 3).
On lit le nud /, et construit (/, 1, (c, 2, 3)) quon empile.
La pile contient `a ce moment (/, 1, (c, 2, 3)); (d, (c, 5, 4), 6).
Lisant enn le nud c, on retrouve bien larbre souhaite.
Le probl`eme majeur de programmation vient de ce que ne se comporte pas comme une pile : en eet
ce sont les elements les plus anciens qui doivent etre retires en priorite (rst in, rst out), au contraire
dune pile o` u les elements retires en priorite sont les plus recemment empiles (last in, rst out).
93
94 CHAPITRE 2. EXERCICES SUR PARCOURS DUN ARBRE
Cest pourquoi je propose une nouvelle structure de donnees pour representer : on parle de queue ou
le dattente.
Pour limplementer en Caml, nous utiliserons ici tout simplement un vecteur darbres, dans la mesure o` u
nous savons quil y aura dans un nombre delements plus petit que le nombre dobjets dans 1.
Il faudra toutefois prendre garde ` a travailler sur les indices du vecteur modulo la taille du tableau, et
garder toujours lindice des elements les plus recent et ancien.
On obtient cette gestion dune queue.
type a queue =
{ empile : (a -> unit) ;
depile : (unit -> a) ;
est_vide : (unit -> bool) } ;;
exception Queue_Vide ;;
exception Queue_Pleine ;;
let cree_queue taille initialisateur =
let n = taille + 1
in
let v = make_vect n initialisateur
and debut = ref 0
and fin = ref 0
in
{ est_vide =
(function () -> !debut = !fin) ;
empile =
(function x -> if (!fin + n - !debut) mod n = taille
then raise Queue_Pleine
else v.(!debut) <- x ;
debut := (!debut + taille) mod n ) ;
depile =
(function () -> if !debut = !fin then raise Queue_Vide
else let x= v.(!fin)
in
fin := (!fin + taille) mod n ;
x ) } ;;
On lapplique comme explique ci-dessus `a la reconstitution dun arbre ` a partir de son parcours militaire,
et on obtient le programme ci-dessous.
let recompose_militaire l feuille_bidon =
let p = rev l
and q = cree_queue (list_length l) (Feuille feuille_bidon)
in
let rec avance = function
| [] -> let a = q.depile ()
in
if q.est_vide () then a
else failwith "Parcours militaire incorrect"
| (F f) :: suite
-> q.empile (Feuille f) ; avance suite
| (N n) :: suite
-> let y = q.depile ()
in
let x = q.depile ()
in
q.empile (Nud(n,x,y)) ; avance suite
in
try avance p
with _ -> failwith "Parcours militaire incorrect" ;;
Le param`etre feuille bidon ne sert quau typage de Caml qui doit initialiser ses tableaux avec quelque
chose. . . Cest dailleurs aussi le r ole du param`etre initialisateur de cree queue.
95
Exercice 2.2
Les deux conversions sont a priori tr`es dierentes. La conversion prexe vers suxe est certainement la
plus simple, puisquil ny a pas ` a revenir en arri`ere, quand on a trouve un nud, pour trouver ses ls.
Pour larbre represente dans la gure suivante, on va construire ce tableau :
lu c / 1 c 2 3 d c 4 5 ) p 6 7 8
pile ) ) )) ) ) ) )) )) )) )) ))) )))
ecrit 1 2 3c/ 4 5c 6 7p 8)dc
pile 1 c /c /c c/c c/c c dc cdc cdc dc )dc p)dc p)dc )dc
a

`
`
`
c

`
`
`
3
>
>
>
>
>
>
>

`
`
`
5

`
`
`
7

`
`
`
8
La pile est une pile de v/f (quon pourra representer par des booleens), la pile 1 est une pile de nuds.
Elles sont toujours de meme taille, et dailleurs la pile contient v(oid) ` a chaque fois quaucun ls na
ete complete pour le nud correspondant de la pile 1, et f(ull) quand le ls gauche est plein.
La r`egle de formation est alors simple : tout nud nouvellement lu est empile dans la pile 1, alors quon
empile un dans la pile ; ` a la lecture dune feuille, on lecrit aussit ot, et, si le sommet de la pile est
un , on le remplace par un ), alors que sil sagit dun ), on depile tous les ) de la pile , et en meme
temps les nuds correspondants de la pile 1 quon ecrit, apr`es quoi on transforme le qui est au sommet
de la pile par un ), `a moins quil ny en ait plus, mais cest quon a termine.
Ceci correspond au programme suivant :
let suffixe_de_prefixe l =
let rec avance pile_A pile_B = function
| [] -> []
| (N n) :: reste
-> avance (true :: pile_A) (n :: pile_B) reste
| (F f) :: reste
-> match pile_A with
| [] -> failwith "Description prefixe incorrecte"
| true :: q_A
-> (F f) :: (avance (false :: q_A) pile_B reste)
| false :: q_A
-> (F f) :: (vidage pile_A pile_B reste)
and vidage pile_A pile_B reste = match pile_A,pile_B with
| true :: q_A , n :: q_B -> avance (false :: q_A) pile_B reste
| false :: q_A , n :: q_B -> (N n) :: (vidage q_A q_B reste)
| [],[] -> if reste = [] then []
else failwith "Description prefixe incorrecte"
| _ -> failwith "Description prefixe incorrecte"
in
avance [] [] l ;;
Pour ce qui est de la transformation inverse, le plus simple est de tr`es loin de construire larbre ` a
laide de recompose suffixe puis de le parcourir en ordre prexe. . .
Chapitre 3
Corrige des exercices
Exercice 3.1
La seule reelle diculte est dans la suppression de la racine dun arbre binaire qui a deux ls non vides.
Je propose dans ce cas de substituer `a la racine le plus petit element du ls droit, cest-`a-dire lelement
le plus profond ` a gauche de ce sous-arbre. On obtient le programme suivant :
let rec recherche phi arbre x = match arbre with
| Vide -> failwith "

Element absent"
| Nud(a,g,d)
-> a = x || recherche phi (if phi(x) < phi(a) then g else d) x ;;
let rec ajout phi arbre x = match arbre with
| Vide -> Nud(x,Vide,Vide)
| Nud(a,g,d)
-> if a = x then arbre
else if phi(x) < phi(a)
then Nud(a,(ajout phi g x),d)
else Nud(a,g,(ajout phi d x)) ;;
let rec supprime phi arbre x =
let rec cherche_min = function
| Vide -> failwith "Erreur de programmation"
| Nud(a,Vide,d) -> a,d
| Nud(a,g,d) -> let mini,g = cherche_min g
in
mini,Nud(a,g,d)
in
let et^ete = function
| Vide -> Vide
| Nud(_,Vide,Vide) -> Vide
| Nud(_,Vide,d) -> d
| Nud(_,g,Vide) -> g
| Nud(_,g,d) -> let min_droit,d = cherche_min d
in
Nud(min_droit,g,d)
in
match arbre with
| Vide -> Vide
| Nud(a,g,d)
-> if a = x then et^ete arbre
else if phi(x) < phi(a)
then Nud(a,(supprime phi g x),d)
else Nud(a,g,(supprime phi d x)) ;;
Exercice 3.2
let mesure_equilibrage arbre =
97
98 CHAPITRE 3. EXERCICES SUR ARBRES DE RECHERCHE
let rec mesure_profondeur = function
| Vide -> Vide
| Nud(a,g,d)
-> match (mesure_profondeur g),(mesure_profondeur d) with
| Vide,Vide -> Nud((a,0,0),Vide,Vide)
| Vide,(Nud((_,kgd,kdd),gd,dd) as d)
-> Nud((a,0,max kgd kdd + 1),Vide,d)
| (Nud((_,kgg,kdg),gg,dg) as g),Vide
-> Nud((a,max kgg kdg + 1,0),g,Vide)
| (Nud((_,kgg,kdg),gg,dg) as g),
(Nud((_,kgd,kdd),gd,dd) as d)
-> Nud((a,max kgg kdg + 1,max kgd kdd + 1),g,d)
in
let rec mesure = function
| Vide -> Vide
| Nud((a,kg,kd),g,d)
-> Nud((a,kg-kd),(mesure g),(mesure d))
in
mesure (mesure_profondeur arbre) ;;
Exercice 3.3
On dispose toujours de linegalite / lg n|, qui est valable pour tous les arbres. Les arbres complets
realisent legalite, et comme ils sont clairement AVL, cela prouve que cette borne est atteinte.
On cherche donc ` a determiner maintenant les arbres AVL les plus profonds possible pour un n xe, cest-
`a-dire encore les plus desequilibres.
`
A une symetrie pr`es, il sagit des arbres dont chaque nud interne
penche `a gauche.
Voici les arbres correspondants, pour les profondeurs 1, 2, 3 et 4.

`
`
`

`
`
`

`
`
`

`
`
`
`

`
`
`

99
Notons 1
k
larbre de profondeur / ainsi construit. 1
k+2
se construit de la facon suivante : on cree un
nouveau nud, on lui accroche comme ls gauche 1
k+1
et 1
k
comme ls droit.
Ces arbres sont appeles arbres de Fibonacci. Si n
k
est la taille de 1
k
, on obtient aussit ot n
k+2
= 1 +
n
k+1
+ n
k
, avec comme conditions initiales n
1
= 2 et n
2
= 4 (on peut aussi poser n
0
= 1). Les (1 + n
k
)
constituent donc la suite de Fibonacci. . .
On a donc n
k
=
_
1+
2

5
5
_

k
+
_
1
2

5
5
_
(1,)
k
1, ce qui fournit notre majoration asymptotique :
/ log

n + O(1) 1,44 lg n.
Voici, au passage, une fonction de construction des squelettes binaires de Fibonacci.
type squelette = Vide | Jointure of squelette * squelette ;;
let rec fibonacci = function
| 0 -> Jointure(Vide,Vide)
| 1 -> Jointure(Jointure(Vide,Vide),Vide)
| n -> Jointure(fibonacci (n-1),fibonacci (n-2)) ;;
Exercice 3.4
Il faudra enregistrer aux feuilles qui ont trois ls deux valeurs pour discriminer ces ls. On trouvera dans
la gure suivante un exemple darbre 23 de recherche.
6 15
4 9 13 4
4 6 8 12 15 16 19
Le type Caml correspondant est :
type (f,n) arbre23 =
| Feuille f
| Nud2 of n * arbre23 * arbre23
| Nud3 of n * n * arbre23 * arbre23 * arbre23 ;;
100 CHAPITRE 3. EXERCICES SUR ARBRES DE RECHERCHE
La fonction de recherche secrit simplement :
let rec recherche phi arbre x = match arbre with
| Feuille(f) -> x = f
| Nud2(a,g,d) -> recherche phi (if phi x > a then d else g) x
| Nud3(a,b,g,m,d)
-> recherche phi
(if phi x > b then d
else if phi x > a then m
else g) x ;;
Soit c un arbre 23 de profondeur / possedant n feuilles. Si tous ses nuds sont `a 2 ls, on sait que
n = 2
k
. De meme si tous ses nuds ont 3 ls, on aura n = 3
k
. En general on a donc
0,63 lg n log
3
n / lg n.
Chapitre 5
Corrige des exercices
Exercice 5.1
let recompose_suffixe_naire liste arite =
let rec depile k liste =
if k = 0 then [],liste
else match liste with
| t :: q
-> let q1,q2 = depile (k-1) q
in
t::q1 , q2
| _ -> failwith "Description suffixe incorrecte"
in
let rec recompose ss_arbres liste = match ss_arbres,liste with
| a,(F f) :: reste
-> recompose (Feuille(f) :: a) reste
| a,(N n) :: reste
-> let k = arite n
in
let fils,a = depile k a
in
recompose (Nud(n,fils) :: a) reste
| [ arbre ],[]
-> arbre
| _ -> failwith "Description suffixe incorrecte"
in
recompose [] liste ;;
Exercice 5.2
On propose le programme suivant.
let rec imprime_expression expr =
let parenth`ese expr =
print_char ( ; imprime_expression expr ; print_char)
in
let est_atome = function
| Constante(_) -> true
| Variable(_) -> true
| Application(_) -> true
| _ -> false
in
match expr with
| Constante(x) -> print_float x
| Variable(v) -> print_char v
| Application(f,u)
-> print_string (match f with
| Sin -> "sin"
101
102 CHAPITRE 5. EXERCICES SUR ARBRES -AIRES
| Cos -> "cos"
| Exp -> "exp"
| Ln -> "ln") ;
parenth`ese u
| Terme(u,^,v)
-> if est_atome u then imprime_expression u
else parenth`ese u ;
print_char ^ ;
if est_atome v then imprime_expression v
else parenth`ese v
| Terme(u,/,v)
-> ( match u with
| Terme(_,+,_) -> parenth`ese u
| Terme(_,-,_) -> parenth`ese u
| _ -> imprime_expression u ) ;
print_char / ;
( match v with
| Application(_) -> imprime_expression v
| Constante(_) -> imprime_expression v
| Variable(_) -> imprime_expression v
| Terme(_,^,_) -> imprime_expression v
| _ -> parenth`ese v )
| Terme(u,*,v)
-> ( match u with
| Terme(_,+,_) -> parenth`ese u
| Terme(_,-,_) -> parenth`ese u
| _ -> imprime_expression u ) ;
print_char * ;
( match v with
| Terme(_,+,_) -> parenth`ese v
| Terme(_,-,_) -> parenth`ese v
| _ -> imprime_expression v )
| Terme(u,+,v)
-> imprime_expression u ;
print_char + ;
imprime_expression v
| Terme(u,-,v)
-> imprime_expression u ;
print_char - ;
match v with
| Terme(_,-,_) -> parenth`ese v
| _ -> imprime_expression v ;;
Chapitre 6
Corrige des exercices
Exercice 6.1
On trouve sans diculte un automate deterministe pour le premier langage propose :
1 2 1
b b
a
a
De meme, pour le second :
1 2 3 4 1 2 3
a a a
a
b b
b
b
Pour le troisi`eme, il est plus simple de fournir un automate non deterministe :
1 2 3 4 55
i n
f
o

Exercice 6.2
On peut tenter une determinisation `a la main. Voil` a ce qui fut ma premi`ere tentative :
1 2 3 4 55
i
n
f
o
A \ {f}
A \ {n}
A \ {o}
A \ {i}
A
103
104 CHAPITRE 6. EXERCICES SUR AUTOMATES FINIS
Une etiquette comma o sur une transition signie quelle a lieu sur tout caract`ere de lalphabet
sauf o.
Un petit peu de reexion montre que cet automate est incorrect. . . On peut par exemple tester cet
automate sur la chane iin)o pour sen convaincre.
En fait, il vaut mieux se er aux methodes du cours (evidemment !), et appliquer lalgorithme de
determinisation. On obtient, apr`es simplication (regroupement des etats nals), lautomate deterministe
suivant :
1
2 3
4
55
i
fno

n
i
fo
i
f i
no
fn
o
Cette fois, letiquette sur une transition signie quelle a lieu sur tout caract`ere qui nest pas dans
i, n, ), o.
Exercice 6.3
Soit lafnd propose, et lafd que construit lalgorithme. On notera
1
c,

2
les transitions de et
Q
1
c,
Q
2
celles de .
La preuve de lalgorithme est alors aisee : pour chaque etat Q de il sut de montrer par recurrence
par recurrence sur la longueur dun mot n que si Q
w,
Q

alors Q

, Q,
w,

.
La demonstration est claire pour n = , puisquon a ferme tous les etats de . La construction meme des
etats de permet de conclure quand n = c : il sut de decouper n en chane-prexe et caract`ere nal.
On conclut en prenant Q = (
0
), etat initial de : un mot n sera reconnu par si et seulement si il est
reconnu par .
Exercice 6.4
1(

) est simplement le complementaire (dans lensemble de tous les mots sur lalphabet quon sest xe)
de 1() = 1().
En revanche, `a cause de labsence detat mort dans , il faut tenir compte des possibilites de blocage de
la reconnaissance. Ainsi 1(

) est-il la partie de 1(

) consistant en tous les mots qui ne provoquent pas


105
de blocage de et qui ne sont pas acceptes par . Bref il sagit des mots n tels que
0
w
avec non
nal dans .
Exercice 6.5
On obtient bien s ur le meme automate, chaque etat de letat initial correspondant ` a son singleton, ` a ceci
pr`es quon a ajoute un etat mort (qui correspond `a un ensemble vide detats de lautomate initial).
Exercice 6.6
Nous utiliserons ici une nouvelle representation des afd.
Un automate sera represente par un vecteur detats, chaque etat etant un objet Caml du type suivant :
type etat_afd_vectoriel == bool * (int vect) ;;
Le booleen dit si letat est terminal, et le vecteur decrit les transitions sur les 256 caract`eres : une
transition est representee par le numero de letat resultat.
La partition de lensemble des etats sera representee par un vecteur de listes dentiers : chacune contient
les numeros des etats de la partie consideree de la partition.
La fonction suivante partage les etats de lautomate en nals et non-nals.
let rec isole_finals qv i n =
if i = n then [],[]
else let finals,non_finals = isole_finals qv (i + 1) n
in
if fst qv.(i) then (i :: finals),non_finals
else finals,(i :: non_finals) ;;
Elle prend en argument le vecteur des etats, i qui doit valoir 0 pour tout balayer, et la taille du vecteur.
Elle renvoie un couple de listes.
La fonction suivante renvoie le numero du paquet de la partition qui contient un etat donne.
exception Trouve of int ;;
let numero_partie q partition =
let n = vect_length partition
in
try
for i = 0 to n - 1 do
if mem q partition.(i) then raise (Trouve(i))
done ;
n
with Trouve(i) -> i ;;
Voici maintenant une fonction plus compliquee :
let repartit l =
let rec ajoute (q,dest) = function
| [] -> [ dest , [ q ] ]
| (u,l) :: r when dest = u -> (u,q::l) :: r
| (u,l) :: r -> (u,l) :: (ajoute (q,dest) r)
in
let rec rep l res =
match l with
| [] -> map snd res
| (q,dest) :: r -> rep r (ajoute (q,dest) res)
in
rep l [] ;;
Elle prend en argument une liste de couples (q,dest) dont le premier element est un etat de lautomate
et le second letat auquel une transition le conduit. Elle renvoie une liste de couples (dest,liste) dont
le premier element est un etat-cible et le second est la liste des elements q de depart dans la liste fournie
en argument.
On est alors en mesure decrire le cur de lalgorithme.
106 CHAPITRE 6. EXERCICES SUR AUTOMATES FINIS
let calcule_minimal qv =
let n = vect_length qv
in
let partition = make_vect n []
and taille_partition = ref 2
and encore = ref true
in
let partage i ll =
let nll = list_length ll
in
let rec rangement ll k = match ll with
| [] -> ()
| l :: ql -> partition.(k) <- l ; rangement ql (k + 1)
in
partition.(i) <- hd ll ;
rangement (tl ll) !taille_partition ;
taille_partition := !taille_partition + nll - 1 ;
if nll > 1 then raise
`
ASuivre else ()
in
( match isole_finals qv 0 n with
| [],l -> ( partition.(0) <- l ; taille_partition := 1 )
| l,[] -> ( partition.(0) <- l ; taille_partition := 1 )
| l1,l2 ->( partition.(0) <- l1 ; partition.(1) <- l2 ) ) ;
while !encore do
try
encore := false ;
for i = 0 to !taille_partition - 1 do
if list_length partition.(i) > 1 then
for c = 0 to 255 do
let l = map
(function q
-> q,
(numero_partie (snd qv.(q)).(c) partition))
partition.(i)
in
partage i (repartit l) ;
done
done
with
`
ASuivre -> encore := true
done ;
( partition,!taille_partition ) ;;
La fonction partage prend la liste creee par la fonction repartit decrite ci-dessus, et modie en
consequence la partition. Il ny a presque plus rien ` a faire pour terminer :
let minimise automate =
let n = vect_length automate
and partition,k = calcule_minimal automate
in
let mini = make_vect k (true,[| |])
in
for i = 0 to k - 1 do
let x = automate.(hd partition.(i))
in
mini.(i) <- (fst x),(make_vect 256 0) ;
match mini.(i) with _,v -> for c = 0 to 255 do
v.(c) <- numero_partie (snd x).(c) partition
done
done ;
mini ;;
Chapitre 7
Corrige des exercices
Exercice 7.1
On a dej`a repondu ` a la question pour le complementaire dans lexercice 6.4 : on a su construire un afd qui
reconnat le complementaire du langage dun afd xe.
On sait que lunion de deux langages rationnels est un langage rationnel, passant aux complementaires,
on en deduit le resultat sur lintersection (meme sil nest pas evident de construire lautomate de linter-
section. . . )
Exercice 7.2
Il sagit `a chaque fois de prouver legalite de deux ensembles, donc deux inclusions. On pourra proceder
par recurrence sur la taille des mots. On montre de facon analogue : (c
1
[c
2
) (c
2
c
1
)c
2
.
Exercice 7.3
Il sut de considerer un automate ni deterministe qui reconnat le langage, et de considerer tous les
etats `a la fois comme initiaux et nals.
Exercice 7.4
Les deux automates ayant la meme transition de letat 2 vers letat 3, on peut se contenter de montrer
lequivalence des automates deduits de ceux proposes par suppression du dernier etat.
On ecrit les expressions reguli`eres correspondantes ` a ces automates. On trouve facilement (c[/)c pour
le premier : ce sont l`a les mots qui se terminent par un c. Pour le second, on trouve une expression plus
compliquee :
/c(c[//c).
En utilisant les r`egles exposees dans lexercice 7.2, on ecrit successivement :
/c(c[//c) /c[/c(c[//c)(c[//c)
/([c(c[//c)([//))c
/([c(c[//c)/)c
/([c(([//)c)/)c
/([c(/c)/)c
/([c(c[/))c
107
108 CHAPITRE 7. EXERCICES SUR LANGAGES RATIONNELS ET AUTOMATES
On conclut en remarquant que :
(c[/)c /(c/)c
/([c/(c/))c
/([c(c[/))c
Exercice 7.5
Utilisons le lemme de letoile : il existe un entier i qui verie les proprietes du lemme. Soit n i, c
n
/c
n
est reconnu, donc secrit sous la forme ::t o` u : est de longueur au plus egale `a i et o` u les mots ::t sont
reconnus. Si : contient un /, on trouverait des mots du langage avec plusieurs /. Sinon, : = c
k
, : = c
p
,
et t = c
nkp
/c
n
. Mais alors :::t = c
n+p
/c
n
serait dans le langage.
Pour le deuxi`eme langage, procedons ainsi : soit i le nombre detats dun afd qui reconnat notre langage,
et soit
0
son etat initial. Appelons
i
letat deni par
0
(ab)
i

i
(pas de probl`eme car (c/)
i
(/c)
i
est bien
reconnu). Necessairement, on peut trouver 0 i < , i tels que
i
=
j
. Alors
0
(ab)
i+k(ji)

i
=
j
pour tout entier /. Alors tous les mots (c/)
i+k(ji)
(/c)
i
sont reconnus, puisque
i
(ba)
i

f
avec
f
nal.
Ces mots netant pas de la forme requise pour / 1, notre langage nest pas rationnel.
Exercice 7.6
Pour le premier langage : (c[/)c(c[/).
Pour le deuxi`eme : /(c[)/.
Pour le troisi`eme : (/[cc).
Pour le quatri`eme, on peut commencer par construire lautomate correspondant :
1 3
4
2
1 3
4
2
b
a
c
a c
a
b
b
c
On utilisera alors la methode du cours pour obtenir lexpression reguli`ere cherchee. Mais il est tout aussi
simple de tout faire `a la main.
Appelons A le motif qui decrit tous les mots de notre langages qui ne contiennent pas de c. Il est facile
`a expliciter :
A = ([c)(/c)([/).
109
Il nest alors pas dicile decrire une expression reguli`ere solution de notre probl`eme :
([A)(cA)([c).
On aura note quil sagit de la meme expression `a substitution pr`es de c en A et de / en c : on pourrait
ainsi generaliser au langage des mots ecrits sur n lettres sans repetition.