Docstoc

cours

Document Sample
cours Powered By Docstoc
					Option informatique :
           e      e
  la deuxi`me ann´e




               Laurent Cheno
                         ´


                       ee
                       ´t´ 




       ´
    Lycee Louis-le-Grand, Paris
              e
Table des mati`res

I   Arbres                                                                                                                                                           13
1 Arbres binaires                                                                                                                                                    15
        e
  1.1 D´finitions et notations . . . . . . . . . . . . . . . .                    . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   15
               e
      1.1.1 D´finition formelle d’un arbre binaire . . . .                        . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   15
               e
      1.1.2 D´finition des arbres binaires en Caml . . . .                        . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
                                  ee
      1.1.3 Une indexation des ´l´ments constitutifs d’un                        arbre           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
  1.2 Notion de profondeur dans un arbre . . . . . . . . .                       . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17
               e
      1.2.1 D´finitions . . . . . . . . . . . . . . . . . . .                     . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17
      1.2.2 Calcul de la profondeur en Caml . . . . . . .                        . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
  1.3 Squelette d’un arbre binaire . . . . . . . . . . . . . .                   . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
      1.3.1 Un exemple . . . . . . . . . . . . . . . . . . .                     . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
               e
      1.3.2 D´finition du squelette . . . . . . . . . . . . .                     . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
                                                e
      1.3.3 Le squelette comme une classe d’´quivalence                          . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
             ´
      1.3.4 Ecriture en Caml . . . . . . . . . . . . . . . .                     . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
  1.4 Combinatoire des arbres et squelettes binaires . . . .                     . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
      1.4.1 Nœuds et feuilles . . . . . . . . . . . . . . . .                    . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
      1.4.2 Profondeur et taille . . . . . . . . . . . . . . .                   . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
               e
      1.4.3 D´nombrement des squelettes binaires . . . .                         . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
  1.5 Exercices pour le chapitre 1 . . . . . . . . . . . . . .                   . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24

2 Parcours d’un arbre                                                                                                                                                27
  2.1 Parcours en largeur d’abord . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      2.1.1 Description de l’ordre militaire     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      2.1.2 Programmation Caml . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
  2.2 Parcours en profondeur d’abord . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
                         e
      2.2.1 Parcours pr´fixe, infixe, suffixe        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
      2.2.2 Programmation en Caml . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   29
                  e
      2.2.3 Probl`me inverse . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   29
  2.3 Exercices pour le chapitre 2 . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   30

3 Arbres de recherche                                                                                                                                                31
        e
  3.1 D´finition d’un arbre binaire de recherche          . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
               e        e e
      3.1.1 D´finition g´n´rale . . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
      3.1.2 Cas particulier . . . . . . . . . . .        . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
                     ee
  3.2 Recherche d’un ´l´ment . . . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
                              e
      3.2.1 Position du probl`me . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
      3.2.2 Recherche dans un arbre binaire de           recherche               .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   32
             ´
      3.2.3 Evaluation . . . . . . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   32
  3.3 Structure dynamique de recherche . . . .           . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
                        ee
      3.3.1 Ajout d’un ´l´ment . . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
                              ee
      3.3.2 Suppression d’un ´l´ment . . . . .           . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
      3.3.3 Application au tri . . . . . . . . .         . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   34

                                                         3
4                                                                                                                          `
                                                                                                             TABLE DES MATIERES

                          e         e
           3.3.4 Le probl`me de l’´quilibrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                  35
     3.4   Exercices pour le chapitre 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                35

4 Tri et tas                                                                                                                                                 37
         e e    e
  4.1 G´n´ralit´s . . . . . . . . . . . . . . .      . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37
                             e
       4.1.1 Files de priorit´ . . . . . . . . .     . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37
       4.1.2 Tas . . . . . . . . . . . . . . . .     . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37
                   e                    a
       4.1.3 Impl´mentation des tas ` l’aide         de tableaux     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   38
  4.2 Percolation . . . . . . . . . . . . . . .      . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   39
       4.2.1 Description de l’algorithme . .         . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   39
       4.2.2 Programmation . . . . . . . . .         . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
              ´
       4.2.3 Evaluation . . . . . . . . . . .        . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42
                              e
       4.2.4 Application : cr´ation d’un 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 arithm´tiquese                                                                                                               45
  5.1 Arbres n-aires . . . . . . . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   45
               e
      5.1.1 D´finition . . . . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   45
                  e
      5.1.2 Impl´mentation . . . . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
                    ee
      5.1.3 Propri´t´s . . . . . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
      5.1.4 Parcours d’un arbre n-aire . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
                          e
  5.2 Expressions arithm´tiques . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   47
                    e
      5.2.1 Une d´finition . . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   47
                            e
      5.2.2 Syntaxe concr`te et syntaxe abstraite . .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   48
      5.2.3 Expressions et arbres . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   49
        e
  5.3 D´rivation formelle . . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   50
               e              e
      5.3.1 D´rivation guid´e par la structure d’arbre           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   50
                                          e
      5.3.2 Simplification : une premi`re approche . .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   53
  5.4 Exercices pour le chapitre 5 . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   55


II     Automates                                                                                                                                             57
                     e                         e
6 Automates finis d´terministes ou non d´terministes                                                                                                          59
                        e
  6.1 Automates finis d´terministes . . . . . . . . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   59
                e
      6.1.1 Pr´sentation informelle . . . . . . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   59
                e               e
      6.1.2 Pr´sentation math´matique . . . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   60
      6.1.3 Transitions et calculs . . . . . . . . . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   60
                                                        e
      6.1.4 Langage reconnu par un automate fini d´terministe                         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   61
           e
  6.2 Impl´mentation en Caml d’un afd . . . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   61
                            e
  6.3 Automates finis non d´terministes . . . . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   62
                e
      6.3.1 Pr´sentation informelle . . . . . . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   62
               e             e
      6.3.2 D´finition math´matique . . . . . . . . . . . . . .                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   63
           e
  6.4 Impl´mentation en Caml d’un afnd . . . . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   64
        e
  6.5 D´terminisation d’un afnd . . . . . . . . . . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   67
                              e
      6.5.1 Algorithme de d´terminisation . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   67
      6.5.2 Programmation en Caml . . . . . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   69
  6.6 Exercices pour le chapitre 6 . . . . . . . . . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
              `
TABLE DES MATIERES                                                                                                                                             5

7 Langages rationnels et automates                                                                                                                            75
                                           e    e
  7.1 Langages rationnels et expressions r´guli`res .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    75
               e
      7.1.1 D´finition . . . . . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    75
                           e   e
      7.1.2 Expressions r´guli`res . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    76
           e e
  7.2 Le th´or`me 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
                             e
      7.3.2 Le lemme de l’´toile . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    83
  7.4 Exercices pour le chapitre 7 . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    84


III         e
      Corrig´ de tous les exercices                                                                                                                          87
1 Exercices sur Arbres binaires                                                                                                                               89

2 Exercices sur Parcours d’un arbre                                                                                                                           93

3 Exercices sur Arbres de recherche                                                                                                                           97

5 Exercices sur Arbres n-aires                                                                                                                               101

6 Exercices sur Automates finis                                                                                                                               103

7 Exercices sur Langages rationnels et automates                                                                                                             107
Table des figures

 1.1    Premiers exemples d’arbres .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   15
 1.2    Indexation d’un arbre binaire    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17
 1.3             ıt´
        Ambigu¨ e de l’indexation . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17
 1.4    Construction du squelette . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   18
 1.5    Taille et profondeur . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   20
 1.6    Squelettes d’arbres complets .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22

 2.1    Un arbre pour l’exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                        27
 2.2          u e
        Ambig¨it´ de la description infixe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                        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                      e
        Une file de priorit´ . . . . . . . . . . . .              .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37
 4.2    Un tas . . . . . . . . . . . . . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   38
 4.3                        e
        Un tas avec sa num´rotation des nœuds                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   38
 4.4              a
        Un arbre ` percoler . . . . . . . . . . . .              .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   39
 4.5      e            e
        L’´tape interm´diaire de la percolation .                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   40
 4.6    Le tas obtenu par percolation . . . . . .                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   40

 5.1    Un exemple d’arbre n-aire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                        45
 5.2                              e                 e
        Un autre arbre n-aire de mˆme parcours pr´fixe . . . . . . . . . . . . . . . . . . . . . . . .                                                                            47

 6.1                                         e
        Un premier exemple d’automate fini d´terministe                               .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   59
 6.2                               e
        Deux automates pour un mˆme langage . . . . .                                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   61
 6.3                           e
        Un automate fini non d´terministe . . . . . . . .                             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   63
 6.4    Un afnd pour les mots qui finissent par ab . . . .                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   64
 6.5    Un afnd pour les mots finissant par abab . . . . .                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   67
 6.6                 e       e
        L’automate d´terminis´ . . . . . . . . . . . . . .                           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   68
 6.7            a      e               u
        Un afnd ` la d´terminisation coˆteuse . . . . . .                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   69

 7.1                                      e    e
        Automates pour les expressions r´guli`res atomiques . .                                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   78
 7.2                                                      e
        Automate pour la somme de deux expressions r´guli`res  e                                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   78
 7.3                                                      e
        Automate pour le produit de deux expressions r´guli`res e                                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   79
 7.4                      e                        e    e
        Automate pour l’´toile d’une expression r´guli`re . . . .                                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   79
 7.5                              e
        Avant la suppression de l’´tat x . . . . . . . . . . . . . .                                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   80
 7.6       e                      e
        Apr`s la suppression de l’´tat x . . . . . . . . . . . . . .                                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   80
 7.7               a e
        Automate ` 2 ´tats . . . . . . . . . . . . . . . . . . . . .                                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   80
 7.8    Quel est le langage reconnu par cet automate ? . . . . .                                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   81
 7.9                   e e
        On a supprim´ l’´tat 2 . . . . . . . . . . . . . . . . . . .                                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   81
 7.10      e                   e
        Apr`s suppression des ´tats 2 et 4 . . . . . . . . . . . .                                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   82
 7.11                                     e
        On recommence en supprimant l’´tat 2 . . . . . . . . . .                                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   82
 7.12      e                   e
        Apr`s suppression des ´tats 2 et 3 . . . . . . . . . . . .                                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   82

                                                                     7
Liste des programmes

 1.1     e
        D´finition du type arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                           16
 1.2    Calcul de la profondeur d’un arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                        18
 1.3    Nombre de nœuds, de feuilles d’un arbre, taille d’un squelette . . . . . . . . . . . . . . .                                                                            20

 2.1    Parcours d’un arbre binaire en ordre militaire . . . . . . . . . . . .                                                  . . . . .           .   .   .   .   .   .   .   28
 2.2                                            e
        Parcours d’un arbre binaire en ordres pr´fixe, infixe et suffixe . . . .                                                    . . . . .           .   .   .   .   .   .   .   29
 2.3                                      `
        Reconstitution d’un arbre binaire a partir de sa description en ordre                                                     e
                                                                                                                                pr´fixe .            .   .   .   .   .   .   .   29
 2.4                                      `
        Reconstitution d’un arbre binaire a partir de sa description en ordre                                                   suffixe .             .   .   .   .   .   .   .   30

 3.1                 e
        Recherche s´quentielle 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                 ee
        Ajout d’un ´l´ment dans un arbre binaire de recherche . . .                                             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
 3.5                       ee
        Suppression d’un ´l´ment dans un arbre binaire de recherche                                             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
 3.6        `
        Tri a l’aide d’arbres binaires de recherche . . . . . . . . . . .                                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35

 4.1                 e
        Percolation r´cursive . . . .     . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
 4.2                  e
        Percolation it´rative . . . . .   . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
 4.3     e
        R´organisation d’un arbre en      tas   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42
 4.4    Le tri par tas (heap sort) . .    . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   43

 5.1    Nombre de nœuds et feuilles d’un arbre n-aire . . . . . . . . . .                                               .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
 5.2    Profondeur d’un arbre n-aire . . . . . . . . . . . . . . . . . . . .                                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
 5.3                e
        Parcours pr´fixe et suffixe d’un arbre n-aire . . . . . . . . . . . .                                              .   .   .   .   .   .   .   .   .   .   .   .   .   .   47
 5.4                                     a                             e
        Reconstitution d’un arbre n-aire ` partir de son parcours pr´fixe                                                .   .   .   .   .   .   .   .   .   .   .   .   .   .   48
 5.5                                                         e
        Conversions arbres d’expression/expressions arithm´tiques . . .                                                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   49
 5.6    ´                                 e
        Evaluation des expressions arithm´tiques . . . . . . . . . . . . .                                              .   .   .   .   .   .   .   .   .   .   .   .   .   .   50
 5.7                  e
        Impressions pr´fixe et suffixe des expressions . . . . . . . . . . .                                               .   .   .   .   .   .   .   .   .   .   .   .   .   .   51
 5.8    Impression infixe des expressions . . . . . . . . . . . . . . . . . .                                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   52
 5.9      e                                        e
        D´rivation formelle des expressions arithm´tiques . . . . . . . .                                               .   .   .   .   .   .   .   .   .   .   .   .   .   .   52
 5.10                                    e
        Simplification des expressions alg´briques . . . . . . . . . . . . .                                             .   .   .   .   .   .   .   .   .   .   .   .   .   .   54

 6.1                               ıne
        Reconnaissance d’une chaˆ par un afd .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   62
 6.2    Quelques fonctions utiles . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   65
 6.3                               ıne
        Reconnaissance d’une chaˆ par un afnd                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   66
 6.4    Fonctions utiles sur les ensembles . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
 6.5        e
        La d´terminisation des automates . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   72




                                                                    9
Liste des exercices

 Exercice   1.1   Indexation d’un arbre binaire . . . . . . . .           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
 Exercice   1.2                                     e
                  Sous-arbres de profondeur donn´e . . . . .              .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
 Exercice   1.3   Calcul du squelette . . . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
 Exercice   1.4     e e
                  G´n´ration des squelettes d’arbres binaires             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
 Exercice   1.5                                             e
                  Squelette d’arbre complet de taille donn´e .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   24
 Exercice   1.6                  e
                  Test de compl´tude . . . . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
 Exercice   1.7          e
                  Test d’´quilibrage . . . . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25

                             a
 Exercice 2.1 Reconstitution ` partir de l’ordre militaire . . . . . . . . . . . . . . . . . . . . . . .                                                          30
                             e
 Exercice 2.2 Conversions pr´fixe/suffixe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                              30

 Exercice   3.1   Une autre structure d’arbre de recherche        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
 Exercice   3.2              e
                  Balance et ´quilibrage . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
 Exercice   3.3   Taille d’un arbre AVL . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   36
 Exercice   3.4   Arbres 2–3 . . . . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   36

                                               `
 Exercice 5.1 Reconstitution d’un arbre n-aire a partir du parcours suffixe . . . . . . . . . . . . .                                                               55
 Exercice 5.2 Impression infixe des expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                            55

 Exercice   6.1   Quelques automates simples . .    . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
 Exercice   6.2    e
                  D´terminisation d’un automate     simple    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
 Exercice   6.3                 e
                  Preuve de la d´terminisation .    . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
 Exercice   6.4              e
                  Ajout d’un ´tat mort . . . . .    . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   71
 Exercice   6.5    e
                  D´terminisation d’un afd ! . .    . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   73
 Exercice   6.6   Minimisation d’un afd . . . . .   . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   73

 Exercice   7.1                                             e
                  Langages rationnels, intersection et compl´mentaire                         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   84
 Exercice   7.2   ´                             e   e
                  Equivalence des expressions r´guli`res . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   84
 Exercice   7.3   Le langage des facteurs des mots d’un langage . . .                         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   84
 Exercice   7.4                          e
                  Reconnaissance d’un mˆme langage . . . . . . . . .                          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   84
 Exercice   7.5   Exemples de langages non rationnels . . . . . . . . .                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   84
 Exercice   7.6                e    e     e
                  Expressions r´guli`res d´crivant des langages donn´se                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   85




                                                       11
     e
Premi`re partie

   Arbres




       13
Chapitre 1

Arbres binaires

1.1       e
         D´finitions et notations
1.1.1      e
          D´finition formelle d’un arbre binaire
      c             e          e      e
Commen¸ons par une d´finition tr`s math´matique.

  e                                             e
D´finition 1.1 (Arbres binaires) On consid`re deux ensembles de valeurs F (valeurs des feuilles) et N
                                                                   e         c e
(valeurs des nœuds). Un arbre binaire sur ces ensembles est d´fini de fa¸on r´cursive comme suit. Toute
                                       ´
feuille, ´l´ment de F , est un arbre. Etant donn´s une valeur n de nœud (n ∈ N ), et deux arbres g et d,
         ee                                        e
(n, g, d) est un nouvel arbre, de racine n, de fils gauche g, de fils droit d.
    e                              e
La d´finition que nous avons donn´e ici permet de distinguer le type des informations port´es respective-e
ment par les nœuds et les feuilles d’un arbre.
                                   e
On utilise d’habitude, au lieu d’´critures comme f pour une simple feuille, ou encore, pour donner
                                                                                           e
un exemple plus complexe, (n1 , (n2 , f21 , f22 ), (n3 , f31 , (n4 , f41 , f42 ))), la repr´sentation graphique qu’on
trouvera dans la figure suivante.
                                                                            
                     f                                                    n1
                                                                    
                                                                     d
                                                                       d 
                                                               
                                                                        d
                                                               n2                    n3
                                                                                
                                                                ¡
                                                                ¡ e                ¡
                                                                                   ¡ e
                                                              ¡     e
                                                                    e            ¡     e
                                                                                       
                                                                                       e
                                                         f21        f22        f31         n4
                                                                                           
                                                                                            ¡
                                                                                            ¡ e
                                                                                          ¡     e
                                                                                                e
                                                                                     f41        f42



                                     Fig. 1.1: Premiers exemples d’arbres

                e                                  e a                 e
Dans cette repr´sentation, les feuilles sont dessin´es ` l’aide de carr´s, les nœuds par des cercles. Notons
que certains auteurs utilisent les expressions nœuds externes pour les feuilles et nœuds internes pour ce
                      e
que nous avons appel´ les nœuds.
        e                                                                       u
La repr´sentation graphique introduit la notion de haut et de bas, et bien sˆr les informaticiens ayant la
 e           a
tˆte un peu ` l’envers, tous nos arbres auront leurs feuilles en bas et leur racine en haut. . .
                    e                        e                                              e
Pour illustrer nos d´finitions, tentons de d´crire avec notre nouveau vocabulaire le deuxi`me arbre de la
figure ci-dessus. Sa racine est le nœud n1 , qui a deux fils, les arbres de racines n2 et n3 . Le sous-arbre

                                                         15
16                                                                   CHAPITRE 1. ARBRES BINAIRES

gauche de racine n2 a pour fils gauche et droit deux feuilles, tandis que le sous-arbre droit de racine n3 a
                                                                                                  `
respectivement pour fils gauche et droit une feuille et un nouveau sous-arbre de racine n4 qui a son tour
a pour fils gauche et droit deux feuilles.
                                                                    a                           `
Le plus souvent, on se permettra l’abus de langage qui consiste ` citer un nœud en pensant a l’arbre (le
sous-arbre) dont il est racine. Ainsi n2 d´signera-t-il tout aussi bien le nœud pr´cis qui porte ce nom que
                                          e                                       e
tout le sous-arbre qui l’admet pour racine.
                                                        e
Remarquons pour terminer que toute feuille figure n´cessairement en bas de l’arbre, puisqu’elle ne peut
                                        e
avoir de fils. Enfin, on dit que a est p`re de b aussi bien quand b est une feuille qui est un fils (droit ou
gauche) de a et quand b est la racine du sous-arbre fils droit ou gauche de a.

1.1.2     e
         D´finition des arbres binaires en Caml
                 e             `       e                                                              a
En Caml, on d´finit un type a deux param`tres qui sont les types respectifs des feuilles et des nœuds, `
l’aide de l’instruction suivante :

               e
Programme 1.1 D´finition du type arbre binaire
           type (’f,’n) arbre_binaire =
                 | Feuille of ’f
                 | Nœud of ’n * (’f,’n) arbre_binaire * (’f,’n) arbre_binaire ;;



    e                                             a
On d´finira les deux arbres de l’exemple ci-dessus ` l’aide d’instructions comme
      let f = Feuille("f")
      and a = Nœud("n1", Nœud("n2",Feuille("f21"),Feuille("f22")),
                         Nœud("n3",Feuille("f31"),Nœud("n4",Feuille("f41"),Feuille("f42")))) ;;


1.1.3                       ee
         Une indexation des ´l´ments constitutifs d’un arbre
                          e                      ee                                                   `
Nous allons maintenant d´finir une indexation des ´l´ments constitutifs d’un arbre (feuilles et nœuds) a
l’aide de mots sur l’alphabet {0, 1}.

  e                                                               e
D´finition 1.2 (Mots binaires) On appelle mot binaire toute suite ´ventuellement vide de 0 ou de 1. Autre-
                                                     e               e                   e
ment dit, un mot binaire est ou bien le mot vide, not´ , ou bien le r´sultat de la concat´nation d’un mot
binaire et d’un 0 ou d’un 1.
`                                          e                                               e
A tout mot binaire est naturellement associ´ un entier naturel, dont le mot choisi est une ´criture en base
                                               ea
2. Par exemple, le mot binaire 10010 est associ´ ` l’entier 18. Par convention, le mot vide sera associ´  e
` −∞, et on notera N = N ∪ {−∞}. Nous noterons par un di`se ( ) cette application des mots binaires
a                                                               e
vers N : ainsi ´crirons-nous 10010 = 18.
               e
                   e        ee                                                          e
On peut alors num´roter les ´l´ments d’un arbre en leur associant un mot binaire. La r`gle est fort simple,
          e
et peut s’´noncer ainsi.

  e                                      e
D´finition 1.3 (Indexation) On consid`re un arbre binaire. S’il s’agit d’une feuille, on l’indexe par le mot
vide . Si en revanche il s’agit d’un nœud (n, g, d), on commence par indexer sa racine n par le mot vide , et
                                      ee
par effectuer l’indexation de tous les ´l´ments de l’arbre g et de l’arbre d. Enfin, on ajoute devant l’index de
        ee
chaque ´l´ment de l’arbre g (resp. d) un 0 (resp. un 1).

                                             e                                  e e         u        ee
On retrouvera dans la figure suivante le deuxi`me arbre de la figure 1.1 page pr´c´dente o` chaque ´l´ment
         ea
est index´ ` sa gauche par un mot binaire.
                         e                                                                            e e
L’indexation ainsi effectu´e discrimine effectivement les feuilles de l’arbre, ce qui fait l’objet du th´or`me
suivant.

   e e
Th´or`me 1.1
Dans l’indexation pr´c´dente, si f1 et f2 sont deux feuilles distinctes d’un mˆme arbre et m1 , m2 les mots
                     e e                                                      e
binaires associ´s, on a m1 = m2 .
               e
1.2. NOTION DE PROFONDEUR DANS UN ARBRE                                                                        17
                                 
                                                      n1
                                           &
                                             
                                          &    
                                      &        
                                      &          
                                    0 n2                            1 n3
                                                                     
                                       t
                                                                      t
                                                                      
                                         t
                                          t                             t
                                                                          t
                           00 f21          01 f22          10 f31          11 n4
                                                                              
                                                                              ƒ
                                                                             
                                                                                ƒ
                                                                                 ƒ
                                                                 110 f41           111 f42



                                  Fig. 1.2: Indexation d’un arbre binaire


  4 La d´monstration se fait par r´currence structurelle.
           e                          e
                  e     a                 e
  Pour un arbre r´duit ` une feuille, le r´sultat est clair.
  Soit a = (n, g, d) un arbre. Soit f1 et f2 deux feuilles de cet arbre.
                                             e
  Ou bien f1 et f2 sont des feuilles du mˆme sous-arbre g de a. Dans ce cas leurs index m1 et m2 sont
           a
  obtenus ` partir des index m1 et m2 qu’elles portent dans l’arbre g grˆce aux relations m1 = 0m1 et
                                                                          a
                                   e        e
  m2 = 0m2 . Comme par hypoth`se de r´currence m1 = m2 , on a bien m1 = m2 .
                                               e
  Ou bien f1 et f2 sont des feuilles du mˆme sous-arbre d de a. Dans ce cas on obtient de mˆme    e
  m1 = 1m1 = 1m2 = m2 .
  Ou bien f1 est une feuille de g et f2 une feuille de d. Mais alors m1 commence par un 0 et m2 par un
  1, et donc m1 = m2 . 3

                                                a
          En revanche, il faut faire attention ` ce qu’on peut avoir m1 = m2 , comme dans le cas de la
                      u
          figure 1.3, o` les feuilles f41 et f31 ont pour index respectifs 010 et 10 qui sont bien diff´rents,
                                                                                                     e
          certes, mais pourtant 010 = 10 = 2.
                                                           
                                                            n1
                                                &
                                                  
                                               &    
                                            &       
                                            &         
                                        0 n2                              1 n3
                                                                           
                                          
                                           t                               
                                                                             t
                                             t
                                              t                             tt
                               00 f21         01 n4              10 f31          11 f32
                                                 
                                                
                                                 ƒ
                                                   ƒ
                                                    ƒ
                                    010 f41         011 f42



                                                    ıt´
                                    Fig. 1.3: Ambigu¨ e de l’indexation




1.2     Notion de profondeur dans un arbre
1.2.1     e
         D´finitions
                                                                          e
On appelle profondeur d’un nœud ou d’une feuille d’un arbre le nombre d’arˆtes qu’il faut traverser pour
                                                           e
descendre de la racine de l’arbre au nœud ou la feuille vis´(e).
18                                                                          CHAPITRE 1. ARBRES BINAIRES

        c               e                                           ee
D’une fa¸on plus math´matique, on peut dire que la profondeur d’un ´l´ment d’un arbre est la longueur
                                               e
du mot binaire qui l’indexe dans l’indexation d´crite plus haut.
                                e           e                                     ee
La profondeur de l’arbre est d´finie comme ´tant le maximum des profondeurs de ses ´l´ments, ou encore,
puisque les feuilles sont sous les nœuds, comme le maximum des profondeurs de ses feuilles.


1.2.2      Calcul de la profondeur en Caml
      u                                     ea                         e
Bien sˆr, le calcul de la profondeur est ais´ ` l’aide d’un programme r´cursif :

Programme 1.2 Calcul de la profondeur d’un arbre
                let rec profondeur = function
                    | Feuille(_) -> 0
                    | Nœud(_,g,d) -> 1 + (max (profondeur g) (profondeur d)) ;;



              e                      e                                                    o
On aura not´ que l’information port´e par les nœuds et feuilles de l’arbre ne joue aucun rˆle dans le
                         e
calcul de la profondeur, ´videmment.


1.3        Squelette d’un arbre binaire
1.3.1      Un exemple
       e     a
Consid´rons ` nouveau l’arbre de la figure 1.1 page 15. On peut commencer par effacer toute l’information
    e                                                                     ea                              e
port´e par ses nœuds et par ses feuilles. On obtient ainsi un arbre dessin´ ` l’aide de cercles et de carr´s.
                                                                                 u
Si on supprime purement et simplement les feuilles, on obtient un squelette o` figurent les seuls nœuds,
comme dans la figure 1.4.
                                                                                       
                       n1
                                                                                        
                 d                                             d                            ¡
                                                                                            ¡ e
                   d                                           d 
           
                    d                                    
                                                                  d                      e
                                                                                          ¡     
                                                                                                e
           n2                     n3
                                                                                 
         ¡
         ¡ e                    ¡
                                ¡ e                       ¡ e
                                                          ¡                 ¡
                                                                            ¡ e             e
       ¡     e
             e                ¡    e
                                    e                   ¡     e
                                                              e           ¡     e
                                                                                
                                                                                e             e
                                                                                              
                                                                                              e
     f21         f22        f31         n4
                                                                                                
                                         ¡
                                         ¡ e                                     ¡
                                                                                 ¡ e
                                       ¡     e
                                             e                                 ¡     e
                                                                                     e
                                  f41         f42



                                             Fig. 1.4: Construction du squelette


                                                                                   e                   e
Si bien entendu le passage du premier au second stade est destructif (on a effac´ l’information port´e), en
                                                 e
revanche le passage du second au dernier est r´versible, comme diraient les thermodynamiciens : il suffit
                               a                                    a
en effet d’ajouter des feuilles ` tous les endroits possibles, c’est-`-dire sous tous les nœuds qui ont 0 ou 1
fils.


1.3.2       e
           D´finition du squelette
  e                                                                     e         c    e
D´finition 1.4 (Squelettes binaires) Un squelette (d’arbre) binaire est d´fini de fa¸on r´cursive comme suit.
                                      ´         e
Le mot vide est un squelette binaire. Etant donn´s deux squelettes g et d, (g, d) est un nouveau squelette,
de fils gauche g, de fils droit d.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES                                                           19

              e
Avec cette d´finition — assez formelle —, tout squelette est un mot sur l’alphabet des trois caract`res (,  e
                                                           e e                                       u
) et la virgule ,. Par exemple, le squelette de la figure pr´c´dente est ((, ), (, (, ))). Mais bien sˆr tout mot
        e
ne repr´sente pas un squelette, comme par exemple le mot ((, , )).
       ee        e         e                           e           e e
On pr´f`rera n´anmoins ´videmment utiliser la repr´sentation g´om´trique des squelettes d’arbres.

1.3.3                                     e
          Le squelette comme une classe d’´quivalence
                                                            a                    e                 e
Le passage d’un arbre binaire sur des ensembles N et F ` son squelette se d´finit sans probl`me ` l’aidea
                                                              e     e                 e
d’une induction structurelle (voir l’exercice 1.3 page 24). L’´galit´ des squelettes d´finit sur l’ensemble des
                               e                    e                                    e e
arbres binaires une relation d’´quivalence, qui d´finit ce qu’on appelle souvent la g´om´trie d’un arbre
binaire.

1.3.4     ´
          Ecriture en Caml
                                                       e                             c
Il suffit pour travailler sur les squelettes en Caml de d´finir un nouveau type de la fa¸on suivante :
      type squelette = Vide | Jointure of squelette * squelette ;;



1.4      Combinatoire des arbres et squelettes binaires
1.4.1     Nœuds et feuilles
           c            e
Nous commen¸ons par un r´sultat assez simple :

   e e
Th´or`me 1.2
Soit a un arbre binaire, et s son squelette. Soit respectivement n, p, n le nombre de nœuds de a, le nombre
de feuilles de a, et le nombre de nœuds de s. Alors n = n = p − 1.

  4 L’´galit´ n = n est ´vidente.
         e     e            e
         e                    e                         a                                 e
  Consid´rons l’arbre interm´diaire entre a et s, c’est-`-dire oublions l’information port´e par les nœuds
                         e        e
  et les feuilles. Par d´finition mˆme d’un arbre binaire, tout nœud de a a exactement 2 fils qui sont
  soit une feuille soit un nouveau nœud. Inversement, toute feuille et tout nœud sauf la racine admet un
           e                                                                a
  nœud-p`re. Ainsi 2n est le nombre de nœuds et feuilles qui ne sont pas ` la racine de l’arbre, ou encore
  2n = n + p − 1, ce qui fournit l’´galit´ demand´e. 3
                                   e     e        e
                    e             e e    a
On aurait pu aussi d´montrer ce th´or`me ` l’aide d’une induction structurelle :
  4 Si a est une feuille, le r´sultat est clair car n = 0 et p = 1.
                               e
                              e
  Sinon, a = (x, g, d). Par r´currence, on sait que les nombres ng et pg (resp. nd et pd ) de nœuds et
  feuilles de g (resp. de d) v´rifient ng = pg − 1 et nd = pd − 1. Or a a pour feuilles les feuilles de g et
                              e
                                                                          a
  celles de d, donc p = pg + pd et pour nœuds les nœuds de g et ceux de d ` quoi il faut ajouter le nœud
  x lui-mˆme, donc n = 1 + ng + nd . L` encore on a bien n = 1 + pg − 1 + pd − 1 = pg + pd − 1 = p − 1.
           e                            a
  3
                      ee            e    e
Personnellement, je pr´f`re la premi`re d´monstration.

1.4.2     Profondeur et taille
Taille d’un arbre ou d’un squelette binaire
                                                         e
La notion de taille d’un arbre varie selon les auteurs, h´las : d’aucuns comptent les nœuds et les feuilles,
                                                                             a         e e
d’autres seulement les nœuds, d’autres encore seulement les feuilles. Mais grˆce au th´or`me 1.2 on passe
   e               a
ais´ment de l’une ` l’autre.
                        e
Nous choisirons ici la d´finition suivante.

D´finition 1.5 (Taille d’un arbre) On appelle taille d’un arbre binaire a et on note |a| la taille de son
  e
                 a
squelette, c’est-`-dire le nombre de ses nœuds.
20                                                                   CHAPITRE 1. ARBRES BINAIRES

              e                                                                                         `
On calcule ais´ment le nombre de nœuds et/ou de feuilles d’un arbre binaire et la taille d’un squelette a
                       e         e
l’aide de programmes r´cursifs tr`s simples.

Programme 1.3 Nombre de nœuds, de feuilles d’un arbre, taille d’un squelette
           (* calculs sur les arbres binaires *)
           let rec nb_nœuds = function
               | Feuille(_) -> 0
               | Nœud(_,g,d) -> 1 + (nb_nœuds g) + (nb_nœuds d) ;;

           let rec nb_feuilles = function
               | Feuille(_) -> 1
               | Nœud(_,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 d’un arbre
On se rappelle que la profondeur d’un arbre est la profondeur maximale de ses nœuds et feuilles. Il est
donc clair qu’on dispose du

Lemme 1.1 Si k est la profondeur d’un arbre binaire, son squelette est de profondeur k − 1.
                                               e      e                                           `
On se doute bien qu’un arbre binaire peut ˆtre tr`s profond, il suffit de descendre toujours a gauche `      a
                                                 e                                         e
partir de la racine, par exemple. Il est plus int´ressant de prouver que pour une taille fix´e, sa profondeur
          e                                              e
est minor´e. La figure 1.5 montre deux squelettes de mˆme taille et de profondeurs minimale et maximale.
                e          e e 
C’est ce que pr´cise le th´or`me suivant :                      
                                                        
                               e                           d
                                                             d 
                                e
                                 e                   
                                                              d
                                                        
                                 ¡
                                 ¡                 ¡
                                                   ¡ e      ¡
                                                            ¡
                              
                               ¡                e
                                                 ¡     
                                                       e  ¡
                                              
                               e
                                 e
                                 
                                 e
                                   
                                    e
                                      e
                                      
                                      e
                                      
                                     ¡¡
                                   
                                    ¡
                                   

                                      Fig. 1.5: Taille et profondeur


   e e
Th´or`me 1.3
Soit s un squelette binaire non vide, de taille n et de profondeur k. Alors lg n ≤ k ≤ n − 1.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES                                                          21

qui a pour corollaire le

   e e
Th´or`me 1.4
                             e     a
Soit a un arbre binaire non r´duit ` une feuille, de taille n (il a donc n nœuds) et de profondeur k. Alors
1 + lg n ≤ k ≤ n.

                                   e                                   a
Rappelons qu’en informatique lg d´signe le logarithme en base 2, c’est-`-dire que lg n = ln n/ ln 2, et que
    e                    e
 x d´signe la partie enti`re de x.
  4 Nous d´montrons le th´or`me 1.3 page pr´c´dente par induction structurelle.
               e               e e                e e
  Soit donc s = (g, d) un squelette. Notons n sa taille, k sa profondeur, et ng et kg (resp. nd et kd ) la
  taille et la profondeur de g (resp. de d).
  Si g et d sont vides, n = 1 et k = 0 : l’encadrement est correct.
                                                                                   e       e
  Si g est vide, mais pas d, n = 1 + nd et k = 1 + kd . Or on sait par hypoth`se de r´currence que
  lg nd ≤ kd ≤ nd − 1. On en d´duit que k ≤ nd = n − 1. La majoration est bien prouv´e. En outre,
                                    e                                                       e
  puisque nd ≥ 1, on a 1 + lg nd = 1 + lg nd = lg(2nd ) ≥ lg(nd + 1) = lg n , ce qui fournit la
  minoration souhait´e.e
                                              c
  Si d est vide, mais pas g, on raisonne de fa¸on analogue.
                                                                                   e
  Si enfin ni d ni g n’est vide, on a n = 1 + nd + ng et k = 1 + max(kd , kg ). La r´currence permet alors
  d’´crire les majorations : k ≤ 1 + max(nd , ng ) ≤ 1 + max(n − 1, n − 1) = n. Pour ce qui est de la
    e
  minoration, on ´crit d’abord que kd ≥ lg nd et kg ≥ lg ng .
                     e
  Mais l’´galit´ entre entiers naturels n = 1+nd +ng montre que nd ou ng est plus grand que (n−1)/2 .
          e      e
  Alors d’apr`s l’hypoth`se de r´currence, max(kd , kg ) ≥ lg n−1 . Ainsi a-t-on k ≥ 1 + lg n−1 .
               e           e      e                             2                               2
  Dans le cas o` n est pair, n = 2p + 2, on a ´crit k ≥ 1 + lg(p + 1) = lg(2(p + 1)) = lg n .
                   u                            e
  Dans le cas o` n est impair, n = 2p + 1, on a ´crit k ≥ 1 + lg p = lg(2p) = lg(2p + 1) = lg n .
                   u                               e
  Cette derni`re ´galit´ fait l’objet du lemme suivant. 3
               e e       e


Lemme 1.2 Pour tout entier naturel p ≥ 1, on a lg(2p + 1) = lg(2p) .

  4 On a bien sˆr l’in´galit´ lg(2p + 1) ≥ lg(2p) .
                u     e     e
  Posons k = lg p . On a 2k ≤ p ≤ 2k+1 − 1, d’o` 2p + 1 ≤ 2k+2 − 1 < 2k+2 . Ainsi lg(2p + 1) < k + 2,
                                               u
  et lg(2p + 1) ≤ k + 1 = lg(2p) , ce qui conclut. 3


Arbres complets
On appelle arbre complet un arbre de profondeur k et de taille n = 2k − 1. On trouvera dans la figure 1.6
                                                   o
page suivante les premiers arbres complets, ou plutˆt leurs squelettes.
                    e
Donnons une caract´risation des arbres complets.

  e e
Th´or`me 1.5
                                                                         a     e
Un arbre binaire est complet si et seulement si toutes ses feuilles sont ` la mˆme profondeur.

  4 Soit en effet a un arbre complet, de taille n = 2k − 1 et de profondeur k. On sait qu’il y a au
                      a                                                                   a
  moins une feuille ` la profondeur k. Supposons un moment qu’une autre feuille soit ` une profondeur
                                                                            u
  strictement plus petite que k. On pourrait la remplacer par un nœud d’o` pendraient deux feuilles, de
                        e     a                e
  profondeur au plus ´gale ` k. L’arbre ainsi ´tendu serait de taille n + 1 (on ajoute un seul nœud, on
                                                                                               e e
  retranche une feuille et en ajoute deux nouvelles), et toujours de profondeur k. Mais le th´or`me 1.4
  affirme k ≥ 1 + lg(n + 1) = 1 + k, ce qui fournit la contradiction souhait´e.
                                                                           e
                             e
  Montrons maintenant la r´ciproque : il suffit pour cela de compter le nombre de nœuds d’un arbre dont
                           a                                        e
  toutes les feuilles sont ` profondeur k. Ceci ne pose pas de probl`me particulier, il suffit de remarquer
  que chaque nœud interne a deux fils, et on trouve effectivement 2k − 1 nœuds. 3
Remarquons qu’un arbre complet de taille n = 2k − 1 poss`de n + 1 = 2k feuilles (de profondeur k).
                                                        e
22                                                                      CHAPITRE 1. ARBRES BINAIRES
                                                                       

                                                                   
                                              ¡ e
                                              ¡                         d
                                                                          d 
                                           e
                                            ¡     
                                                  e                
                                                                           d
                                                                    
                                                                 ¡
                                                                 ¡ e      ¡
                                                                          ¡ e
                                                              e
                                                               ¡     e
                                                                     e  ¡     
                                                                              e

                                                      

                                                  ¨ rr
                                                 ¨ 
                                               ¨¨      rr
                              ¨                                rr 
                               ¨¨                                  r
                                                                   
                               d                                      d
                                 d                                   d 
                         
                                  d                             
                                                                        d
                                           
                       ¡
                       ¡ e      ¡
                               ¡ e      ¡
                                        ¡ e      ¡
                                                 ¡ e
                    e
                     ¡     e
                           e  ¡    e
                                   e  ¡     e
                                            e  ¡     
                                                     e
                    

                                     Fig. 1.6: Squelettes d’arbres complets


       e       e
Arbres ´quilibr´s

                  e       e                        e
Un arbre sera dit ´quilibr´ quand ses feuilles se r´partissent sur au plus deux niveaux seulement.
                                      ee                                     e                           e
On verra plus loin dans ce cours l’int´rˆt que peut avoir pour un arbre cet ´quilibrage : ce sera le crit`re
                   e                                a
essentiel d’efficacit´ des algorithmes de recherche ` l’aide de structures d’arbres.

   e e                  e                     e
Th´or`me 1.6 (Caract´risation des arbres ´quilibr´s)  e
                                                      e       e                                    e
Un arbre binaire a de taille n et de profondeur k est ´quilibr´ si l’une ou l’autre des conditions ´quivalentes
               e e
suivantes est v´rifi´e :
(1) toute feuille de a est de profondeur k ou k − 1 ;
                   a
(2) l’arbre obtenu ` partir de a en supprimant toutes ses feuilles de profondeur k est complet.
         e       e e
Un arbre ´quilibr´ v´rifie la condition k = 1 + lg n .

                                                                                  a
Bien entendu, quand on dit qu’on supprime des feuilles d’un arbre, on entend par l` que l’on remplace
             e
leurs nœuds-p`res par des feuilles.

     4 L’´quivalence entre (1) et (2) est ` peu pr`s ´vidente.
           e                                a       e e
                                                        e     e
     Montrons simplement qu’on a bien, pour un arbre ´quilibr´ a, la relation k = 1 + lg n .
     Soit pour cela a l’arbre complet obtenu par suppression dans a des feuilles de profondeur k. La taille de
     a est n , il poss`de n + 1 feuilles, et donc 1 ≤ n − n ≤ n + 1. La profondeur de a est k − 1, donc
                      e
     n = 2k−1 − 1. Alors 1 ≤ n − (2k−1 − 1) ≤ 2k−1 , et 2k−1 ≤ n ≤ 2k − 1. On a bien lg n = k − 1. 3



1.4.3        e
            D´nombrement des squelettes binaires
                  e                                    e
Il va de soi que d´nombrer les arbres binaires eux-mˆmes n’a pas de sens, puisqu’aussi bien les ensembles
                                                      e
des valeurs qui habillent nœuds et feuilles peuvent ˆtre infinis.
                            e
Il est donc naturel de s’int´resser ici aux squelettes d’arbres binaires.
1.4. COMBINATOIRE DES ARBRES ET SQUELETTES BINAIRES                                                         23

     e
Une r´currence naturelle
                                                                                                 e
Pour compter les squelettes de taille n, on s’appuie sur le fait qu’un tel squelette est constitu´ d’une racine
et de deux sous-arbres dont la somme des tailles vaut n − 1, ce qui conduit ` une formule du genre :
                                                                                 a

                                             Sn =       Si Sn−1−i ,

o` Sk d´signe le nombre de squelettes de taille k. Une convention s’impose donc : S0 = 1. On en d´duit
 u     e                                                                                         e
    e               e e
imm´diatement le th´or`me qui suit.

   e e
Th´or`me 1.7
                                                                  e         e
Le cardinal Sn de l’ensemble des squelettes binaires de taille n v´rifie la r´currence
                                                        n−1
(1.1)                                    ∀n ≥ 1, Sn =         Si Sn−1−i ,
                                                        i=0

sous r´serve de la convention S0 = 1.
      e
Le tableau suivant fournit les premiers termes de cette suite.

                         n   0 1 2 3 4           5   6   7   8    9    10
                        Sn   1 1 2 5 14          42 132 429 1430 4862 16796

Une formule plus close
                               e                                             e e
Les informaticiens utilisent fr´quemment ce qu’ils appellent des fonctions g´n´ratrices. Pour l’exemple
            e                                                    e
qui nous int´resse, il s’agit de poser, pour tout (complexe) z (v´rifiant certaines conditions dont nous
nous occuperons plus tard)
                                                       +∞
                                              S(z) =         Sk z k ,
                                                       k=0

      e            u                          e
en esp´rant bien sˆr qu’il n’y a pas de probl`me de convergence.
    e                               e                             e      e
La r´currence qui fait l’objet de l’´quation 1.1 se traduit, d’apr`s la d´finition du produit de Cauchy de
      e         e          a a
deux s´ries enti`res, et grˆce ` la condition S0 = 1, par l’´quation
                                                            e

(1.2)                                        S(z) = 1 + zS 2 (z).

(Le d´calage n → n − 1 de la somme de 1.1 est traduit par le facteur z devant S 2 (z).)
     e
        e                         a e                        e
On s’int´resse donc naturellement ` l’´quation du second degr´

(1.3)                                           X = 1 + zX 2
                               √
                             1−  1 − 4z
qui a pour solution X =                  (on choisit cette solution pour que faisant tendre z vers 0 on
                                2z
                    e     a
obtienne une limite ´gale ` S0 = 1).
                                                                                            e
Si on demande, pour se rassurrer (il est vrai que pour l’instant on s’est vraiment peu souci´ de rigueur
     e          a                        e                  ea
math´matique), ` Maple de calculer le d´veloppement limit´ ` l’ordre 8 de X, on obtient :

(1.4)         X = 1 + z + 2 z 2 + 5 z 3 + 14 z 4 + 42 z 5 + 132 z 6 + 429 z 7 + 1430 z 8 + O z 9 .

          e                   `                                  e   a
Ces consid´rations conduisent a prendre en quelque sorte le probl`me ` l’envers.
Posons
                                          1,         si z = 0 ;
                                 f (z) = 1−√1−4z
                                             2z   , si 0 = |z| < 1/4.
On montre alors facilement que f est de classe C ∞ sur ]−1/4, 1/4[, et qu’elle v´rifie ` la fois l’´quation 1.3
                                                                                e     a           e
et la condition f (0) = 1.
24                                                                   CHAPITRE 1. ARBRES BINAIRES

                                            e                 ea            `
Or il se trouve que l’on sait calculer son d´veloppement limit´ ` l’origine a tout ordre. Les coefficients de
    e                    e e                  e             e
ce d´veloppement limit´ v´rifieront alors n´cessairement l’´quation 1.1. Ce seront bien les termes de la
suite (Sn ) !
                       c                                                                       e    e
On trouve de cette fa¸on, au prix d’un calcul que tout hypo-taupin sait mener sans difficult´, le r´sultat
      e
qui s’´nonce sous la forme du

   e e          e
Th´or`me 1.8 (D´nombrement des squelettes binaires)
Le nombre Sn de squelettes binaires de taille n, qui est aussi le nombre d’arbres binaires portant n nœuds
(internes) vaut
                                                    1     2n
                                            Sn =               .
                                                  n+1 n


1.5     Exercices pour le chapitre 1
Exercice 1.1 Indexation d’un arbre binaire
´
Ecrire une fonction Caml
      indexation : (’f,’n) arbre_binaire -> (string,string) arbre_binaire

qui remplace toute l’information des nœuds et feuilles de l’arbre fourni en argument par le mot binaire
              `               e      a
correspondant a l’indexation d´crite ` la section 1.1.3 page 16.


                                           e
Exercice 1.2 Sous-arbres de profondeur donn´e
´
Ecrire une fonction Caml
            a
      liste_`_profondeur : (’f,’n) arbre_binaire -> int -> (’f,’n) arbre_binaire list

                                                                                  e
qui prend en arguments un arbre binaire a et un entier n et qui renvoie la liste (´ventuellement vide) de
                                             a
tous les sous-arbres de a dont la racine est ` la profondeur n dans a.


Exercice 1.3 Calcul du squelette
´
Ecrire une fonction Caml
       e
      d´shabille : (’f,’n) arbre_binaire -> squelette

qui prend en argument un arbre binaire et qui renvoie son squelette.


              e e
Exercice 1.4 G´n´ration des squelettes d’arbres binaires
´
Ecrire une fonction Caml
               a
      engendre_`_profondeur : int -> int -> squelette list

qui prend en arguments deux entiers n et p et qui renvoie la liste des squelettes de taille n et de profondeur
                u
p. Dans le cas o` n = 0, la valeur de p ne sera pas prise en compte.
     e
En d´duire une fonction
      engendre : int -> squelette list

qui renvoie la liste de tous les squelettes dont la taille est fournie en argument.


                                                     e
Exercice 1.5 Squelette d’arbre complet de taille donn´e
´
Ecrire une fonction Caml
      squelette_complet : int -> squelette

                                                                                                e
qui prend en argument une taille n et renvoie le squelette complet de taille n s’il existe, et d´clenche une
erreur sinon.
1.5. EXERCICES POUR LE CHAPITRE 1                                                   25

                          e
Exercice 1.6 Test de compl´tude
´
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.

                    e
Exercice 1.7 Test d’´quilibrage
´
Ecrire une fonction Caml
         e       e
     est_´quilibr´ : (’f,’n) arbre_binaire -> bool
                                                                       e       e
qui prend en argument un arbre binaire et qui dit si oui ou non il est ´quilibr´.
Chapitre 2

Parcours d’un arbre

                                               e        e           e                   ee
Ce court chapitre a pour but d’expliciter diff´rentes m´thodes utilis´es pour lister les ´l´ments d’un arbre
      c               u                                                      a
de fa¸on non ambig¨e, de telle sorte qu’on puisse reconstituer sa structure ` l’aide de cette seule liste.
                                                                                                    e
On verra que la distinction faite dans les arbres binaires entre feuilles et nœuds permet de r´soudre
                     e
facilement ce probl`me, quand au contraire il faut davantage d’effort pour donner une description non
        u
ambig¨e d’un squelette d’arbre binaire.
                                                      e e                               e
Dans ce qui suit, on utilisera comme exemple privil´gi´ celui de l’arbre qui est dessin´ dans la figure 2.1,
                                                           e
et dont les feuilles sont des entiers, les nœuds des caract`res.
                                                  
                                                   a
                                             
                                              d
                                                d 
                                        
                                                 d
                                          b                       c
                                                               
                                          ¡
                                          ¡ e                     ¡
                                                                  ¡ e
                                        ¡     e
                                              e                 ¡     e
                                                                      
                                                                      e
                                    1         2             3         d
                                                                   
                                                                   ¡
                                                                   ¡ e
                                                                e
                                                                 ¡     e
                                                                  e       6
                                                                 
                                                                  ¡
                                                                  ¡ e
                                                                ¡     e
                                                                      e
                                                            4         5



                                    Fig. 2.1: Un arbre pour l’exemple




2.1     Parcours en largeur d’abord
2.1.1    Description de l’ordre militaire
                                              e          ıt                              e
Le premier type de parcours que nous allons ´crire paraˆ sans doute le plus naturel, mˆme si ce n’est pas
               a
le plus simple ` programmer.
                                                                             `
Certains l’appellent le parcours militaire d’un arbre, puisqu’il fait penser a l’axiome militaire bien connu
                    e                                       e e
qui donne la priorit´ au plus ancien dans le grade le plus ´lev´. Il suffit d’imaginer qu’en descendant dans
                              e
l’arbre on descend dans la hi´rarchie, et qu’on dispose les fils du plus ancien au plus jeune, pour faire le
rapprochement.

                                                       27
28                                                            CHAPITRE 2. PARCOURS D’UN ARBRE

          e            e
On peut ´galement d´crire cet ordre de parcours en disant qu’on liste les nœuds et feuille par ordre
                                         `                                  e
croissant de profondeur, et de gauche a droite pour une profondeur donn´e. C’est pourquoi d’autres
l’appellent le parcours en largeur d’abord.
                                                    e e                     e
Dans le cas de notre exemple de la figure 2.1 page pr´c´dente, ce parcours s’´crit donc :

                                            a b c 1 2 3 d e 6 4 5.

    e                                              ee      e                               `
La r`gle de reconstitution est simple : le premier ´l´ment ´crit est la racine de l’arbre. A chaque fois qu’on
                                           e                                                   `
dessine un nœud on dessine les deux arˆtes pendantes qui en proviennent, et au fur et a mesure de la
                                             e            a
lecture, on remplit les trous ainsi constitu´s, de gauche ` droite. . .
       a
Reste ` programmer ce parcours en Caml.


2.1.2    Programmation Caml
                           ` e                            `
Nous aurons tout d’abord a d´finir le type qui correspond a la description de notre arbre. Il s’agira d’une
        ee                                                                    e
liste d’´l´ments qui seront ou bien des feuilles ou bien des nœuds, ce qui s’´crit par exemple ainsi en
Caml :
      type (’f,’n) listing_d’arbre = F of ’f | N of ’n ;;

                                                                               e
Le programme 2.1 permet alors de parcourir dans l’ordre militaire un arbre donn´ en argument.

Programme 2.1 Parcours d’un arbre binaire en ordre militaire
           let parcours_militaire a =
               let rec parcours_rec nœuds_pendants = match nœuds_pendants with
                   | [] -> []
                   | Feuille(f) :: reste
                       -> (F f) :: (parcours_rec reste)
                   | Nœud(n,g,d) :: reste
                       -> (N n) :: (parcours_rec (reste @ [ g ; d ]))
               in
               parcours_rec [a] ;;



                               `                                   e
On peut appliquer ce programme a notre arbre exemple, et voici le r´sultat :
      #parcours_militaire exemple ;;
      - : (int, char) listing_d’arbre list =
       [N ‘a‘; N ‘b‘; N ‘c‘; F 1; F 2; F 3; N ‘d‘; N ‘e‘; F 6; F 4; F 5]

                                          `                                      e
En revanche, la reconstruction de l’arbre a partir d’une telle liste est un probl`me beaucoup plus ardu. . .


2.2     Parcours en profondeur d’abord
                                           e
Nous envisageons maintenant d’autres m´thodes de parcours qui sont plus proches de la structure na-
             e                                                                                   ee
turellement r´cursive des arbres, ce qui facilitera la programmation, et qui justifie qu’on les pr´f`rera au
parcours militaire.
    e                                            e
L’id´e des trois parcours qui suivent est la mˆme, et nous fera descendre tout en bas de l’arbre sur sa
                     e                          `
gauche avant de s’int´resser aux feuilles plus a droite : c’est ce qu’on appelle un parcours en profondeur
d’abord.


2.2.1               e
         Parcours pr´fixe, infixe, suffixe
                                                e                                  e
Ces trois parcours s’appuient sur la structure r´cursive des arbres : on applique r´cursivement le parcours
                                                         u                     e             e
aux sous-arbres gauche et droit, et c’est le moment o` on liste le nœud-p`re qui caract´rise ces trois
    e
diff´rents parcours.
                    e
Dans le parcours pr´fixe d’un nœud (n, g, d), on commence par lister n, puis on parcourt le sous-arbre g
et enfin le sous-arbre d.
2.2. PARCOURS EN PROFONDEUR D’ABORD                                                                     29

                                                          e
On obtient ainsi, dans le cas de notre arbre exemple, la s´quence
                                          a b 1 2 c 3 d e 4 5 6.
Dans le parcours infixe d’un nœud (n, g, d), on commence par parcourir le sous-arbre gauche, puis on liste
n, et on termine par le sous-arbre d.
                                    e
On obtient pour notre exemple la s´quence
                                          1 b 2 a 3 c 4 e 5 d 6.
Dans le parcours suffixe (on dit aussi postfixe), enfin, on commence par parcourir les deux sous-arbres g
                                                                         e
et d et on termine en listant n, ce qui, pour notre exemple, fournit la s´quence
                                          1 2 b 3 4 5 e 5 d c a.

2.2.2    Programmation en Caml
                        e          a           `                    e                          e
Ces trois parcours se prˆtent tout ` fait bien a une programmation r´cursive, et on obtient imm´diatement
                                           e
le programme 2.2, qui met d’ailleurs en ´vidence la ressemblance de ces trois algorithmes de parcours.

                                                      e
Programme 2.2 Parcours d’un arbre binaire en ordres pr´fixe, infixe et suffixe
                              e
           let rec parcours_pr´fixe = function
               | Feuille(f) -> [F f]
                                                    e                      e
               | Nœud(n,g,d) -> [N n] @ (parcours_pr´fixe g) @ (parcours_pr´fixe d) ;;

           let rec parcours_infixe = function
               | Feuille(f) -> [F f]
               | Nœud(n,g,d) -> (parcours_infixe g) @ [N n] @ (parcours_infixe d) ;;

           let rec parcours_suffixe = function
               | Feuille(f) -> [F f]
               | Nœud(n,g,d) -> (parcours_suffixe g) @ (parcours_suffixe d) @ [N n] ;;




2.2.3         e
         Probl`me inverse
`        e                                                      e               e    a
A la diff´rence du parcours en largeur d’abord, il n’est pas tr`s difficile de proc´der ` la reconstitution
                   `                            e
de l’arbre initial a partir de sa description pr´fixe, comme le montre le programme 2.3.

                                                `                                     e
Programme 2.3 Reconstitution d’un arbre binaire a partir de sa description en ordre pr´fixe
                           e
           let recompose_pr´fixe 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
                                       Nœud(n,g,d),reste
                                                    e
                   | [] -> failwith "Description pr´fixe incorrecte"
               in
               match recompose l with
                   | a,[] -> a
                                                  e
                   | _ -> failwith "Description pr´fixe incorrecte" ;;


                 a
Contrairement ` ce que certains s’imaginent parfois, le parcours suffixe d’un arbre ne fournit pas la
                 e
description sym´trique du parcours infixe, et il ne suffit pas d’appliquer recompose pr´fixe au miroir
                                                                                             e
d’une liste pour obtenir recompose suffixe.
                                     `                           `
Mais une approche directe conduit a la solution, qui consiste a construire l’arbre final en faisant pousser
      `               `                                        a
petit a petit l’arbre a partir de ses feuilles les plus basses ` gauche. C’est ce que fait le programme 2.4
page suivante.
30                                                           CHAPITRE 2. PARCOURS D’UN ARBRE

                                                `
Programme 2.4 Reconstitution d’un arbre binaire a partir de sa description en ordre suffixe
           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 (Nœud(n,g,d) :: a) reste
                   | [ arbre ],[]
                       -> arbre
                   | _ -> failwith "Description suffixe incorrecte"
               in
               recompose [] l ;;



                       e                                          `
Il nous reste le probl`me de la reconstitution d’un arbre binaire a partir de sa description en ordre infixe.
    a                      c                   e                                                 e
Et l`, surprise ! on s’aper¸oit que des trois m´thodes de parcours d’arbre que nous venons de d´crire, c’est
                         u          a                   e
la seule qui soit ambig¨e ! C’est-`-dire qu’on peut tr`s bien trouver un autre arbre que celui qui a ´t´ ee
        e                                               e                    a
propos´ dans la figure 2.1 page 27 avec pourtant le mˆme parcours infixe, ` savoir 1 b 2 a 3 c 4 e 5 d 6.
                    e
Par exemple, on v´rifiera que l’arbre de la figure 2.2 a aussi ce parcours infixe.
                                                       
                                                       c
                                                   
                                                    d
                                                      d 
                                              
                                                       d
                                              a                  d
                                                            
                                           ¡
                                           ¡ e                ¡
                                                              ¡ e
                                        e
                                         ¡     e           e
                                                            ¡     e
                                          b        3         e        6
                                                          
                                          ¡
                                          ¡ e                ¡
                                                             ¡ e
                                        ¡     e
                                              e            ¡     e
                                                                 e
                                    1         2        4         5



                                              u e
                               Fig. 2.2: Ambig¨it´ de la description infixe




2.3     Exercices pour le chapitre 2
                            a
Exercice 2.1 Reconstitution ` partir de l’ordre militaire
´
Ecrire une fonction Caml
      recompose_militaire : (’f,’n) listing_d’arbre list -> (’f, ’n) arbre_binaire
                                 `
qui reconstitue un arbre binaire a partir de sa description en ordre militaire.

                           e
Exercice 2.2 Conversions pr´fixe/suffixe
´                               `                           e
Ecrire une fonction Caml qui a partir de la description pr´fixe d’un arbre produit la description suffixe
                                  u
(sans reconstruire l’arbre, bien sˆr). Que pensez-vous de la fonction inverse ?
Chapitre 3

Arbres de recherche

3.1      e
        D´finition d’un arbre binaire de recherche
3.1.1     e         e e
         D´finition g´n´rale
On consid`re un ensemble ordonn´ (F, ) de feuilles et une application φ : F → N strictement croissante.
            e                       e
C’est-`-dire que si f1 f2 alors φ(f1 ) < φ(f2 ).
       a
Un arbre de recherche pour F est un arbre binaire sur les ensembles de feuilles et de nœuds F et N qui
est ou bien une feuille ou bien un arbre (n, g, d) tel que pour toute feuille f du sous-arbre gauche g on a
φ(f ) ≤ n et pour toute feuille f du sous-arbre droit d on a n < φ(f ).
                                                                                      u
Il est clair qu’on peut choisir pour valeur de n tout entier de l’intervalle [M, m[, o` M est le maximum
                                                                                           e e
des φ(f ) sur les feuilles f de g et m le minimum des φ(f ) sur les feuilles f de d. En g´n´ral on choisit
                                                                                        e
n = M , mais nous verrons qu’il faut savoir s’affranchir de cette contrainte, et on v´rifiera que tous les
 e                                             ee
r´sultats suivants n’utilisent pas cette propri´t´.
                        e                        e                                          e
Si on se rappelle la d´finition des parcours pr´fixe, infixe et suffixe d’un arbre, on en d´duit imm´dia-  e
              e                                              e
tement par r´currence structurelle que les feuilles sont list´es dans l’ordre croissant dans chacun de ces
parcours.


3.1.2    Cas particulier
On utilise le plus g´n´ralement F = N avec l’identit´ pour φ, et tous nos exemples seront construits sur
                    e e                             e
        e
ce mod`le.
On trouvera dans la figure 3.1 page suivante un premier exemple d’arbre de recherche sur N, qui nous
reservira dans la suite.



3.2                    ee
        Recherche d’un ´l´ment
3.2.1                     e
         Position du probl`me
                                                                      a                   ee
Comme leur nom l’indique, les arbres binaires de recherche servent ` la recherche d’un ´l´ment d’une
                 e e                                                       e
famille : plus pr´cis´ment, on se donne un ensemble de valeurs et on veut ´crire une fonction d’apparte-
        a
nance ` cet ensemble.
                                a                            ee                            ee     a
Une solution simple consiste ` utiliser une liste simple des ´l´ments de l’ensemble consid´r´, et ` faire
                                         e
une recherche dans cette liste, ce qui s’´crit en Caml comme dans le programme 3.1 page suivante.
                    e         e                                                                u
Pas besoin d’une r´flexion tr`s approfondie pour prouver que cet algorithme tourne en O(n), o` n est la
taille de l’ensemble de valeurs-cibles.

                                                    31
32                                                       CHAPITRE 3. ARBRES DE RECHERCHE
                                                        
                                                         5
                                                     
                                                      d
                                                        d 
                                                
                                                         d
                                                3                   9
                                                              
                                             ¡
                                             ¡ e                ¡
                                                                ¡ e
                                          e
                                           ¡     e           e
                                                              ¡     e
                                            1       5         7         12
                                                            
                                            ¡
                                            ¡ e                ¡
                                                               ¡ e
                                          ¡     e
                                                e            ¡     e
                                                                   
                                                                   e
                                      1         3        7          8
                                                                   
                                                                    ¡
                                                                    ¡ e
                                                                  ¡     e
                                                                        e
                                                              8         9



                               Fig. 3.1: Un arbre binaire de recherche sur N

                         e
Programme 3.1 Recherche s´quentielle dans une liste
           let rec recherche l x =
               match l with
                   | [] -> failwith "´l´ment absent de la liste"
                                     E e
                   | t :: q -> t = x || recherche q x ;;




3.2.2     Recherche dans un arbre binaire de recherche
                                              a                  e               e     e
Les arbres binaires de recherche conduisent ` une solution tr`s simple du mˆme probl`me, si on sait
construire un arbre dont l’ensemble des feuilles est l’ensemble de nos valeurs-cibles.
C’est ce que propose l’algorithme 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 "´l´ment absent"
                                                      E e
                   | Nœud(n,g,d) -> if phi x > n
                                       then recherche phi d x
                                       else recherche phi g x ;;



Bien sˆr, ceci se simplifie dans le cas d’un arbre sur N et on obtient le programme plus simple 3.3 page
      u
suivante.


3.2.3     ´
          Evaluation
                           e                                     ee
Si on suit sur l’arbre donn´ dans la figure 3.1 la recherche de l’´l´ment 8, on se rend compte qu’on descend
                             a                                  `            `
dans l’arbre en choisissant ` chaque nœud de descendre soit a droite soit a gauche par une comparaison :
                                 a         a          a           a
ici, on descend successivement ` droite, ` gauche, ` droite et ` gauche.
                   e                                                                               e
Si on avait cherch´ la valeur 6 qui ne fait pas partie de l’ensemble des feuilles, on aurait utilis´ la descente
a          a         a                           e                               e          e
` droite, ` gauche, ` gauche, et on serait arriv´ sur la feuille 7 = 6, ce qui d´cide de l’´chec.
         e          e                     e                           e e
On en d´duit imm´diatement par une r´currence structurelle le th´or`me qui suit.

   e e              u
Th´or`me 3.1 (Coˆt d’une recherche dans un arbre binaire)
                                                    e                                           e    a
La recherche dans un arbre binaire de recherche se r´alise en un nombre de comparaisons au plus ´gal ` k + 1,
 u
o` k est la profondeur de l’arbre.
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 "´l´ment absent"
                                                      E e
                   | Nœud(n,g,d) -> if x > n then recherche d x
                                             else recherche g x ;;




                   e e                                        e
En utilisant les th´or`mes 1.2 page 19 et 1.4 page 21, on en d´duit le corollaire suivant.

   e e                                u
Th´or`me 3.2 (Encadrement du coˆt de la recherche dans un arbre binaire)
                    ee                                           e                                   e
La recherche d’un ´l´ment dans un ensemble de n valeurs organis´es en arbre binaire de recherche se r´alise
                                                           e
dans le cas le pire en un nombre c(n) de comparaisons qui v´rifie :

                                       2 + lg(n − 1) ≤ c(n) ≤ n.

Dans le cas particulier o` l’arbre de recherche utilis´ est ´quilibr´, on a l’´galit´ c(n) = 2 + lg(n − 1) ,
                         u                            e     e       e         e     e
                     u
ce qui garantit un coˆt logarithmique pour notre recherche.
                  e                                  e        e                             e
Toute la difficult´ est donc de construire un arbre ´quilibr´ de recherche, ce que nous ´tudions dans la
section suivante.


3.3     Structure dynamique de recherche
                                                                                                a
En pratique on veut maintenir une structure dynamique de l’ensemble des valeurs-cibles. C’est-`-dire
                                                       `
qu’on veut pouvoir ajouter ou retrancher une valeur a cet ensemble. Il s’agit donc pour nous d’ajouter
                          `
ou retrancher une feuille a un arbre binaire de recherche.


3.3.1               ee
         Ajout d’un ´l´ment
               ee            e                                                                     a
L’ajout d’un ´l´ment x se r´alise un peu comme la recherche : on descend dans l’arbre jusqu’` arriver
` une feuille. Ou bien c’est l’´l´ment qu’on veut ajouter, il y est d´j`, et il n’y a rien a faire. Ou bien
a                              ee                                       ea                 `
          ee           e
c’est un ´l´ment y diff´rent de x, ce qui signifie que x n’est pas encore dans l’arbre. On remplace alors la
feuille y par un arbre (φ(x), x, y) si φ(x) < φ(y) ou (φ(y), y, x) sinon.
                                        e
Tout ceci se programme sans difficult´ en Caml : c’est le programme 3.4.

                         ee
Programme 3.4 Ajout d’un ´l´ment 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 Nœud(phi x,Feuille(x),Feuille(y))
                      else Nœud(phi y,Feuille(y),Feuille(x))
               | Nœud(n,g,d)
                   -> if phi x > n then Nœud(n,g,ajout phi d x)
                      else Nœud(n,ajout phi g x,d) ;;



                         e                              e                  e                             u
La fonction ajout ainsi ´crite renvoie le nouvel arbre r´sultat. Il est imm´diat qu’elle tourne en O(k) o`
k est la profondeur de l’arbre.


3.3.2                     ee
         Suppression d’un ´l´ment
                      ee                                                      u                    ee
La suppression d’un ´l´ment dans un arbre binaire de recherche n’a bien sˆr de sens que si cet ´l´ment
figure parmi les feuilles, sans quoi il ne se passe rien.
                                 ee              ee
Il suffit a priori de rechercher l’´l´ment consid´r´, et de couper la feuille correspondante de l’arbre. Puis
                        e           e
on remplace le nœud-p`re par le fr`re gauche ou droit qui subsiste.
34                                                                 CHAPITRE 3. ARBRES DE RECHERCHE
                                                                  
                                                                      5
                                                       
                                                        d
                                                          d 
                                                  
                                                           d
                                                      3                               9
                                                                           
                                             ¡
                                             ¡ e                             ¡
                                                                             ¡ e
                                          e
                                           ¡     e                        e
                                                                           ¡     e
                                              1               5               8                12
                                                                         
                                            ¡
                                            ¡ e                             ¡
                                                                            ¡ e
                                          ¡     e
                                                e                         ¡     e
                                                                                e
                                      1               3               8               9



                                Fig. 3.2: Arbre obtenu par suppression du 7


                                                                     ee                         e
Reprenant notre arbre de la figure 3.1 page 32, si on supprime l’´l´ment 7, on remplace le p`re de la
                                                                           e             e           e
feuille 7 par son fils droit, et on obtient bien un arbre de recherche qui r´pond au probl`me qu’on s’´tait
    e
pos´, comme le montre la figure 3.2.
                                                ee                                e           e
Supprimons maintenant de ce nouvel arbre l’´l´ment 5. On remplace donc son p`re par son fr`re gauche,
et on obtient le nouvel arbre de la figure 3.3.
                                                    
                                                                  5
                                                   
                                                    d
                                                      d 
                                              
                                                       d
                                                  1                               9
                                                                       
                                                ¡
                                                ¡ e                      ¡
                                                                         ¡ e
                                              ¡     e
                                                    e                 e
                                                                       ¡     e
                                          1               3               8               12
                                                                       
                                                                        ¡
                                                                        ¡ e
                                                                      ¡     e
                                                                            e
                                                                  8               9



                          Fig. 3.3: Arbre obtenu par suppression du 7 puis du 5

                                                                            ee        e
L’arbre obtenu est bien un arbre de recherche, et la suppression a bien ´t´ effectu´e. En revanche on
      c                 ee       e          e          a e               e              e e
s’aper¸oit que la propri´t´ cosm´tique qui ´tait jusqu’` pr´sent conserv´e n’est plus v´rifi´e : les valeurs
                          e              e     a
des nœuds ne sont plus n´cessairement ´gales ` la feuille maximale du sous-arbre gauche. Ainsi, la racine
                                                                                           ea
de notre arbre vaut-elle toujours 5, qui ne figure pourtant plus dans l’arbre. Mais on l’a d´j` dit, ce n’est
             e
pas un probl`me.
                   e
On programme ais´ment cette suppression en Caml : c’est le programme 3.5 page suivante.
                        a                   u
Ce programme tourne l` encore en O(k), o` k est la profondeur de l’arbre.

3.3.3     Application au tri
                                           e e
Il suffit de combiner les programmes pr´c´dents pour obtenir un tri.
                                                      e                                            ee
On construit pour commencer un arbre constitu´ d’une seule feuille contenant le premier ´l´ment de la
      `                                                       ee
liste a trier, auquel on ajoute successivement les autres ´l´ments. Il suffit de lire les feuilles par un parcours
 e                                            e           u
r´cursif de l’arbre pour obtenir la liste tri´e. Le coˆ t de cet algorithme de tri s’obtient en sommant les
   u                                                                     e    e
coˆts des ajouts successifs. Si on peut s’assurer que l’arbre reste ´quilibr´ tout au long de l’algorithme,
                 u
on aura un coˆt de l’ordre de
                                      lg 1 + lg 2 + · · · + lg n = O(n lg n);
3.4. EXERCICES POUR LE CHAPITRE 3                                                                      35

                               ee
Programme 3.5 Suppression d’un ´l´ment 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)
               | Nœud(n,g,d)
                   -> if phi x > n then
                            if d = Feuille(x) then g
                            else Nœud(n,g,suppression phi d x)
                      else if g = Feuille(x) then d
                            else Nœud(n,suppression phi g x,d) ;;


                  a
Programme 3.6 Tri ` l’aide d’arbres binaires de recherche
           let tri_par_arbre_de_recherche liste =
               let rec liste_feuilles = function
                   | Feuille(f) -> [ f ]
                   | Nœud(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) ;;



                                                          u     e                                       u
sinon, il se pourrait que chaque ajout se fasse pour un coˆt lin´aire, et on retomberait alors sur un coˆt
global quadratique, c’est-`-dire en O(n2 ).
                           a

3.3.4            e        e
         Le probl`me de l’´quilibrage
               e                                                     e e
Tout le probl`me est donc bien d’assurer que l’arbre reste ´quilibr´, ce qui n’est pas garanti par nos
                                                                         e
algorithmes trop rudimentaires. Il suffit pour s’en convaincre de consid´rer l’arbre obtenu par ajout
              ee                                          e       e
successif des ´l´ments 1, 2, . . . , 8, qui est tout sauf ´quilibr´ !


3.4     Exercices pour le chapitre 3
Exercice 3.1 Une autre structure d’arbre de recherche
                                                         a                      `
Une autre solution pour les arbres de recherche consiste ` placer l’information a chercher aux nœuds. On
e
´crit donc le type
      type ’a arbre_de_recherche =
          | Vide
          | Nœud 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 nœuds.
´                                                                                               ee
Ecrire pour cette nouvelle structure les fonctions de recherche, d’ajout et de suppression d’un ´l´ment.

                        e
Exercice 3.2 Balance et ´quilibrage
                   e                                           e                       e e
On reprend la repr´sentation des arbres binaires de recherche d´finie dans l’exercice pr´c´dent.
´
Ecrire la fonction mesure ´quilibrage qui prend un arbre de type ’a arbre_de_recherche et qui
                           e
             e
renvoie en r´sultat un arbre de type (’a * int) arbre_de_recherche obtenu en ajoutant a chaque  `
nœud l’entier kg − kd o` kg est la profondeur de son fils gauche et kd la profondeur de son fils droit. On
                        u
utilisera par convention −1 comme profondeur de Vide.
Un arbre sera dit AVL si on a toujours kg − kd ∈ {−1, 0, +1}.
36                                                        CHAPITRE 3. ARBRES DE RECHERCHE

Exercice 3.3 Taille d’un arbre AVL
´          e              e     e
Ecrire et d´montrer les in´galit´s qui constituent l’encadrement de la profondeur k d’un arbre AVL en
fonction de sa taille n.
                                                                                           e       ee
On montre qu’on peut utiliser ces arbres comme arbres de recherches, ce qui assure des op´rations ´l´-
                                      ee                    u                  e
mentaires (ajout et suppression d’un ´l´ment) toutes de coˆt logarithmique, mˆme dans le pire des cas.
                    e                                                 ee                            ee
Il faut pour cela d´finir des fonctions d’ajout et de suppression d’un ´l´ment qui conserve la propri´t´
des arbres AVL.

Exercice 3.4 Arbres 2–3
                                             u                    e
Un arbre de recherche 2–3 est un arbre o` l’information recherch´e est aux feuilles, dont tout nœud a 2
                                           a     e
ou 3 fils, et dont toutes les feuilles sont ` la mˆme hauteur.
                                                          e
Proposer un type Caml pour ces arbres de recherche, et ´crire la fonction de recherche correspondante.
                                                                         e
Montrer que la profondeur k des feuilles et le nombre n de ces feuilles v´rifient un encadrement que l’on
  e
pr´cisera.
 a                                                                              ee
L` encore, on peut construire des algorithmes d’ajout et de suppression d’un ´l´ment sur un arbre 2–3,
                                             a u
ce qui en fait une structure de recherche ` coˆt toujours logarithmique.
Chapitre 4

Tri et tas

4.1      e e     e
        G´n´ralit´s
4.1.1                    e
         Files de priorit´
                    e
Une file de priorit´ est un arbre binaire dont les feuilles et les nœuds sont des entiers. C’est pourquoi,
dans la suite de ce chapitre, on ne parlera plus de nœuds et de feuilles mais de nœuds internes et de
                                                         e     c
nœuds externes. On dessinera tous ces nœuds de la mˆme fa¸on : avec un cercle. La taille de la file sera
le nombre total de ses nœuds, internes ou externes.
                        e      e           e               ee                 e
Mais une file de priorit´ doit ´galement v´rifier la propri´t´ suivante : tout p`re est plus grand que chacun
                      ee
de ses fils. Si l’on pr´f`re, on peut dire que le long de tout chemin qui descend dans l’arbre de la racine
` l’un de ses nœuds, on lit une suite d´croissante d’entiers.
a                                       e
                                                             e            e    ´
On notera qu’en revanche il n’y a pas de condition impos´e sur des fr`res. Evidemment la racine d’une
              e                            e
file de priorit´ est le plus grand entier pr´sent dans tout l’arbre.
La figure 4.1 montre un exemple de file de priorit´.  e
                                                         
                                                          12
                                                     
                                                      d
                                                       d 
                                                
                                                        d
                                                 9                  3
                                                     
                                              ¡
                                              ¡ e      ¡
                                                       ¡
                                           e
                                            ¡     
                                                  e  ¡
                                            5        7         1
                                        
                                        ¡
                                       ¡ e   e
                                     e
                                      ¡    e
                                           e   
                                               e
                                       4         3        6
                                     

                                                                   e
                                       Fig. 4.1: Une file de priorit´



4.1.2    Tas
                                               e          e       e
Un tas est un cas particulier de file de priorit´, qui est ´quilibr´, et dont les nœuds externes de profondeur
                              a
maximale sont tous le plus ` gauche possible. On parle souvent dans cette situation d’arbre parfait.
On trouvera dans la figure 4.2 page suivante un exemple de tas.
                  e         e e     e    e                        e e                e             e e
En utilisant les r´sultats g´n´raux ´tudi´s dans les chapitres pr´c´dents, on peut d´montrer le th´or`me 4.1
page suivante.

                                                     37
38                                                                                                  CHAPITRE 4. TRI ET TAS
                                                                 
                                                                  12
                                                          
                                                           d
                                                             d 
                                                     
                                                              d
                                                     9                              6
                                                       
                                                ¡
                                                ¡ e      ¡
                                                         ¡ e
                                             e
                                              ¡     e
                                                    e  ¡     
                                                             e
                                                 5           7              1               3
                                        
                                        ¡
                                       ¡ e
                                     e
                                      ¡    
                                           e
                                         4           3
                                     

                                                     Fig. 4.2: Un tas


   e e                 e e
Th´or`me 4.1 (Propri´t´s des tas)
Soit T un tas de taille n. Sa profondeur k v´rifie l’´galit´ k = lg n . Parmi ses nœuds externes, il y a
                                            e       e     e
exactement n + 1 − 2 nœuds ` profondeur ´gale ` k, les autres sont de profondeur k − 1.
                    k
                             a            e     a

     4 La profondeur d’un arbre ´quilibr´ est connue depuis le th´or`me 1.6 page 22.
                                     e      e                        e e
                            a
     Comme l’arbre obtenu ` partir de notre tas en supprimant les nœuds externes de profondeur k est complet
     et de profondeur k − 1, il poss`de 2k − 1 nœuds, qui sont les nœuds internes du tas et ses nœuds externes
                                    e
     de profondeur k − 1. C’est dire qu’il y a bien n − (2k − 1) nœuds externes de profondeur k. 3


4.1.3           e                  a
            Impl´mentation des tas ` l’aide de tableaux
                                                                 e                    e
On pourrait bien entendu utiliser une structure d’arbre pour repr´senter les tas, en d´finissant un type
             c
Caml de la fa¸on suivante :
        type tas = Vide | Nœud of int * tas * tas ;;
                                  e                                             a              e
Il se trouve qu’il existe une impl´mentation beaucoup plus simple et efficace, ` l’aide d’un bˆte tableau.
                      e                                     e
Si en effet on veut d´crire un tas, le plus simple est assur´ment de donner sa description dans un parcours
                                u e                   u              e                     e           e
militaire. Il n’y a pas d’ambig¨it´ dans la mesure o` seule la derni`re ligne du tas peut ˆtre incompl`te.
   e                   e                  e                                   c     e
Pr´cisons ceci, en d´finissant une num´rotation des nœuds d’un tas de fa¸on r´cursive : la racine est
     e e                      e                                                              e e
num´rot´e 0. Si i est le num´ro d’un nœud interne, ses nœuds fils gauche et droit sont num´rot´s respec-
tivement 2i + 1 et 2i + 2.
                                                        e e                 e
On trouvera dans la figure 4.3 le tas de l’exemple pr´c´dent avec les num´ros de chacun des nœuds ` sa a
gauche.
                                                         
                                                                 0 12
                                                          D
                                                            l
                                                          D
                                                        D     l
                                                     
                                                      D        l
                                                                l
                                                 1   9                              2   6
                                                   
                                               „      „
                                              „  „
                                                 „      
                                                        „
                                         3   5           4   7          5       1           6   3
                                         
                                       „
                                      „
                                         „
                                 7   4           8   3
                                      

                                                           e
                               Fig. 4.3: Un tas avec sa num´rotation des nœuds
4.2. PERCOLATION                                                                                              39

     e e                         e                             e                             `
Le th´or`me 4.2 montre que la num´rotation que nous venons de d´finir correspond effectivement a un
parcours militaire du tas.
    e e                e
Th´or`me 4.2 (Num´rotation des nœuds d’un tas)
Pour la num´rotation d´finie plus haut, on ´num`re les entiers de 0 ` n − 1 en num´rotant les nœuds dans
             e           e                     e    e              a             e
l’ordre du parcours militaire d’un tas de taille n.
  4 Nous proc`dons par r´currence sur la profondeur k du tas.
                 e           e
       e
  Le r´sultat est clair pour un tas de profondeur nulle.
  Supposons le acquis pour les tas de profondeur au plus ´gale ` k (k ≥ 0) et consid´rons un tas T de
                                                            e     a                      e
  profondeur k + 1.
  La d´finition d’un tas montre qu’en supprimant dans T tous les nœuds (externes) de profondeur k + 1,
       e
  on obtient un arbre complet, de taille 2k+1 − 1. On a dit qu’il poss´dait 2k nœuds externes, et d’apr`s
                                                                       e                                  e
  l’hypoth`se de r´currence, elles portent les num´ros 2k − 1 ` 2k+1 − 2.
           e       e                               e           a
  Posons λ : i → 2i + 1 et µ : i → 2i + 2.
                     u                                                                          e
  λ et µ sont bien sˆr injectives, et λ(N) et µ(N) sont clairement disjoints par raison de parit´.
                                                                                                   e
  Enfin, pour tout entier i, λ(i), µ(i), λ(i + 1) et µ(i + 1) sont, dans cet ordre, des entiers cons´cutifs.
  Il suffit pour conclure d’observer que λ(2k − 1) = 2k+1 − 1. La k + 1-i`me ligne du tas porte donc des
                                                                          e
  num´ros cons´cutifs qui d´butent effectivement ` l’entier qui suit 2k+1 − 2, dernier num´ro port´ par la
       e        e            e                     a                                        e        e
  ligne de profondeur k. 3
                 e
On va donc impl´menter un tas de taille n sous la forme d’un vecteur v d’entiers, et on usera des analogies
                                                                                        e
suivantes : v2i+1 est le fils gauche de vi , v2i+2 est son fils droit, v (i−1)/2 est son p`re.


4.2     Percolation
4.2.1    Description de l’algorithme
                            e                    ` e
On appelle percolation l’op´ration qui consiste a r´organiser un arbre sous forme d’un tas sachant que
                                  e        ea                                     a
les deux sous-arbres de la racine ´taient d´j` des tas : il s’agit donc de mettre ` sa place la racine.
                             e                                       e
Par exemple, on peut consid´rer l’arbre A de la figure 4.4, et, apr`s percolation, on obtient le tas T de la
figure 4.6 page suivante.
                                                      
                                                        6
                                                   
                                                    d
                                                      d 
                                              
                                                       d
                                               9                  5
                                                  
                                           ¡
                                           ¡ e      ¡
                                                    ¡ e
                                        e
                                         ¡     e
                                               e  ¡     
                                                        e
                                          8        7         2          1
                                     
                                     ¡
                                    ¡ e
                                  e
                                   ¡    
                                        e
                                    4          3
                                  

                                                           `
                                        Fig. 4.4: Un arbre a percoler

                                                                              e
L’algorithme de percolation est simple : on descend la valeur x inappropri´e de la racine (dans notre
exemple x = 6) en cherchant sa nouvelle place dans l’arbre. Si x est plus grand que ses deux fils, c’est
             e                                  e
qu’il a trouv´ sa place, et on a fini, sinon, on ´change x avec le plus grand de ses deux fils.
                                                e            e                         u           e
On trouvera dans la figure 4.5 page suivante l’´tape interm´diaire de la percolation, o` on a entour´ d’un
    e
carr´ la position courante de x.
´                                                               u
Evidemment l’arbre obtenu n’est un tas que dans la mesure o` les deux fils gauche et droit de la racine
                   e            e
de l’arbre initial ´taient eux-mˆmes des tas : on n’a fait que replacer au bon endroit la racine.
40                                                  CHAPITRE 4. TRI ET TAS




                              
                               9
                              
                              d
                             
                                d 
                                 d
                      6                 5
                           
                   ¡ e
                   ¡       ¡
                           ¡ e
                e
                 ¡     e
                       e ¡     
                               e
                 8        7        2         1
             
             ¡
            ¡ e
          e
           ¡    
                e
            4         3
          

                 e           e
     Fig. 4.5: L’´tape interm´diaire de la percolation




                              
                               9
                          
                           d
                             d 
                     
                              d
                      8                 5
                          
                   ¡
                   ¡ e      ¡
                            ¡ e
                e
                 ¡     e
                       e  ¡     
                                e
                 6        7        2         1
             
             ¡
            ¡ e
          e
           ¡    
                e
            4         3
          

         Fig. 4.6: Le tas obtenu par percolation
4.2. PERCOLATION                                                                                              41

4.2.2    Programmation
                e
Utilisons l’impl´mentation par vecteur d’un tas pour programmer cette percolation, ce qui fait l’objet des
                                                e            e
programmes 4.1 et 4.2, dans les deux versions r´cursive et it´rative.

                           e
Programme 4.1 Percolation r´cursive
                             e
           let percolation_r´cursive tas =
               let fils_gauche i = try tas.(2 * i + 1) with _ -> -1
               and fils_droit i = try tas.(2 * i + 2) with _ -> -1
                   e
               and ´change 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
                            e
                            ´change i (2 * i + 1) ;
                            percole_encore (2 * i + 1)
                        end
                   else
                   if x < fd && fd >= fg then
                        begin
                            ´change i (2 * i + 2) ;
                            e
                            percole_encore (2 * i + 2)
                        end
               in
               percole_encore 0 ;
               tas ;;




                            e
Programme 4.2 Percolation it´rative
                              e
           let percolation_it´rative 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 ;;



                        e                                          e
           On aura not´ comment dans les deux programmes on ´vite des comparaisons fastidieuses entre
                                e
           indices et n pour v´rifier qu’on n’est pas sur un nœud externe avant de calculer les fils en
                                             e      e             e               ee
           comptant sur l’erreur qui serait d´clench´e par un acc`s incorrect aux ´l´ments du vecteur et en
  renvoyant alors une valeur, −1, inf´rieure ` tous les autres ´l´ments et qui termine donc la percolation.
                                     e       a                 ee
                                  e                      o             e    a     e
  En outre, pour le programme it´ratif, on a choisi, plutˆt que de proc´der ` des ´changes dans le vecteur,
                                         a                                   e e      e
  de ne recopier la valeur de x que tout ` la fin, quand sa position finale a ´t´ trouv´e.
42                                                                            CHAPITRE 4. TRI ET TAS

4.2.3    ´
         Evaluation
            e                                                            u
Il est bien ´vident que notre algorithme de percolation tourne en O(k), o` k est la profondeur de notre
arbre, donc en O(lg n), puisqu’il s’agit d’un tas.


4.2.4                    e
         Application : cr´ation d’un tas
 e
R´organisation
´           e                                                             e             e
Etant donn´ un vecteur v quelconque de n entiers naturels, on souhaite ´crire une proc´dure r´organise
                                                                                                e
                 ee                                     e                    e
qui permute ses ´l´ments de telle sorte que le vecteur r´sultant soit la repr´sentation d’un tas.
       e                                         c
v repr´sente a priori un arbre. On va, en commen¸ant par les niveaux de plus grande profondeur, remonter
                        `                                                `
en s’assurant au fur et a mesure que les sous-arbres dont la racine est a profondeur i sont des tas. Pour
passer ` la profondeur i − 1, il suffira de percoler tous les nœuds de cette profondeur.
         a
                                      e                                                       e
Observons toutefois qu’il n’est pas n´cessaire de percoler les nœuds externes, qui ne posent ´videmment
              e
pas de probl`me.
                             e e
Or nous savons depuis le th´or`me 4.1 page 38 quels sont les nœuds internes et les nœuds externes, et il
suffit donc de percoler ` rebours tous les nœuds dont les indices varient de n/2 − 1 ` 0. C’est ce que
                        a                                                                 a
fait le programme 4.3.

               e
Programme 4.3 R´organisation d’un 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 ;;

                e
           let r´organise tas =
               let n = vect_length tas
               in
               for i = (n - n/2 - 1) downto 0 do percolation tas i n done ;
               tas ;;



                  ee
           On a r´´crit ici la fonction de percolation, en demandant que percolation tas i j ne percole
                                                                 e                                 e
           que le sous-arbre de tas dont la racine porte le num´ro i et dont les nœuds sont de num´ros
           strictement plus petit que j.



´
Evaluation

                 e                             e           u                            e
L’algorithme de r´organisation que nous avons ´crit a un coˆt qu’il n’est pas difficile d’´valuer, puisqu’on
                        `                                            e
applique la percolation a n/2 reprises pour des profondeurs qui ne d´passent pas lg n. Il tourne donc en
O(n lg n).
4.3. LE TRI PAR LES TAS                                                                                  43

4.3     Le tri par les tas
4.3.1    Programmation
                              c                                                          e       e
Nous avons ici une nouvelle fa¸on de trier un vecteur v de n entiers naturels. Une fois r´organis´ en tas,
                                                                   e                        ee
le maximum du tableau est simplement la racine v0 de l’arbre. On l’´change avec le dernier ´l´ment vn−1 ,
et il n’y a plus qu’` recommencer avec le sous-tableau v[0..n − 2]. En outre, il n’est pas n´cessaire de
                    a                                                                         e
 e                e                                        e    a
r´organiser compl`tement ce sous-tableau : il suffit de proc´der ` une percolation.
                       a
C’est ce qui conduit ` l’algorithme dit tri par tas ou, en anglais, heap sort, qui fait l’objet du pro-
gramme 4.4.

Programme 4.4 Le tri par tas (heap sort)
           let tri_par_tas tas =
               let n = vect_length tas
                   e
               and ´change p q =
                   let a = tas.(p)
                   in
                   ( tas.(p) <- tas.(q) ; tas.(q) <- a )
               in
                e
               r´organise tas ;
               for i = n - 1 downto 1 do
                   e
                   ´change 0 i ;
                   percolation tas 0 i
               done ;
               tas ;;




4.3.2    ´
         Evaluation
                                   e            u
Nous avons tout ce qu’il faut pour ´valuer le coˆ t de ce nouvel algorithme de tri. Nous avons dit que la
r´organisation en tas avait un coˆt en O(n lg n) ; il reste ensuite n − 1 percolations ` r´aliser, toutes de
 e                               u                                                     a e
   u       e                             e
coˆt major´ par lg n. L’algorithme propos´ est donc bien un nouvel algorithme de tri en O(n lg n), ce que
             e
nous savons ˆtre optimal.
Chapitre 5

Arbres n-aires et expressions
      e
arithm´tiques

5.1       Arbres n-aires
5.1.1       e
           D´finition
                             e e                                                                  a     e
Les arbres n-aires sont une g´n´ralisation des arbres binaires : on autorise cette fois les nœuds ` poss´der
                                          e                                          c
un nombre quelconque de fils. On peut d´finir rigoureusement ces arbres de la fa¸on suivante.


   e
D´finition 5.1 (Arbres n-aires) Soit F et N des ensembles de valeurs de feuilles et de nœuds. On d´finit                  e
r´cursivement un arbre n-aire sur ces ensembles en disant que toute feuille f ∈ F est un arbre n-aire, et que
 e
si n ∈ N , si p est un entier, p ≥ 1, et si enfin a1 , a2 , . . . , ap sont des arbres n-aires, alors (n, a1 , . . . , ap ) est
                                                                             e
aussi un arbre n-aire. Dans ce dernier cas on dit que n est le nœud p`re de chacun des ai , que les ai sont des
               e
sous-arbres fr`res, fils du nœud n.

        e                                                             c           `
On repr´sente bien entendu graphiquement les arbres n-aires, d’une fa¸on analogue a ce qu’on a fait pour
                                                                  e
les arbres binaires, comme sur l’exemple de la figure 5.1, qui repr´sente l’arbre

                                         (n1 , (n2 , f1 , f2 , f3 ), (n3 , (n4 , f4 , f5 ))).


                                                                   n1


                                                          n2                 n3



                                                 f1       f2       f3        n4



                                                                        f4        f5


                                         Fig. 5.1: Un exemple d’arbre n-aire

                             e                                              e
Notons qu’il n’est pas demand´ aux nœuds d’un arbre n-aire d’avoir tous le mˆme nombre de fils.

                                                                 45
46                                                                             ´
                              CHAPITRE 5. ARBRES N -AIRES ET EXPRESSIONS ARITHMETIQUES

5.1.2           e
            Impl´mentation
                       e                                           a e                      u
Une solution pour impl´menter les arbres n-aires en Caml consiste ` d´finir un nouveau type o` les nœuds
contiennent leur information propre et une liste d’arbres binaires :
        type (’f,’n) arbre_n_aire =
            | Feuille of ’f
            | Nœud of ’n * (’f,’n) arbre_n_aire list ;;

                                            e e        e
L’arbre de l’exemple de la figure 5.1 page pr´c´dente s’´crit alors
        Nœud("n1", [ Nœud("n2", [ Feuille("f1"); Feuille("f2"); Feuille("f3") ]) ;
                     Nœud("n3", [ Nœud("n4" ,
                                       [ Feuille("f4"); Feuille("f5") ] ) ] )
                   ] )


5.1.3             e e
            Propri´t´s
               e           e     c
On ne peut d´finir de la mˆme fa¸on que pour les arbres binaires la taille d’un arbre n-aire, car il n’y a
                                                                                                   e
plus de relation automatique entre nombre de feuilles et nombre de nœuds. Il conviendra donc de pr´ciser
                   a
ces deux nombres ` chaque fois qu’on voudra parler de la taille d’un arbre n-aire.

Programme 5.1 Nombre de nœuds et feuilles d’un arbre n-aire
             let rec nb_feuilles = function
                 | Feuille(_) -> 1
                 | Nœud(_,liste_fils)
                     -> it_list (fun n a -> n + (nb_feuilles a))
                                0
                                liste_fils ;;

             let rec nb_nœuds = function
                 | Feuille(_) -> 0
                 | Nœud(_,liste_fils)
                     -> it_list (fun n a -> n + (nb_nœuds a))
                                1
                                liste_fils ;;


                 e          c
En revanche, on d´finit de fa¸on analogue la profondeur d’un nœud ou d’une feuille de l’arbre, ce qui fait
l’objet du programme 5.2.

Programme 5.2 Profondeur d’un arbre n-aire
             let rec profondeur = function
                 | Feuille(_) -> 0
                 | Nœud(_,liste_fils)
                     -> 1 + it_list (fun M a -> max M (profondeur a))
                                    0
                                    liste_fils ;;



                               e                                                        e
              Nous avons utilis´ ici la fonction it list, qui fait partie de la biblioth`que standard de Caml.
              Son type est : (’a -> ’b -> ’a) -> ’a -> ’b list -> ’a.
                                                        e
     L’appel it_list f a [ b1 ; b2 ; ... ; bn ] s’´value en

                                            f (. . . (f (f (a, b1 ), b2 ) . . .), bn )


5.1.4       Parcours d’un arbre n-aire
      e      e                               e                                          e
On d´finit tr`s naturellement les parcours pr´fixe et suffixe d’un arbre n-aire, et on peut ´crire facilement
les fonctions Caml correspondantes, ce qui fait l’objet du programme 5.3 page suivante.
                         e                                                                    u
En revanche, il est bien ´vident que cela n’aurait pas de sens de parler de parcours infixe : o` placer la
                  `
racine d’un arbre a 3 fils ?
                       ´
5.2. EXPRESSIONS ARITHMETIQUES                                                                           47

                         e
Programme 5.3 Parcours pr´fixe et suffixe d’un arbre n-aire
                              e
           let rec parcours_pr´fixe = function
               | Feuille(f) -> [ F f ]
               | Nœud(n,liste_fils)
                                                          e
                   -> it_list (fun l a -> l @ (parcours_pr´fixe a))
                              [N n]
                              liste_fils ;;

           let rec parcours_suffixe = function
               | Feuille(f) -> [ F f ]
               | Nœud(n,liste_fils)
                   -> (it_list (fun l a -> l @ (parcours_suffixe a))
                               []
                               liste_fils) @ [ N n ] ;;



               e          ıt                                                   `          e
Un autre probl`me apparaˆ au moment de reconstituer un arbre a partir de son parcours pr´fixe (ou
                 e         e
suffixe, c’est le mˆme probl`me). En effet, si on reprend l’arbre exemple de la figure 5.1 page 45, son
           e      e
parcours pr´fixe s’´crit :
                                  n1 , n2 , f1 , f2 , f3 , n3 , n4 , f4 , f5 .
         e                                                           e    e
Mais on v´rifie sans peine que c’est aussi le parcours de l’arbre repr´sent´ dans la figure 5.2.

                                                          n1


                                                n2        f3        n3



                                           f1        f2        n4        f5


                                                               f4


                                                              e              e
                          Fig. 5.2: Un autre arbre n-aire de mˆme parcours pr´fixe

On peut n´anmoins lever l’ambigu¨ e, ` condition que tout nœud portant une mˆme valeur nk donn´e
           e                     ıt´ a                                          e                   e
        e                                                   e
ait le mˆme nombre de fils. Ce nombre de fils s’appelle l’arit´ du nœud, et on suppose donc qu’il existe
une fonction
          e
      arit´ : ’n -> int
     e                                                 a                          e
Nous ´crivons par exemple la reconstitution de l’arbre ` partir de son parcours pr´fixe dans le pro-
gramme 5.4 page suivante.


5.2                       e
        Expressions arithm´tiques
5.2.1         e
         Une d´finition
                                          e                                              e
Nous allons maintenant donner une d´finition rigoureuse d’une expression arithm´tique. Nous con-
   e                                     `               e
sid`rerons des expressions construites a l’aide des op´rations habituelles (addition, soustraction, mul-
                         ee        a                                   e
tiplication, division et ´l´vation ` une puissance), des constantes r´elles, des variables, et des fonctions
                            a
(nous nous limiterons ici ` l’exponentielle, son logarithme, et les sinus et cosinus).

D´finition 5.2 (Expressions arithm´tiques) On consid`re un ensemble O d’op´rations ` 2 arguments, par
  e                                 e                  e                       e       a
exemple O = {+, −, ×, /, ↑} ; un ensemble C de constantes, par exemple C = R ; un ensemble V de variables,
48                                                                          ´
                           CHAPITRE 5. ARBRES N -AIRES ET EXPRESSIONS ARITHMETIQUES

                                               a                          e
Programme 5.4 Reconstitution d’un arbre n-aire ` partir de son parcours pr´fixe
                            e               e
           let recompose_pr´fixe_naire arit´ l =
               let rec recompose = function
                   | (F f) :: reste -> Feuille(f), reste
                   | (N n) :: reste
                                                                    e
                        -> let liste_fils,reste = cherche_fils (arit´ n) reste
                           in
                           Nœud(n,liste_fils),reste
                                                      e
                   | [] -> failwith "Description pr´fixe 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
                                                    e
                   | _ -> failwith "Description pr´fixe incorrecte" ;;




par exemple V = {A, B, . . . , X, Y, Z} ; et un ensemble F de fonctions ` 1 argument, par exemple F =
                                                                            a
{sin, cos, ln, exp}. On d´finit l’ensemble A des expressions arithm´tiques correspondantes de fa¸on r´cursive :
                         e                                        e                            c    e
  — toute constante est une expression arithm´tique : C ⊂ A ;
                                             e
  — toute variable est une expression arithm´tique : V ⊂ A ;
                                            e
  — si c ∈ O et si u et v sont des expressions arithm´tiques, alors (ucv) est aussi une expression arithm´tique ;
                                                     e                                                   e
  — si f ∈ F et si u est une expression arithm´tique, alors f (u) est aussi une expression arithm´tique.
                                              e                                                  e


5.2.2                 e
         Syntaxe concr`te et syntaxe abstraite
                              e
En Caml, on introduit ainsi tr`s 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 l’expression 2 + sin2 (3 + X) est l’´criture math´matique habituelle de l’expression arithm´tique
                                          e            e                                         e
(2 + (sin((3 + X)) ↑ 2)). Notons qu’on a l’habitude en math´matiques de se dispenser de certaines
                                                               e
        e                               e
parenth`ses qu’impose pourtant notre d´finition.
                              `
Notre expression correspond a une valeur Caml de type (float,char,char,fonction) expression, o`       u
                          e
le type fonction serait d´fini par
      type fonction = Sin | Cos | Exp | Ln ;;

                 e
La valeur Caml s’´crirait :
      Terme(Constante(2.0),
            ‘+‘,
            Terme(Application(Sin,Terme(Constante(3.0),‘+‘,Variable(‘X‘))),
                  ‘^‘,
                  Constante(2.0))) ;;

                            e                     e              e                                  e
Comme on le constate ais´ment, passant de la d´notation math´matique habituelle (la syntaxe concr`te),
` la notation Caml (la syntaxe abstraite), on complique grandement l’´criture des expressions, mais on a
a                                                                       e
 e e
r´alis´ l’essentiel de leur analyse, ce qui permet ensuite des manipulations bien plus faciles.
                       ´
5.2. EXPRESSIONS ARITHMETIQUES                                                                           49

5.2.3    Expressions et arbres
                             e
Arbre d’une expression arithm´tique
                                  `                      e
On peut naturellement associer a une expression arithm´tique un arbre n-aire : l’ensemble des valeurs
des feuilles est C ∪ V, l’ensemble des valeurs des nœuds est O ∪ F. Ceci s’exprime en Caml de la fa¸on
                                                                                                   c
suivante :
     type nœud = F of fonction | O of char ;;
     type feuille = N of float | V of char ;;
                                                        u                               e
Notons que nous sommes ici dans le cas favorable o` il existe une fonction d’arit´ (voir la section
   e e
pr´c´dente), ce qui permet de mettre bijectivement en relation les arbres d’expressions et leurs parcours
   e
pr´fixes ou suffixes.
                    e
On peut facilement ´crire les fonctions de conversion d’une expression en arbre et inversement, ce qui fait
l’objet du programme 5.5.

                                                                e
Programme 5.5 Conversions arbres d’expression/expressions arithm´tiques
           let rec arbre_d’expression = function
               | Constante x -> Feuille (N x)
               | Variable v -> Feuille (V v)
               | Terme(a,o,b) ->   let g = arbre_d’expression a
                                   and d = arbre_d’expression b
                                   in
                                   Nœud(O o, [ g ; d ])
               | Application(f,a) -> Nœud(F f, [ (arbre_d’expression a) ]) ;;

           let rec expression_d’arbre = function
               | Feuille (N x) -> Constante(x)
               | Feuille (V x) -> Variable(x)
               | Nœud(O o, [ e ; f ])
                   -> Terme(expression_d’arbre e,o,expression_d’arbre f)
               | Nœud(F f, [ e ]) -> Application(f,expression_d’arbre e)
               | _ -> failwith "Ce n’est pas un arbre d’expression" ;;




´                                               e
Evaluation et impression d’une expression arithm´tique
       ea              e      e             e                           e         e
On a d´j` vu en premi`re ann´e comment ´valuer une expression donn´e par son ´criture suffixe. On aura
         e                         e                     a
remarqu´ combien le programme ´crit alors ressemble ` celui qui permet la reconstitution d’un arbre a   `
                                                          ıvet´        e
partir de son parcours suffixe, et on n’aura pas eu la na¨ e de s’en ´tonner.
       e e                                                          e
Plus g´n´ralement, l’arbre d’une expression permet facilement d’´valuer l’expression ou encore de l’im-
            e        e
primer en ´criture pr´fixe, infixe ou suffixe.
                                        e                                          `   e
Occupons nous pour commencer de l’´valuation. Il faut ici simplement ajouter a la s´mantique d´critee
          e      e
en premi`re ann´e ce qui concerne les variables. En bref, il faut expliquer ce qu’on veut obtenir dans
  e                                                   e
l’´valuation d’une variable. Pour cela, il nous faut d´finir la notion d’environnement d’une expression.

  e                                 e                                        e
D´finition 5.3 (Environnement d’´valuation) On appelle environnement d’´valuation des variables d’une
expression arithm´tique sur les ensembles C, V, F et O toute application ψ de V dans C.
                 e

                               e
En Caml, un environnement d’´valuation des variables sera simplement une liste associative, c’est-`-direa
                                                                              e
une liste de couples variables/valeurs de la forme (vari , vali ). La biblioth`que Caml fournit la fonction
                                             e a                                             e            e
assoc qui permet de chercher la valeur associ´e ` une variable, et qu’on pourrait d’ailleurs ´crire soi-mˆme
comme suit.
     let rec assoc v env = match env with
         | [] -> failwith "Variable absente de l’environnement"
         | (var,val) :: q -> if v = var then val else assoc v q ;;


D´finition 5.4 (S´mantique d’une expression arithm´tique) Soit A l’ensemble des expressions arithm´-
  e                e                                    e                                                 e
tiques sur les ensembles C, V, F et O. Soit ψ un environnement d’´valuation des variables. On suppose qu’est
                                                                 e
50                                                                            ´
                             CHAPITRE 5. ARBRES N -AIRES ET EXPRESSIONS ARITHMETIQUES

                                      ˆ
associ´e ` tout f ∈ F une fonction f de C dans lui-mˆme, et ` tout o ∈ O une fonction o de C 2 dans C. On
      e a                                              e       a                      ˆ
 e            e              e
d´finit alors r´cursivement l’´valuation d’une expression :
   — si c ∈ C, alors eval(c) = c ;
   — si v ∈ V, alors eval(v) = ψ(v) ;
                                                            ˆ
   — si f ∈ F, si u est une expression, alors eval(f (u)) = f (eval(u)) ;
     — si o ∈ O, si u et v sont deux expressions, alors eval((uov)) = o(eval(u), eval(v)).
                                                                      ˆ
  e                     e e
L’´valuation est alors r´alis´e par le programme 5.6.

              ´                                e
Programme 5.6 Evaluation des expressions arithm´tiques
                     e
             let rec ´valuation environnement = function
                 | Constante x -> x
                 | Variable v -> assoc v environnement
                                             e
                 | Terme(a,o,b) -> let x = ´valuation environnement a
                                             e
                                    and y = ´valuation environnement b
                                    in
                                    ( match o with
                                           | ‘+‘ -> x +. y
                                           | ‘-‘ -> x -. y
                                           | ‘/‘ -> x /. y
                                           | ‘*‘ -> x *. y
                                           | ‘^‘ -> power x y
                                                              e
                                           | _ -> failwith "Op´ration inconnue" )
                                                 e
                 | Application(f,a) -> let x = ´valuation environnement a
                                        in
                                        ( match f with
                                               | Sin -> sin x
                                               | Cos -> cos x
                                               | Exp -> exp x
                                               | Ln -> log x ) ;;


                     e                                   e
Les impressions pr´fixe et suffixe ne posent pas de probl`me particulier. Rappelons que l’existence d’une
                e                                          e
fonction d’arit´ permet de se dispenser de tout parenth´sage. On trouvera ces fonctions dans le pro-
gramme 5.7 page suivante.
                                                                e                   e
Pour l’impression infixe, en revanche, il est indispensable d’´crire des parenth`ses. La suppression des
         e             e                                     e                    e
parenth`ses qu’on n’´crit pas habituellement est un probl`me difficile, qui n´cessite qu’on discute des
       e          e                           e
priorit´s des op´rateurs. C’est une difficult´ analogue qu’on rencontre quand on veut programmer le
              e              `                                                                       e
passage de l’´criture infixe a la syntaxe abstraite des expressions. Nous nous contenterons ici d’´crire
                    e
toutes les parenth`ses, y compris celles qui sont superflues, ce qui est fait dans le programme 5.8 page 52.


5.3         e
           D´rivation formelle
5.3.1        e             e
            D´rivation guid´e par la structure d’arbre
         e                                                                             e          e
On peut ´galement utiliser la structure qu’on a introduite ici des expressions arithm´tiques pour ´crire
                  e                                                        e
un programme de d´rivation formelle, utilisant les formules classiques de d´rivation :
                    (u + v) = u + v              (u − v) = u − v             (uv) = u v + uv
                  (u/v) = u /v − uv /v 2   (uv ) = uv v ln u + u(v−1) u v      (ln u) = u /u
                    (exp u) = u exp u            (sin u) = u cos u          (cos u) = −u sin u
                 `           e
Traduisant mot a mot ces r`gles, on obtient facilement le programme 5.9 page 52.
Reprenant l’expression e = 2 + sin2 (3 + X), on trouve comme d´riv´e par rapport a X l’expression
                                                                      e e                `
0 + sin2 (3 + X) × 0 × ln sin(3 + X) + sin(2−1) (3 + X) × 2 × (0 + 1) × cos(3 + X). La d´riv´e par rapport
                                                                                        e e
` Y donne l’expression 0 + sin2 (3 + X) × 0 × ln sin(3 + X) + sin(2−1) (3 + X) × 2 × (0 + 0) × cos(3 + X).
a
                                                               a      a
Il va de soi que ces expressions ne correspondent pas tout ` fait ` notre attente, et il convient de les
simplifier au moins un peu, ce qui fait l’objet de ce qui suit.
      ´
5.3. DERIVATION FORMELLE                                                        51




                            e
Programme 5.7 Impressions pr´fixe et suffixe des expressions
                           e
         let impression_pr´fixe expr =
             let a = arbre_d’expression expr
             in
             let rec imprime = function
                 | Feuille(N x) -> print_float x ; print_char ‘ ‘
                 | Feuille(V x) -> print_char x ; print_char ‘ ‘
                 | Nœud(O o, [ e ; f ])
                     -> print_char o ; print_char ‘ ‘ ; imprime e ; imprime f
                 | Nœud(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_d’expression expr
             in
             let rec imprime = function
                 | Feuille(N x) -> print_float x ; print_char ‘ ‘
                 | Feuille(V x) -> print_char x ; print_char ‘ ‘
                 | Nœud(O o, [ e ; f ])
                     -> imprime e ; imprime f ; print_char o ; print_char ‘ ‘
                 | Nœud(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 N -AIRES ET EXPRESSIONS ARITHMETIQUES


Programme 5.8 Impression infixe des expressions
         let impression_infixe expr =
             let a = arbre_d’expression expr
             in
             let rec imprime = function
                 | Feuille(N x) -> print_float x
                 | Feuille(V x) -> print_char x
                 | Nœud(O o, [ e ; f ])
                     -> print_char ‘(‘ ;
                          imprime e ; print_char ‘ ‘ ;
                          print_char o ;
                          print_char ‘ ‘ ; imprime f ;
                          print_char ‘)‘
                | Nœud(O o, [ e ; f ])
                     -> print_char ‘(‘ ;
                          imprime e ; print_char o ; imprime f ;
                          print_char ‘)‘
                 | Nœud(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 ;;




               e                                        e
Programme 5.9 D´rivation formelle des expressions arithm´tiques
                  e
         let rec d´rivation 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)
                                    e
                     -> let u’ = d´rivation u x
                                    e
                         and v’ = d´rivation 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)
                                    e
                     -> let u’ = d´rivation 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. DERIVATION FORMELLE                                                                                   53

5.3.2                             e
         Simplification : une premi`re approche
                                                  ee
Nous nous contentons ici d’une simplification ´l´mentaire des expressions. Une simplification plus com-
  e                                                  e        e
pl`te des expressions poserait de redoutables probl`mes de d´finition et nous n’en parlerons pas davantage.
On obtient ainsi le programme 5.10 page suivante.
        a     e                e                      e e                e
Et voil` le r´sultat, sur le mˆme exemple que pr´c´demment. On v´rifiera sur cette session Caml que
                                              e            ee e e
toutes les simplifications qu’on pouvait esp´rer ont bien ´t´ r´alis´es. En revanche, il ne fallait pas compter
                                                        u                        e
sur la simplification de 2 sin a cos a en sin(2a), bien sˆr. On pourrait quand mˆme essayer de reconnaˆ    ıtre
              e       e     e                                                         e      e
dans une diff´rence l’´galit´ des deux termes, ou dans un quotient ou un produit l’´galit´ des facteurs, ce
                                            e
qui permettrait des simplifications suppl´mentaires.
54                                                                       ´
                        CHAPITRE 5. ARBRES N -AIRES ET EXPRESSIONS ARITHMETIQUES

                                                e
Programme 5.10 Simplification des expressions alg´briques
         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 qu’il en soit voici ce qu’on obtient :
                                           e
      #impression_infixe (simplification (d´rivation expr ‘X‘) ) ;;
      (sin((3.0 + X)) * (2.0 * cos((3.0 + X))))- : unit = ()
                                           e
      #impression_infixe (simplification (d´rivation expr ‘Y‘) ) ;;
      0.0- : unit = ()



5.4     Exercices pour le chapitre 5
                                              a
Exercice 5.1 Reconstitution d’un arbre n-aire ` partir du parcours suffixe
´                                                              a
Ecrire le programme qui permet de reconstituer un arbre n-aire ` partir de son parcours suffixe, supposant
                         e
connue la fonction d’arit´.

Exercice 5.2 Impression infixe des expressions
´                                 e                                                    e
Ecrire un programme Caml qui g`re une impression infixe des expressions sans parenth`ses inutiles.
On rappelle que ↑ est prioritaire par rapport a × et /, eux-mˆmes prioritaires par rapport a + et −.
                                              `              e                             `
     e
Deuxi`me partie

 Automates




       57
Chapitre 6

                 e
Automates finis d´terministes ou
     e
non d´terministes

6.1                      e
         Automates finis d´terministes
6.1.1       e
          Pr´sentation informelle
                          e          e    a                                    e         e   e
Un automate est un syst`me qui r´agit ` des stimuli. Ces stimuli peuvent ˆtre repr´sent´s de diff´rentese
      e    `                                                                   e     u e             e
mani`res. A chaque stimulus, l’automate peut se bloquer, ou bien passer de l’´tat o` il ´tait avant r´ception
` un nouvel ´tat, voire rester dans le mˆme ´tat.
a             e                           e    e
                e                                      e                             e
Nous nous int´resserons dans ce cours tout particuli`rement aux automates qui r´agissent aux caract`res    e
                                   e                                   e
d’un alphabet. Si donc on consid`re un automate dans un certain ´tat initial, on lui fait lire une chaˆ     ıne
          e          a                     e                              e             e
de caract`res, c’est-`-dire qu’on le fait r´agir successivement aux diff´rents caract`res qui composent la
chaˆ                                                               ıne
    ıne. Le processus peut s’interrompre avant la fin de la chaˆ : ou bien l’automate s’est bloqu´, ou    e
                     e                                                       e        e          `
bien tous les caract`res sont lus, et on peut dire que l’automate est pass´ de son ´tat initial a un nouvel
e             e                               ıne
´tat, qui est ´videmment fonction de la chaˆ lue.
      e e            e        e
En g´n´ral, on num´rote les ´tats possibles de l’automate.
                                                        e
L’automate est dit fini s’il n’a qu’un nombre fini d’´tats et si l’alphabet (l’ensemble des stimuli) est lui
aussi fini.
                       e   `                                           e    e              e             e
Les transitions d’un ´tat a l’autre, sous l’effet des stimuli, sont repr´sent´es par des fl`ches entre les ´tats
e       e
´tiquet´es par le nom du stimulus.
                   e
La figure 6.1 repr´sente un automate fini.

                                                   b                a

                                                            a
                                                   1                2

                                                                a       b
                                                            b

                                                                    3


                                                                     e
                        Fig. 6.1: Un premier exemple d’automate fini d´terministe

                         e        e
Cet automate a trois ´tats, not´s 1, 2 et 3.
        e              e    e              e
1 est l’´tat initial (d´sign´ par le petit ´clair).
          e         e                       e                                                         e
3 est un ´tat dit ´tat d’acceptation ou ´tat final (il peut y en avoir plusieurs), puisqu’il est entour´ de
deux cercles.

                                                       59
60                                           ´                    ´
                CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES

               e                         ıne                                        e
Partant de l’´tat 1, la lecture de la chaˆ abba nous fait passer successivement aux ´tats 2, 3, 1 et enfin 2.
                          e                           ıne
Comme ce n’est pas un ´tat final, on dit que la chaˆ n’est pas reconnue par l’automate.
                   ıne                                  `      e              e
Si on lisait la chaˆ abca, l’automate se bloquerait a l’arriv´e du c dans l’´tat 3. On dit que la chaˆ   ıne
                                      a                                           e
n’est pas reconnue par l’automate ` cause du blocage, bien qu’on soit dans un ´tat final.
               ıne
Enfin, la chaˆ bbaaab est reconnue par cet automate, et on peut montrer que l’ensemble des chaˆ          ınes
reconnues est l’ensemble de toutes les chaˆ  ınes sur les deux lettres a et b qui finissent exactement par
       e                                 u                  u                              a e
ab : l’´tat 2 correspond au moment o` on a lu un a et o` on attend un b pour passer ` l’´tat final 3 ;
  e                  `                         e
l’´tat 1 correspond a ce qui arrive quand apr`s avoir bien lu ab, on tombe sur un b, et que tout est donc
a
` refaire. . .


6.1.2       e              e
          Pr´sentation math´matique
     c
De fa¸on plus rigoureuse on peut donner la

D´finition 6.1 (Automates finis d´terministes) Soit A un alphabet fini. Un automate fini d´terministe
  e                                  e                                                             e
(en abr´g´ afd) est un quadruplet (Q, q0 , F, ϕ) o` Q est un ensemble fini d’´l´ments appel´s ´tats, q0 est un
       e e                                        u                          ee            e e
´l´ment de Q, appel´ ´tat initial, F est une partie non vide de Q, dont les ´l´ments sont appel´s ´tats finals,
ee                  ee                                                      ee                 e e
et o` ϕ est une fonction de Q × A dans Q.
    u

                                                                           e              e
On notera que ϕ est une fonction, et non une application : elle n’est pas n´cessairement d´finie pour tout
couple (q, c) ∈ Q × A.
L’automate ´tant fix´, si pour c ∈ A et pour deux ´tats q et q on a ϕ(q, c) = q , on dira qu’il existe une
              e       e                              e
                                             c
transition de q vers q sur c et on notera q → q .
Reprenant l’automate repr´sent´ dans la figure 6.1 page pr´c´dente, on peut choisir A = {a, b}, Q =
                             e    e                            e e
{1, 2, 3}, q0 = 1, F = {3}, et ϕ est d´finie par le tableau suivant :
                                      e
                                                q   c       ϕ(q, 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
 e
D´finitions
                          c
On a dit qu’on notait q → q si ϕ(q, c) = q : il s’agit l` d’une transition toute banale. On peut g´n´raliser
                                                        a                                         e e
a
` ce qu’on appellera un calcul.

D´finition 6.2 (Mots) Soit A un alphabet fini. Un mot est une suite finie ´ventuellement vide d’´l´ments
  e                                                                         e                          ee
de A. Le mot vide est not´ ε. Un mot w de taille n est constitu´ des ´l´ments successifs w0 , w1 , . . . , wn−1 .
                         e                                     e     ee
L’ensemble des mots sur A est not´ A∗ .
                                 e

D´finition 6.3 (Calculs d’un afd) Soit A un alphabet fini et (Q, q0 , F, ϕ) un afd sur cet alphabet. Soit q
  e
           e
et q deux ´tats de l’automate et w un mot non vide de longueur n. On dira qu’un calcul de l’automate fait
passer de q ` q ` la lecture de w si il existe n − 1 ´tats q1 , . . . , qn−1 tels que
            a a                                      e
                                        w       w       wn−2          wn−1
                                     q −→ q1 −→ · · · −→ qn−1 −→ q .
                                        0     1



                        w                               ε
On notera ce calcul : q → q . Par convention on a q → q pour tout ´tat q ∈ Q.
                                                                  e
         ´
6.2. IMPLEMENTATION EN CAML D’UN AFD                                                                        61

      e e
Propri´t´s
    e          e                    ee
On d´montre ais´ment les deux propri´t´s suivantes :

                ∀(w1 , w2 ) ∈ A∗2 , ∀(q1 , q2 , q3 ) ∈ Q3 , (q1 −→ q2 et q2 −→ q3 ) ⇒ q1 −→2 q3 ,
                                                               w 1       w   2           w .w
                                                                                         1




 u         e
o` on a not´ w1 .w2 le mot r´sultat de la concat´nation des mots w1 et w2 ;
                            e                   e

                              ∀w ∈ A∗ , ∀(q, q , q ) ∈ Q3 , (q → q et q → q ) ⇒ q = q ,
                                                           w         w



                   e
ce qui traduit le d´terminisme de l’automate.

6.1.4                                          e
          Langage reconnu par un automate fini d´terministe
                     e
On est en mesure de d´finir rigoureusement les mots reconnus par un afd.

                                                ´
D´finition 6.4 (Mots accept´s par un afd) Etant donn´ un alphabet A et un afd (Q, q0 , F, ϕ), un mot
  e                             e                           e
        ∗                                                                            w
w ∈ A est dit reconnu ou accept´ par l’automate si il existe q ∈ F tel que q0 → q. Dans les autres cas,
                                    e
      a                                                                   e           e
c’est-`-dire si l’automate se bloque pendant la lecture de w ou s’il s’arrˆte dans un ´tat non final, on dit que
                  e
le mot est rejet´ par l’automate, ou encore qu’il n’est pas reconnu.

                                                            ıt
Le langage d’un afd α est l’ensemble des mots qu’il reconnaˆ : on le notera L(α).
                   ea                                           e           e                    e
Notons d’ores et d´j` que deux automates distincts peuvent d´finir le mˆme langage. On v´rifiera par
                                           e              e
exemple que les automates de la figure 6.2 d´finissent le mˆme langage que celui de la figure 6.1 page 59.
                                           e                            a         e
Le premier d’entre eux comporte en effet un ´tat (4) inaccessible, c’est-`-dire un ´tat q tel que pour aucun
                    w
mot w on n’ait q0 → q. Le second ne comporte pas d’´tat inaccessible, mais d´finit pourtant le mˆme
                                                       e                           e                    e
langage.

                          b                  a                                                  b

                                    a                                                 a
                          1                  2                                   1              2


                                         a                                           a      a
                      b                          b                           b                      b
                                   b

                          4         a        3                                   4              3
                                                                                      b

                                                                                 b

                                                                   e
                                 Fig. 6.2: Deux automates pour un mˆme langage

                                         e        e                               e
Un afd est dit minimal si tout afd qui d´finit le mˆme langage a au moins autant d’´tats. Il va de soi
        ee        e e
qu’on pr´f`re en g´n´ral manipuler des afd minimaux. . .


6.2          e
         Impl´mentation en Caml d’un afd
         e                          e                 e             c
Pour repr´senter les afd on pourra d´finir le type des ´tats de la fa¸on suivante :
           e
      type ´tat_de_afd =
          { mutable est_terminal : bool ;
                                e
             transitions : arriv´e vect }
                e                    e
      and arriv´e = Blocage | OK of ´tat_de_afd ;;
62                                            ´                    ´
                 CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES

Si q est un ´tat, q.est_terminal dit si oui ou non q ∈ F, et q.transitions est un vecteur de 256
             e
                                       e
valeurs, correspondant aux 256 caract`res dans le codage ascii. q.transitions.(i) vaudra Blocage s’il
n’y a pas de transition a partir de q sur le caract`re c de code ascii i, ou bien OK(q’) si ϕ(q, c) = q .
                        `                          e
                   e
On programme ais´ment la reconnaissance d’une chaˆ     ıne, ce qui fait l’objet du programme 6.1.

                                      ıne
Programme 6.1 Reconnaissance d’une chaˆ par un afd
             exception ´chec ;;
                       E

                  e
             type ´tat_de_afd =
                 { mutable est_terminal : bool ;
                                       e
                    transitions : arriv´e vect }
                       e                    e
             and arriv´e = Blocage | OK of ´tat_de_afd ;;

             let lit_transition_afd q1 c =
                 match q1.transitions.(int_of_char c) with
                     | Blocage -> raise ´chec
                                        E
                     | OK(q2) -> q2 ;;

                 e
             let ´crit_transition_afd q1 c q2 =
                 q1.transitions.(int_of_char c) <- OK(q2) ;;

                        ı e           e      ı
             let reconna^t ´tat_de_d´part cha^ne =
                                  e
                 let rec transite ´tat i n =
                                    e
                     if i = n then ´tat.est_terminal
                                                       e       ı
                     else transite (lit_transition_afd ´tat cha^ne.[i]) (i+1) n
                 in
                 try
                              e         e                        ı
                     transite ´tat_de_d´part 0 (string_length cha^ne)
                 with _ -> false ;;


                                                                   u                            ıne
Il est clair que cet algorithme de reconnaissance tourne en O(n), o` n est la longueur de la chaˆ de
       e        e
caract`res test´e.
Indiquons au passage comment, par exemple, on entre la description de l’afd de la figure 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 } ;;

        ´crit_transition_afd
        e                      q1   ‘a‘   q2   ;;
        e
        ´crit_transition_afd   q1   ‘b‘   q1   ;;
        ´crit_transition_afd
        e                      q2   ‘a‘   q2   ;;
        ´crit_transition_afd
        e                      q2   ‘b‘   q3   ;;
        ´crit_transition_afd
        e                      q3   ‘a‘   q2   ;;
        ´crit_transition_afd
        e                      q3   ‘b‘   q1   ;;

                                                                  ıne
L’appel reconna^t q0 cha^ne renvoie true si et seulement si la chaˆ est reconnue par l’automate dont
                   ı    ı
  e
l’´tat initial est q0.


6.3                           e
          Automates finis non d´terministes
6.3.1        e
           Pr´sentation informelle
                                                                                   e
On trouvera dans la figure 6.3 page suivante un premier exemple d’automate fini non d´terministe (afnd
      e e
en abr´g´).
                         e                    `
On remarque quelques diff´rences avec les afd, a savoir essentiellement :
                e         e      e
  — certaines fl`ches sont ´tiquet´es par la lettre ε : il s’agit de ce qu’on appellera donc des ε-transitions,
                                                                 e    a          e
    et l’automate passera tout seul en cas de besoin d’un ´tat ` un autre ´tat par la voie d’une telle
    transition ;
                                    e                   e    e      e      e          e
     — on peut trouver plusieurs fl`ches issues d’un mˆme ´tat et ´tiquet´es de la mˆme lettre : c’est ce
                              ıt´                                            e
       qui fait toute l’ambigu¨ e d’un afnd, et explique qu’on parle de non-d´terminisme.
                          ´
6.3. AUTOMATES FINIS NON DETERMINISTES                                                                                63


                                                                                     b

                                                  ε                      b
                                      2                      1                   5

                                              ε       a              b
                                                                             a
                                          b                      b

                                                  3          a           4


                                                                 e
                                  Fig. 6.3: Un automate fini non d´terministe


     e
On v´rifiera sur cet exemple que les mots b, bbb ou encore baa sont reconnus par cet automate : les
           e                                                             e                        e
parcours d’´tats correspondants sont 15, 1415 ou 1555, 12345. On aura not´ qu’il n’y a plus unicit´. . .


6.3.2      e            e
          D´finition math´matique
 e
D´finition d’un afnd
D´finition 6.5 (Automates finis non d´terministes) Soit A un alphabet fini. Un automate fini non d´ter-
  e                                       e                                                               e
ministe (en abr´g´ afnd) est un quintuplet (Q, q0 , F, ϕ, ψ) o` Q est un ensemble fini d’´l´ments appel´s ´tats,
                e e                                           u                         ee            e e
q0 est un ´l´ment de Q, appel´ ´tat initial, F est une partie non vide de Q, dont les ´l´ments sont appel´s
          ee                    ee                                                       ee                  e
´tats finals, et o` ϕ (resp. ψ) est une application de Q × A (resp. Q) dans P(Q), ensemble des parties de Q.
e                u

             e                    `            e                    e
On aura not´ qu’une transition a partir d’un ´tat q sur le caract`re c se calcule par ϕ : ϕ(q, c) est
l’ensemble des ´tats auxquels on peut aboutir par cette transition, et ∅ dans le cas o` il n’y a pas de
                e                                                                      u
           `
transition a partir de q sur c.
         c                      e                 e              a
D’une fa¸on analogue, ψ(q) d´signe l’ensemble des ´tats atteints ` partir de q par une ε-transition.
                                                                     e
            Certains auteurs s’autorisent, pour les afnd, plusieurs ´tats initiaux, q1 , q2 , . . . , qk . Il suffit,
                              a         e                            e
            pour se ramener ` notre d´finition, d’ajouter un unique ´tat initial q0 et des -transitions de q0
            vers chacun des qi , 1 ≤ i ≤ k. C’est pourquoi nous avons choisi de consid´rer syst´matiquement
                                                                                      e            e
                    e
  qu’il n’y a qu’un ´tat initial pour chacun de nos automates.



               e
Fermeture d’un ´tat
       e                                                                       e
Pour d´finir proprement les calculs qu’effectue un afnd il nous faut maintenant d´finir ce qu’on appelle
                  e
la fermeture d’un ´tat par ε-transition.

D´finition 6.6 (Fermeture par ε-transition) Soit A un alphabet fini et (Q, q0 , F, ϕ, ψ) un afnd sur cet
  e
alphabet. Pour tout ´tat q ∈ Q on d´finit sa fermeture par ε-transition et on notera κ(q) la plus petite partie
                    e              e
                      e
de Q contenant q et v´rifiant :
                                                            ψ(q ) ⊂ κ(q).
                                                  q ∈κ(q)

     c e
De fa¸on ´vidente, on montre le

    e e
Th´or`me 6.1 (Calcul des fermetures)
Soit A un alphabet fini et (Q, q0 , F, ϕ, ψ) un afnd sur cet alphabet. Soit q un ´tat fix´. On d´finit r´cursivement
                                                                                e      e      e      e
les parties (Kn ) de Q en posant K0 = {q}, et, pour n ≥ 1, Kn = Kn−1 ∪ q ∈Kn−1 ψ(q ). La suite (Kn ) est
                                                         e     a
croissante et stationnaire (pour l’inclusion), de limite ´gale ` κ(q).
64                                             ´                    ´
                  CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES

     4 La suite (Kn ) est ´videmment croissante, et, comme Q est fini, elle est stationnaire. Soit K sa
                              e
     limite. Bien sˆr q ∈ K.
                   u
     Soit q ∈ K. Il existe un indice p ≥ 0 tel que q ∈ Kp . Mais alors ψ(q ) ⊂ Kp+1 ⊂ K, et K v´rifie donc
                                                                                               e
     bien la propri´t´ requise par κ(q), ce qui montre que κ(q) ⊂ K.
                   ee
     R´ciproquement, on montre par r´currence sur n que les Kn sont inclus dans κ(q). 3
       e                                e
                     e                             e                          e             a
Intuitivement, κ(q) d´signe l’ensemble de tous les ´tats (dont q) qui peuvent ˆtre atteints ` partir de q
   e
apr`s un nombre fini quelconque de ε-transitions.

Calculs d’un afnd
On consid`re ici un afnd (Q, q0 , F, ϕ, ψ) sur un alphabet A.
            e
´                                                                     ε
Etant donn´s deux ´tats q1 et q2 et un caract`re c, on notera q1 → q2 quand q2 ∈ κ(q1 ), et on notera
              e      e                           e
    c
q1 → q2 quand il existe q1 ∈ κ(q1 ) et un ´tat q2 ∈ ϕ(q1 , c) tels que q2 ∈ κ(q2 ). C’est dire que dans les
                                            e
                                                                              e
transitions, on passera gratuitement par autant de ε-transitions qu’il est n´cessaire.
                                                                                                w
Avec ces d´finitions, on peut reprendre la mˆme d´finition que pour les afd de la notation q1 → q2 . Mais
            e                                 e     e
cette fois l’automate n’´tant plus d´terministe, il n’y a pas unicit´ de l’´tat d’arriv´e q2 .
                        e            e                              e      e           e
                                                                                                   w
Ici encore, un mot w est dit accept´ par l’automate s’il existe un ´tat final q ∈ F tel que q0 → q. Le
                                      e                                e
                                                                e
langage de l’automate est toujours l’ensemble des mots accept´s par lui.

Comparaison des afd et des afnd
     ee                        e                                                     e e
L’int´rˆt des automates non d´terministes est qu’il est beaucoup plus facile en g´n´ral de concevoir un
                                     e            e                  e
afnd qu’un afd pour un langage donn´, ce qu’on ´tudiera de plus pr`s dans le chapitre suivant. L’exemple
des mots sur {a, b} qui se terminent par ab est explicite ` cet ´gard. Autant il n’est pas ´vident que l’afd
                                                          a     e                          e
de la figure 6.1 page 59 convient, autant il est clair que l’afnd de la figure 6.4 est une solution.

                                              b

                                                     a           b
                                              1              2         3


                                              a

                             Fig. 6.4: Un afnd pour les mots qui finissent par ab

En revanche il est beaucoup moins simple de programmer le fonctionnement d’un afnd, et surtout, l’al-
gorithme obtenu est beaucoup moins efficace. C’est ce qu’on va voir maintenant.


6.4           e
          Impl´mentation en Caml d’un afnd
         c           `                                             ea e
D’une fa¸on analogue a ce qu’on a pu faire pour un afd, on est amen´ ` d´finir le type suivant pour les
e
´tats d’un afnd :
             e
        type ´tat_de_afnd =
            { mutable est_final : bool ;
                               e
               mutable table : ´tat_de_afnd list vect ;
                                       e
               mutable table_epsilon : ´tat_de_afnd list ;
                  e
               num´ro : int } ;;

            e         e `           e
On a ajout´ un num´ro a chaque ´tat, ce qui nous servira plus tard. En outre cette fois si transition il y
                e        e                         e                                          e
a sur un caract`re donn´, on fournit la liste des ´tats accessibles par cette transition. De mˆme y a-t-il
              e
une liste des ´tats accessibles par ε-transitions.
                                                                 ea
La programmation de la reconnaissance, comme nous l’avons d´j` dit, est plus difficile. Nous utiliserons
quelques fonctions auxiliaires simples qui font l’objet du programme 6.2 page ci-contre.
         ´
6.4. IMPLEMENTATION EN CAML D’UN 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) ;;

                             e
           let rec exists pr´dicat l = match l with
               | [] -> false
                               e                     e
               | t :: q -> (pr´dicat t) || (exists pr´dicat q) ;;

                   e
           let mem_´tat q ql =
                            e
               let n = q.num´ro
               in
                                          e
               exists (function x -> x.num´ro = n) ql ;;

                         e
           let rec union_´tats ql1 ql2 = match ql2 with
               | [] -> ql1
                                           e
               | q :: r -> let ql = union_´tats ql1 r
                           in
                                  e
                           if mem_´tat q ql then ql
                           else q :: ql ;;

                            e                        e
           let union_listes_´tats ll = it_list union_´tats [] ll ;;



                        e
           Nous avons ´crit les fonctions mem_´tat et union_´tats qui testent l’appartenance d’un ´tat a
                                                e              e                                        e   `
                       e                      e                       e
           une liste d’´tats et calculent la r´union de deux listes d’´tats sans utiliser la fonction de com-
                                                                                    e          e
           paraison standard de Caml (=) qui pourrait boucler sur les structures r´cursives ´ventuellement
                          e                                                            e         e
  cycliques que sont les ´tats d’un automate. C’est pour cela que nous avons utilis´ la num´rotation des
  e
  ´tats.

                                                                                e e
Notons toutefois que les fonctions it_list, list_it, exists et map sont pr´d´finies en Caml.
Pr´cisons que it_list f a [ x0 ; x1 ; ... ; xk ] s’´value en f (. . . (f (f ax0 )x1 ) . . .)xk , alors que
  e                                                        e
list_it f [ x0 ; x1 ; ... ; xk ] a s’´value en f x0 (f x1 (. . . (f xk a) . . .)).
                                          e
                     e                                          u
Maintenant, on peut ´crire la reconnaissance, qui utilise bien sˆr une fonction de calcul des fermetures
par ε-transitions.
                         e
           Nous avons ´crit pour cela une fonction de recherche d’un point fixe. pt_fixe attend deux
           arguments : une fonction f : ’a -> ’a list et une liste l : ’a list et calcule la plus petite
                                                                     ee
           liste l’ qui contient l et les images par f de chacun des ´l´ments de l’.

                                                                e         e
Cet algorithme de reconnaissance prend en argument la liste des ´tats de d´part (le plus souvent ce sera
                 ıne a
[ q0 ]) et la chaˆ ` reconnaˆ ıtre.
                             e                                                    e
Remarquons que sa complexit´ est sans commune mesure avec l’algorithme utilis´ pour les automates
 e
d´terministes.
Indiquons pour finir comment, par exemple, on entre l’automate de la figure 6.3 page 63 en Caml :
                   e
     let q1 = { num´ro = 1 ; est_final =    false ;
                table = make_vect 256 []    ; table_epsilon   = [] }
                   e
     and q2 = { num´ro = 2 ; est_final =    false ;
                table = make_vect 256 []    ; table_epsilon   = [] }
                   e
     and q3 = { num´ro = 3 ; est_final =    false ;
                table = make_vect 256 []    ; table_epsilon   = [] }
                   e
     and q4 = { num´ro = 4 ; est_final =    false ;
                table = make_vect 256 []    ; table_epsilon   = [] }
                   e
     and q5 = { num´ro = 5 ; est_final =    true ;
                table = make_vect 256 []    ; table_epsilon   = [] } ;;

     q1.table_epsilon <- [ q2 ] ;
     q2.table_epsilon <- [ q3 ] ;
66                                        ´                    ´
             CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES




                                      ıne
Programme 6.3 Reconnaissance d’une chaˆ par un afnd
              e
         type ´tat_de_afnd =
             { mutable est_final : bool ;
                                e
                mutable table : ´tat_de_afnd list vect ;
                                        e
                mutable table_epsilon : ´tat_de_afnd list ;
                   e
                num´ro : int } ;;

         let lit_transition_afnd q1 c = q1.table.(int_of_char c) ;;
             e
         let ´crit_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 =
                     e         a             e
             let rec ´tape res `_faire trait´s =
                       a
                 match `_faire with
                     | [] -> res
                                         e           e
                     | q :: r -> if mem_´tat q trait´s then
                                      e                e
                                      ´tape res r trait´s
                                 else
                                      let l = f q
                                      in
                                      ´tape (union_´tats l res)
                                      e            e
                                                   e       a
                                            (union_´tats l `_faire)
                                                       e
                                            (q :: trait´s)
             in
             e
             ´tape l l [] ;;

         let calcule_fermeture ql =
             pt_fixe (function q -> q.table_epsilon) ql ;;

                                   e        ı
         let reconnaissance_afnd ´tats 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’ =
                                        e
                          union_listes_´tats
                                (map
                                   (function q -> q.table.(c))
                                   ql)
                      in
                      avance (calcule_fermeture ql’) (i+1)
             in
                                                  e
             let ql = avance (calcule_fermeture ´tats) 0
             in
             exists (function q -> q.est_final) ql ;;
      ´
6.5. DETERMINISATION D’UN AFND                                                                          67

      ´crit_transition_afnd
      e                       q1   ‘a‘   q3   ;;
      e
      ´crit_transition_afnd   q3   ‘a‘   q4   ;;
      e
      ´crit_transition_afnd   q4   ‘a‘   q5   ;;
      e
      ´crit_transition_afnd   q1   ‘b‘   q5   ;;
      e
      ´crit_transition_afnd   q1   ‘b‘   q4   ;;
      e
      ´crit_transition_afnd   q2   ‘b‘   q3   ;;
      e
      ´crit_transition_afnd   q4   ‘b‘   q1   ;;
      e
      ´crit_transition_afnd   q5   ‘b‘   q5   ;;



6.5      e
        D´terminisation d’un afnd
        e                  e          e                                     e
On s’int´resse ici au probl`me de la d´terminisation d’un automate fini non d´terministe α. Il s’agit de
 e                            e                         ıt    e
d´terminer un automate fini d´terministe β qui reconnaˆ le mˆme langage : L(β) = L(α).

6.5.1                   e
         Algorithme de d´terminisation
Un exemple
       e                        e                                    ıt      u
Consid´rons l’automate non d´terministe α de la figure 6.5 qui reconnaˆ bien sˆr tous les mots sur
l’alphabet {a, b} qui se terminent par la chaˆ abab.
                                             ıne

                                   b

                                              a           b               a           b
                                   1               2              3              4        5


                                   a

                              Fig. 6.5: Un afnd pour les mots finissant par abab

                             `                    e                          ıt    e
Nous allons construire pas a pas un automate d´terministe β qui reconnaˆ le mˆme langage. Ce nouvel
automate aura un ensemble d’´tat ´gal ` P(Q), ensemble des parties de l’ensemble des ´tats de α.
                                e     e    a                                              e
Pour chaque partie X = {q1 , . . . , qk } de Q, on d´finira les transitions de β ` partir de X de la fa¸on
                                                    e                           a                       c
           a                       e                  `    e                                     e
suivante : ` la lecture d’un caract`re c, on aboutira a un ´tat qui est l’ensemble Y de tous les ´tats de Q
               `                              e
qu’on atteint a partir d’un quelconque des ´tats qui composent X.
Pour notre exemple, le tableau suivant fournit quelques transitions de β :
                                         e         e
                                         ´tat de d´part       a est lu    b 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 ´crit le tableau complet, il y aura 25 = 32 lignes ` ´crire. . . mais toutes ne sont pas utiles, car
       e                                                  a e
certaines parties de Q ne correspondent pas a des ´tats de β accessibles ` partir de l’´tat initial {1}.
                                              `    e                      a            e
                                          e                   e                    `
On va donc reconstituer le tableau en ´crivant les lignes n´cessaires au fur et a mesure des besoins,
      a
c’est-`-dire de leur apparition dans les deux colonnes de droites.
                                         e         e
                                         ´tat de d´part       a est lu    b 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 DETERMINISTES OU NON DETERMINISTES

                                e        e                                             e
Cette fois on n’a plus que 5 ´tats ! Les ´tats finals de β sont ceux qui contiennent un ´tat final de α, ici
il s’agit du seul ´tat {1, 3, 5}.
                  e
On peut dessiner l’automate obtenu, ce qui est fait dans la figure 6.6.

                                          b
                                                              a
                                                  1                     12
                                                              a
                                                      b             b
                                              b               13          a
                                                                    a
                                                              a
                                              135                       124
                                                              b

                                                          e        e
                                    Fig. 6.6: L’automate d´terminis´

                                       e
Effectivement, il est beaucoup moins ais´ de deviner sur cet afd le langage reconnu. . .

Explicitation de l’algorithme
Soit α = (Q, q0 , F, ϕ, ψ) un afnd sur l’alphabet A. On construit un afd β sur le mˆme alphabet qui a
                                                                                         e
pour ensemble d’´tats P(Q), pour ´tat initial l’ensemble κ(q0 ). Ses ´tats finals sont les parties de Q qui
                  e                 e                                 e
                           e
contiennent au moins un ´tat final de α.
Voici comment on construit les transitions de β : soit X = {q1 , . . . , qk } un ´tat de l’automate β et un
                                                                                 e
      e
caract`re c. Notons
                                             Y =       ϕ(qi )
                                                      1≤i≤k

l’ensemble de tous les ´tats auxquels on aboutit a partir d’un des qi par une transition de α, puis
                       e                         `

                                                  Z=         κ(y)
                                                       y∈Y

                                                    e
la fermeture par ε-transitions de Y . Alors Z est l’´tat de β auquel on aboutit depuis X par une transition
             e
sur le caract`re c.
On montre alors le

   e e                                             e
Th´or`me 6.2 (Correction de l’algorithme de d´terminisation)
            e                                    ıt    e                               e
L’automate d´terministe β ainsi construit reconnaˆ le mˆme langage que l’automate non d´terministe α.
      ´
6.5. DETERMINISATION D’UN AFND                                                                               69

         e        e
Complexit´ de la d´terminisation
 e                                                     u             e        e       e            e
H´las, la situation favorable de l’exemple ci-dessus, o` l’automate d´terminis´ a le mˆme nombre d’´tats
                e
que l’afnd de d´part, est exceptionnelle.
On dispose en effet du

   e e                     e          e
Th´or`me 6.3 (Complexit´ de la d´terminisation)
Soit n ≥ 1 un entier naturel. Il existe un afnd α ` n + 1 ´tats, tel que tout afd β qui reconnaˆ le mˆme
                                                   a       e                                   ıt    e
langage ait au moins 2n ´tats. La d´terminisation est donc un algorithme de coˆt exponentiel.
                        e           e                                         u

  4     Consid´rons, pour n fix´, l’automate non d´terministe α de la figure 6.7 sur l’alphabet A = {a, b}.
              e               e                  e
                                a

                                        a       a        a         a          a
                                0           1       2         3         ...        n
                                                b        b         b          b

                                b

                                               a     e                u
                             Fig. 6.7: Un afnd ` la d´terminisation coˆteuse

  α reconnaˆ tous les mots qui ont au moins n lettres et qui se terminent par un a suivi de (n − 1)
              ıt
        e
  caract`res a ou b.
  Montrons que si β est un afd qui reconnaˆ le mˆme langage, alors β a au moins 2n ´tats.
                                               ıt    e                                  e
                               `
  Soit q0 l’´tat initial de β. A tout mot m de n lettres dans {a, b}, on peut associer l’´tat q de β d´fini
            e                                                                            e            e
         m
  par q0 → q. On obtient ainsi une application de l’ensemble An des mots de n lettres dans l’ensemble Q
      e
  des ´tats de β.
  Nous allons montrer que cette application est injective. Alors le cardinal de Q vaudra au moins celui de
  An , qui est ´gal ` 2n , et la preuve sera termin´e.
                 e   a                             e
                                                                                  m          m
  Supposons donc qu’on ait deux mots distincts m et m de n lettres tels que q0 → q et q0 → q pour un
    e    e
  mˆme ´tat q de β.
                                      a
  Soit v le plus long suffixe commun ` m et m . Comme m = m , c’est qu’on a m = uav et m = u bv
  (ou le contraire, bien sˆr !). Notons que u et u ont la mˆme longueur (´ventuellement nulle) et que
                          u                                e             e
  v est de longueur au plus ´gale ` n − 1. Soit alors w un mot quelconque tel que vw soit de longueur
                              e     a
  exactement ´gale ` n − 1.
               e     a
  Alors mw = uavw est reconnu par les automates α et donc β, alors que m w = u bvw ne l’est pas.
          m         m               w                                                       mw
  Or q0 → q et q0 → q, donc q → qf o` qf est un ´tat final de l’automate β puisque q0 → qf et mw
                                    u           e
                                    mw
  est reconnu. Mais de mˆme q0 → qf et m w n’est pas reconnu, donc qf n’est pas un ´tat final : on a
                          e                                                        e
  trouv´ la contradiction esp´r´e. 3
        e                    ee


6.5.2     Programmation en Caml
                                      e
La structure d’ensemble de la biblioth`que standard de Caml
                              e
Le module set de la biblioth`que standard de Caml permet la gestion des parties d’un ensemble muni
d’une relation d’ordre. Voici une description des fonctions qui le composent :
                                                ee
typage le type ’a t est le type des ensembles d’´l´ments du type ’a ;
set empty renvoie l’ensemble vide, cette fonction attend en argument une fonction de comparaison,
                                                           ee             e                  e
    de type ’a -> ’a -> int qui renvoie 0 si les deux ´l´ments sont ´gaux, un entier n´gatif (resp.
    positif) si le premier est plus petit (resp. grand) que le second, pour les entiers on pourra utiliser
                                                      e                                  e          e
    set__empty (prefix -), pour les ensembles d’´tats d’un afnd (ce qui va nous int´resser ici sp´cia-
                    u                                                           u
    lement, bien sˆr), nous pourrons utiliser set__empty compare_´tats, o` compare_´tats q1 q2
                                                                       e                    e
70                                           ´                    ´
                CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES

      renvoie q1.num´ro - q2.num´ro, enfin, pour les ensembles d’ensembles, on pourra utiliser, ce qui
                     e               e
              o
      va bientˆt devenir plus clair, set__empty set__compare ;
set is empty renvoie true si et seulement si son argument est l’ensemble vide ;
set mem est le test d’appartenance : set__mem x E dit si x ∈ E ;
set add ajoute un ´l´ment ` un ensemble : set__add x E renvoie l’ensemble {x} ∪ E ;
                  ee      a
set remove r´alise l’op´ration inverse : set__remove x E renvoie l’ensemble E \ {x} ;
            e          e
           e
set union r´alise l’union de deux ensembles ;
           e
set inter r´alise l’intersection de deux ensembles ;
          e            e
set diff r´alise la diff´rence ensembliste ;
                  e     e
set equal teste l’´galit´ de deux ensembles ;
set compare prend en arguments deux ensembles et renvoie un entier qui n’est nul que si les deux
                   e          e
    ensembles sont ´gaux, et d´finit dans les autres cas une relation d’ordre sur l’ensemble des ensembles
                                            e                      e
    de ce type, cette fonction est particuli`rement utile pour cr´er le type des ensembles d’ensembles
                   e           e
    d’un type donn´ (voir la d´finition de set__empty) ;
                                  ee
set elements renvoie la liste des ´l´ments d’un ensemble ;
                       e                               ee
set iter applique une mˆme fonction successivement aux ´l´ments d’un ensemble, renvoie toujours () ;
                       ee                                                                                  u
set fold combine les ´l´ments d’un ensemble : set__fold f E a renvoie (f xn . . . (f x2 (f x1 a)) . . .), o`
                    ee
    les xi sont les ´l´ments de l’ensemble E.

           e
Quelques pr´liminaires
           c                                              e
Nous commen¸ons, dans le programme 6.4 page suivante par d´finir quelques fonctions utiles pour la
suite.
taille ensemble utilise la fonction set__fold pour calculer le cardinal d’un ensemble quelconque ;
                        e          e e                       ee                         e             e
set exists dit si le pr´dicat est v´rifi´ par au moins un des ´l´ments de l’ensemble test´ (on a utilis´ le
      e                                             e       e
     d´clenchement d’une exception en cas de succ`s pour ´viter de parcourir tout l’ensemble et sortir
     plus vite de la fonction set__iter) ;
                                                 e                              e
compare ´tats permettra la comparaison de deux ´tats par le biais de leurs num´ros, et sera la fonction
         e
           e                                       e                                   e
     utilis´e par set__empty pour nos ensembles d’´tats, ainsi que nous l’avons expliqu´ plus haut ;
              e              a                      e                                e
set of list cr´e un ensemble ` partir d’une liste d’´tats en supprimant les doublons ´ventuels au pas-
     sage ;
                                                                e                    e
fermeture agit comme calcule_fermeture mais prend un ensemble d’´tats et renvoie de mˆme un
                e
     ensemble d’´tats, au lieu de travailler sur des listes.

    e
La d´terminisation proprement dite
           e                                    ee e         e
On suit tr`s exactement l’algorithme qui a ´t´ d´velopp´ plus haut dans notre programme 6.5 page 72.
              `                       e                     e
Cependant, a cause de la circularit´ des strutures utilis´es, nous sommes contraints de construire dans
                                    e
un premier temps l’ensemble des ´tats de l’afd en gestation, puis, dans un second temps, on met a jour   `
                               e             ee
les tables de transitions des ´tats ainsi cr´´s.
                                                                    e         e
La fonction ens_transition (lignes –) attend un ensemble d’´tats de d´part de l’afnd et le code ascii
            e                              e               e
d’un caract`re, et renvoie l’ensemble des ´tats de l’afnd r´sultats de toutes les transitions correspondantes.
                                                                      e
La fonction liste_´tats_afd (lignes –) prend en argument l’´tat initial q0 de l’afnd. On commence
                     e
                  e                     e                               e         e
(ligne ) par cr´er l’ensemble e0 des ´tats de sa fermeture, qui repr´sentera l’´tat initial de l’afd final. On
   e                                         e                                    e
cr´e alors (ligne ) un ensemble eE0 form´ du seul ensemble e0 (on note syst´matiquement les ensembles
                                             c
d’ensembles par un identificateur commen¸ant par eE). On appelle alors la fonction it`re qui petit a petit
                                                                                           e             `
                                   e                       o                e
construit l’ensemble de tous les ´tats de l’afd, ou plutˆt de leurs repr´sentations en tant qu’ensembles
   e                                      a
d’´tats de l’afnd. C’est ce qu’on faisait ` la main en remplissant les colonnes de notre tableau.
                                                                                    u
La fonction cr´´_´tats_afd (lignes –) renvoie une liste de couples (e, q) o` e est un ensemble d’´tats
                ee e                                                                                       e
                 e                                   u                    ea          e
de l’afnd et q l’´tat correspondant de l’afd. Bien sˆr, comme on l’a d´j` annonc´, 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 ;;

                             e
           let set_exists pr´dicat e =
               try
                   set__iter
                       (function x
                                   e                           e
                           -> if pr´dicat x then failwith "Gagn´" else ())
                       e ;
                   false
                                 e
               with Failure "Gagn´" -> true ;;

                       e                   e           e
           let compare_´tats q1 q2 = q1.num´ro - q2.num´ro ;;

           let set_of_list ql =
                                                       e
               list_it set__add ql (set__empty compare_´tats) ;;

                             e
           let fermeture ens_´tats =
                                                                 e
               set_of_list (calcule_fermeture (set__elements ens_´tats)) ;;



                                              e                                        `
ne sont pas encore correctes : on ne peut ´crire les transitions que quand on a a sa disposition tous les
e
´tats.
                                                                       e             a
La fonction m`j_transitions (lignes –) est justement charg´e de mettre ` jour ces tables de transi-
               a
                                                                                                 e
tion. Elle utilise la fonction associe (lignes –) qui prend en argument un ensemble d’´tats de l’afnd
                               e                                  e
et la liste de couples (e, q) d´crite ci-dessus, et qui renvoie l’´tat q de l’afd correspondant.
La fonction d´terminise (lignes –) ne pose alors plus de probl`me.
               e                                                          e


6.6     Exercices pour le chapitre 6
Exercice 6.1 Quelques automates simples
Concevoir un automate sur l’alphabet {a, b} qui accepte les chaˆ    ınes ayant un nombre pair de a.
Concevoir un automate sur l’alphabet {a, b} qui accepte les chaˆ                                      e
                                                                      ınes ayant au plus deux a cons´cutifs,
      a                           ıne
c’est-`-dire qui rejette toute chaˆ contenant le mot aaa.
Concevoir un automate sur l’alphabet A = {a, b, c, . . . , z} qui accepte les chaˆ
                                                                                 ınes contenant le mot inf o.


              e
Exercice 6.2 D´terminisation d’un automate simple
                                                   e e            e
Reprendre le dernier des automates de l’exercice pr´c´dent et le d´terminiser.


                           e
Exercice 6.3 Preuve de la d´terminisation
 e           e                 e e
R´diger une d´monstration du th´or`me 6.2 page 68.


                        e
Exercice 6.4 Ajout d’un ´tat mort
       e                                                          e           e                       e
Pour ´viter les blocages d’un afd, on peut ajouter un nouvel ´tat qm dit ´tat mort : pour tout ´tat q et
                                                                                                c
tout caract`re c tel qu’il n’y ait pas de transition depuis q sur c, on ajoute la transition q → qm . En outre
            e
                                                      c
pour tout caract`re c, on ajoute la transition qm → qm . Enfin, qm ne fait pas partie des ´tats finals.
                   e                                                                           e
Il est bien clair qu’ainsi on ne change pas le langage reconnu par notre automate initial.
                           e                                 e     e
Soit α un afd et β le mˆme automate auquel on a ajout´ un ´tat mort, comme on vient de l’expliquer.
On sait que L(α) = L(β).
                                          `                                                  e
Soit α (resp. β ) l’automate obtenu a partir de α (resp. β) en rendant final tout ´tat non final et
r´ciproquement. Comparer L(α) = L(β), L(α ) et L(β ).
 e
72                                          ´                    ´
               CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES




                  e
Programme 6.5 La d´terminisation des automates
          let ens_transition e i =
              set_of_list
                  (set__fold
                      (fun q l -> (calcule_fermeture q.table.(i)) @ l)
                      e []) ; ;
       
                     e
           let liste_´tats_afd q0 =
                          e                   e
               let rec it`re eEproductifs eEd´finitifs =
                                                          e
                    if set__is_empty eEproductifs then eEd´finitifs
                  else
                  let eEnouveaux = ref (set__empty set__compare)
                  in
                  for i = 0 to 255 do
                       set__iter
                           (function e
                               -> let e’ = ens_transition e i
                                   in
                                                                               e
                                     if not (set__is_empty e’ || set__mem e’ eEd´finitifs)
                                   then eEnouveaux := set__add e’ !eEnouveaux)
                           eEproductifs
                  done ;
                    e                                          e
                    it`re !eEnouveaux (set__union !eEnouveaux eEd´finitifs)
             in
             let e0 = set_of_list (calcule_fermeture [ q0 ] )
             in
             let eE0 = set__add e0 (set__empty set__compare)
             in
                e
               it`re eE0 eE0 ; ;
      
                e e
           let cr´e_´tats_afd q0 =
                  e
               let ´tat_afd e =
                  {   est_terminal = set_exists (function q -> q.est_final) e ;
                      transitions = make_vect 256 Blocage     }
             in
                             e
               let eE = liste_´tats_afd q0
             in
             set__fold
                  (fun e l
                               e
                        -> (e , (´tat_afd e)) :: l)
                  eE [] ; ;
      
         let rec associe e l = match l with
             | [] -> raise Not_found
             | (e’,q_afd) :: r
                 -> if set__equal e e’ then q_afd
                     else associe e r ; ;
      
              a                           e
           let m`j_transitions q_afd e les_´tats =
             for i = 0 to 255 do
                 let e’ = ens_transition e i
                 in
                 if not set__is_empty e’ then
                                                                  e
                        q_afd.transitions.(i) <- OK (associe e’ les_´tats)
             done ; ;
      
              e
           let d´terminise q0 =
                     e         e e
               let les_´tats = cr´e_´tats_afd q0
             in
                                     a                      e          e
               map (function (e,q) -> m`j_transitions q e les_´tats) les_´tats ;
                                                                  e
               associe (set_of_list (calcule_fermeture [ q0 ])) les_´tats ; ;
6.6. EXERCICES POUR LE CHAPITRE 6                                                                           73

              e
Exercice 6.5 D´terminisation d’un afd !
                                                         e              a              ea e
Que se passe-t-il quand on applique notre algorithme de d´terminisation ` un automate d´j` d´terministe ?




Exercice 6.6 Minimisation d’un afd
                        e                 e               e                              e
Soit α un automate d´terministe. Pour ´viter tout probl`me, on le suppose muni d’un ´tat mort (voir
exercice 6.4).
             a                            e                                e
On cherche ` construire un automate d´terministe β qui reconnaisse le mˆme langage mais qui ait un
                    e                               e
nombre minimal d’´tats. L’algorithme que nous pr´sentons ici s’appelle l’algorithme de Hopcroft.
Pour cela, on introduit la notion d’´tats ´quivalents de α : deux ´tats q1 et q2 sont dits ´quivalents si
                                       e    e                     e                        e
                                                                                                  w
pour tout mot w, les deux calculs ` partir de q1 et q2 bloquent tous les deux, ou si, quand q1 → q et
                                      a
    w
q2 → q , q et q sont tous les deux finals ou tous les deux non-finals.
            e                                                         e      e
Il est bien ´vident qu’on peut alors tout simplement identifier deux ´tats ´quivalents sans changer le
langage reconnu.
     o                        e     e                              e                  e
Plutˆt que de chercher les ´tats ´quivalents, on se propose de d´terminer si deux ´tats ne sont pas
e                            e
´quivalents. Voici les deux r`gles que l’on appliquera :
  1. deux ´tats q1 et q2 dont l’un est final et l’autre pas ne sont pas ´quivalents ;
          e                                                            e
                        ea            e                              e                                  e
  2. si q1 et q2 sont d´j` connus non ´quivalents, si c est un caract`re de l’alphabet, et si q1 et q2 v´rifient
         c            c
     q1 → q1 et q2 → q2 , alors q1 et q2 sont non ´quivalents.
                                                   e
                              `                      e
On va donc raffiner petit a petit la relation d’´quivalence : on maintiendra une partition en classes,
         e       e      e        a                   e                 oe
initialis´e d’apr`s la r`gle (1) ` deux parties, les ´tats finals d’un cˆt´, et les autres. On applique ensuite
    e               a                                          e
la r`gle (2) jusqu’` ce que la partition ne soit plus modifi´e : on cherchera si la lecture d’un caract`re  e
de l’alphabet partage une des parties en deux sous-parties. Exemple : pour l’automate ci-dessous, sur
l’alphabet {a, b}, on obtient les partitions successives suivantes.

                                                    b


                                                    3

                                                                         b
                                    b
                                                a


                                                           b
                                        a                                       b
                            1                       2                4                    5
                                                           a
                                            a
                                                                     a

On commence par {{1, 2, 3, 4}, {5}} (r`gle 1).
                                        e
                                         e      e
La lecture d’un a ne permet pas de s´parer les ´tats du premier groupe, mais la lecture d’un b isole
  e
l’´tat 4.
On obtient donc {{1, 2, 3}, {4}, {5}}.
   e                   u             e
Mˆme chose ensuite, o` l’on isole l’´tat 2.
La partition finale est {{1, 3}, {2}, {4}, {5}}.
                a
Cela correspond ` l’automate suivant :
74                                          ´                    ´
               CHAPITRE 6. AUTOMATES FINIS DETERMINISTES OU NON DETERMINISTES

                   b                                b
                                                    b
                                 a                                     b
                       1                  2                   4                  5
                                                    a
                                      a
                                                              a
Remarque : ces automates reconnaissent les mots sur {a, b} qui se terminent par abb.
´
Ecrire une fonction de minimisation en Caml.
Chapitre 7

Langages rationnels et automates

Dans tout ce chapitre, A d´signe un ensemble fini, appel´ alphabet.
                          e                            e


7.1                                          e    e
         Langages rationnels et expressions r´guli`res
7.1.1      e
          D´finition
            e
Langages, op´rations sur les langages
´
Etant donn´ un alphabet A, on note A l’ensemble des mots sur A : il s’agit, rappelons-le, des suites
             e
        ee                                                            e                         e
finies d’´l´ments de l’alphabet. Cet ensemble de mots est muni d’une op´ration interne, la concat´nation,
qu’on note parfois par un point, mais le plus souvent par simple juxtaposition : si w1 et w2 sont deux
                                                                    e                             e
mots, on notera aussi bien w1 .w2 que w1 w2 le mot obtenu par concat´nation. Le mot vide est not´ ε.
Un langage sur l’alphabet A est une partie de A . Leur ensemble est not´ L(A) = P(A ). Notons que ∅
                                                                        e
est un langage particulier.
La concat´nation des mots fait de A un mono¨ : c’est-`-dire que la concat´nation est une loi de
           e                                     ıde        a                    e
composition interne associative.

D´finition 7.1 (Op´rations sur les langages) On d´finit sur L(A) trois op´rations fondamentales :
 e               e                              e                      e
                                                                                            a       a
l’union de deux langages L1 et L2 est tout simplement l’ensemble des mots qui appartiennent ` L1 ou ` L2 ,
     qui est bien sˆr not´ L1 ∪ L2 ;
                   u     e
le produit not´ L1 L2 de deux langages L1 et L2 est l’ensemble des mots obtenus par concat´nation d’un
              e                                                                           e
     mot de L1 et d’un mot de L2 : L1 L2 = {w1 w2 , w1 ∈ L1 , w2 ∈ L2 } ;
  e                                       e
l’´toile d’un langage L est l’ensemble not´ L                                     e
                                                       des mots obtenus par concat´nation d’un nombre fini
       e
      (´ventuellement nul) de mots de L,

                                  L = {ε} ∪ L ∪ {w1 w2 · · · wn , n ≥ 2, ∀i, wi ∈ L};

      on peut dire aussi que L est le sous-mono¨ de A engendr´ par L.
                                               ıde           e

Langages rationnels
D´finition 7.2 (Langages rationnels) L’ensemble des langages rationnels sur un alphabet A est not´ R(A).
   e                                                                                                       e
Il s’agit de la plus petite partie de L(A) qui contienne le langage vide et les singletons, et qui soit stable pour
             e           e              a                                 e
les trois op´rations list´es ci-dessus, ` savoir l’union, le produit et l’´toile.

Exemples sur l’alphabet A = {a, b} : ∅ est un langage rationnel ; A est un langage rationnel (c’est l’´toile
                                                                                                      e
d’une somme finie de singletons, puisque l’alphabet est fini) ; l’ensemble des mots qui se terminent par
ab est rationnel car il est produit des trois langages rationnels A , {a}, {b}.

                                                        75
76                                           CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES

7.1.2                    e    e
            Expressions r´guli`res
       e           e              e e                                 e
Les d´finitions tr`s formelles pr´c´dentes ne permettent pas de v´rifier rapidement qu’un langage est
                     ee     e                             a                            e
rationnel, et on pr´f`re d´crire les langages rationnels ` l’aide de formules appel´es expressions r´gu-e
  e                                  e      e                        e    e                               e
li`res : tout langage rationnel peut ˆtre d´crit par une expression r´guli`re (il n’y a pas du tout unicit´),
    e                                e    e        e
et r´ciproquement les expressions r´guli`res ne d´crivent de langages que rationnels.
      e                       e  e            e      c                e                             e
On d´finit les expressions r´guli`res de la mˆme fa¸on qu’on a pu d´finir des expressions arithm´tiques :
                                                     e                                        e
on se donnera des constantes, des variables, des op´rations et des fonctions. En outre, la s´mantique des
               e   e                                                                   e    e
expressions r´guli`res consistera en une application de l’ensemble des expressions r´guli`res sur R(A).

 e                         e    e
D´finition des expressions r´guli`res
                                                                     e                       e   e
Les informaticiens utilisent le plus souvent le mot motif pour d´crire une expression r´guli`re (pattern
en anglais). Nous allons ainsi donner ici la description des diff´rents motifs sur un alphabet A fix´.
                                                                 e                                   e
      e                                         `
Pour ´crire un motif non vide nous aurons a notre disposition des constantes (motifs constants) qui
           ee                                                                    e
seront les ´l´ments de l’alphabet et la constante ε. Nous aurons aussi des op´rateurs binaires : la somme
(encore appel´e union), que nous noterons |, et le produit (encore appel´ concat´nation), qui sera not´e
              e                                                              e        e                   e
                                                  e                 e          e       c
par simple juxtaposition. Il existera aussi un op´rateur unaire : l’´toile, not´e de fa¸on suffixe. Enfin, nous
                                                a     e
nous autoriserons l’usage de variables servant ` repr´senter des sous-motifs.
Plus formellement :

D´finition 7.3 (Expressions r´guli`res) Soit A un alphabet fini. On d´finit r´cursivement l’ensemble corre-
  e                          e    e                                e      e
spondant E(A) des expressions r´guli`res de la fa¸on suivante :
                               e e               c
     — ∅ est une expression r´guli`re ;
                             e e
                                                             e e
     — ε et toute lettre de l’alphabet sont des expressions r´guli`res, dites atomiques ;
     — si e1 et e2 sont des expressions r´guli`res, (e1 |e2 ) et (e1 e2 ) sont des expressions r´guli`res, appel´es
                                         e e                                                    e e             e
                                          e e
       somme et produit des expressions r´guli`res e1 et e2 ;
                             e e                             e e            e e           e e
  — si e est une expression r´guli`re, e est une expression r´guli`re, appel´e ´toile (ou ´toil´e) de e.
                         e                 e                                      e            e
L’usage est de ne pas ´crire les parenth`ses que rendent inutiles les priorit´s suivantes : l’´toile est
                                    e
prioritaire devant le produit, lui-mˆme prioritaire devant la somme.
Exemples d’expressions r´guli`res : ∅ ; ab |(a|c) b = (a(b ))|(((a|c) )b).
                           e   e
      e                                                                                         e
Pour ´viter de trop longs motifs, on pourra ajouter aux expressions atomiques des variables repr´sentant
des sous-motifs.
    e
On ´crira ainsi par exemple : A = a|b|c|...|z|A|B|...|Z, B = 0|1|2|3|4|5|6|7|8|9 et A(A|B) sera un motif
         e                      e                                  c
qui repr´sente les mots comps´s de lettres et de chiffres commen¸ant par une lettre.

 e
S´mantique
                           e                          e    e
Il est temps de donner la s´mantique des expressions r´guli`res :

  e               e                               e    e       e
D´finition 7.4 (S´mantique des expressions r´guli`res) On d´finit par induction structurelle une applica-
tion de E(A) sur R(A), qui d´finit la s´mantique des expressions r´guli`res en associant ` chaque expression
                              e          e                       e e                    a
 e e                                    c
r´guli`re un langage rationnel, de la fa¸on suivante :
     — le langage associ´ ` ∅ est le langage vide ;
                        ea
       a             e                    e
     — ` ε est associ´ le langage constitu´ du seul mot vide ;
     — si c est une lettre de l’alphabet, le langage associ´ est le singleton {c} ;
                                                           e
                                          e e                        e                              ea
     — si e1 et e2 sont des expressions r´guli`res de langages associ´s L1 et L2 , le langage associ´ ` l’expression
       (e1 |e2 ) est la r´union L1 ∪ L2 ;
                         e
                                      e e                         e                              ea
  — si e1 et e2 sont des expressions r´guli`res de langages associ´s L1 et L2 , le langage associ´ ` l’expression
    (e1 e2 ) est le produit L1 L2 ;
                             e e                       e                     ea                       e
  — si e est une expression r´guli`re de langage associ´ L, le langage associ´ ` l’expression e est l’´toile L
    du langage L.
          ´  `
7.2. LE THEOREME DE KLEENE                                                                                   77

  4 De par la d´finition mˆme des langages rationnels, il est clair que tous les langages associ´s aux
                  e           e                                                                       e
               e e
  expressions r´guli`res sont bien rationnels.
                     e                                                                          e
  Pour montrer la r´ciproque, on remarque tout d’abord que vide et tout singleton sont repr´sent´s par e
                   e e                                       e                     e e     e
  des expressions r´guli`res. L’ensemble des langages associ´s aux expressions r´guli`res ´tant clairement
  stable par union, produit et ´toile, on en d´duit qu’on a bien d´crit tous les langages rationnels. 3
                                e              e                  e
                           e    e             e     e
Comme les expressions r´guli`res seront repr´sent´es par des chaˆ                  e
                                                                    ınes de caract`res, les informaticiens ont
 u                                      e                                ` e
dˆ ajouter quelques notations particuli`res : ainsi le symbole . sert-il a d´signer toute lettre de l’alphabet,
                ee
c’est si l’on pr´f`re l’expression somme de toutes les expressions atomiques sauf ε. En outre, on utilise le
                                           e             e e
symbole + (en notation suffixe) pour repr´senter une r´p´tition au moins une fois d’un motif : pour tout
                 e                    e                                          e               e e
motif A, A+ d´signera AA∗. De mˆme ? (toujours en notation suffixe) repr´sentera une r´p´tition z´ro           e
                                                     e                             e
ou une fois d’un motif : pour tout motif A, A? d´signera (ε|A). Enfin, pour ´viter toute ambigu¨ e, on    ıt´
utilise un caract`re d’´chappement, \ : a repr´sente une suite quelconque de a, mais a\ repr´sente un
                  e      e                       e                                                    e
                   e e
a suivi du caract`re ´toile.

             e    e
Expressions r´guli`res en Caml
                                                           e    e
Voici le type que l’on peut utiliser pour les expressions r´guli`res non vides en Caml :
      type expr_rat =
          | Epsilon
          | Mot of string
          | ´toile of expr_rat
            E
          | Somme of expr_rat list
          | Produit of expr_rat list ;;
      e         e
Pour ´viter d’´crire abc comme Produit(Lettre ‘a‘ , Produit(Lettre ‘b‘ , Lettre ‘c‘), on a
  eee                 e                                               e
pr´f´r´ utiliser l’abr´viation Mot pour le produit d’atomes. De mˆme, on fait usage de l’associativit´   e
       e              e                                  o
des op´rateurs pour ´crire Produit [ X ; Y ; Z] plutˆt que Produit(X , Produit(Y,Z)).
L’expression r´guli`re ab(a|b)∗ba qui repr´sente les mots sur {a, b} d’au moins quatre lettres, commen¸ant
               e    e                      e                                                          c
                                         e    e
par ab et se terminant par ba, sera repr´sent´e par l’objet Caml suivant :
      Produit [ Mot "ab" ; ´toile( Somme [ Mot "a" ; Mot "b" ] ) ; Mot "ba" ] ;;
                           E
                                e            e                                  e a
Nous n’aborderons pas ici le d´licat probl`me du passage de la syntaxe concr`te ` la syntaxe abstraite
                  e    e          a           e
des expressions r´guli`res, c’est-`-dire de l’´criture d’une fonction parseur : string -> expr_rat qui
             e
serait utilis´e par exemple ainsi :
      #parseur "ab(a|b)*ba" ;;
      - : expr_rat =
        Produit [Mot "ab"; ´toile (Somme [Mot "a"; Mot "b"]); Mot "ba"]
                           E
      #



7.2          e e
        Le th´or`me de Kleene
      e                  e e                      e e                     e
Nous d´montrons ici un th´or`me fondamental, le th´or`me de Kleene, qui s’´nonce ainsi :

   e e
Th´or`me 7.1 (Kleene)
L’ensemble R(A) des langages rationnels sur un alphabet fini A est exactement ´gal ` l’ensemble des langages
                                                                             e a
reconnus par des automates finis.
78                                         CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES

      e e                      e          e
Ce th´or`me consiste en deux r´sultats diff´rents, pour lesquels nous donnerons des preuves constructives :
   1. tout langage rationnel est reconnu par un automate fini : dans la sous-section 7.2.1, nous prou-
                  e                         e                                                    e
      verons ce r´sultat en donnant une m´thode de construction d’un automate fini non d´terministe
                  ıt                          e    e                      e     e
      qui reconnaˆ un langage rationnel repr´sent´ par une expression r´guli`re fix´e ;e
                            ıt
   2. le langage que reconnaˆ un automate fini est rationnel : dans la sous-section 7.2.2 page suivante, nous
                      e                                                           e     e          e
      prouverons ce r´sultat en expliquant comment construire une expression r´guli`re qui repr´sente le
                                              e
      langage reconnu par un automate fini d´terministe fix´.  e
                                               e                      e                          e
Notons toutefois que le premier de ces deux r´sultats est le plus int´ressant, puisqu’on sait d´terminiser
                                  e
un afnd, et qu’un automate fini d´terministe permet de programmer facilement et efficacement la recon-
naissance des mots d’un langage.

7.2.1     Des langages rationnels aux automates
                                                e    e                                             e
Nous montrons ici que pour toute expression r´guli`re on peut construire un automate fini non d´termi-
                        e                         e                                                  e  e
niste ayant un unique ´tat initial et un unique ´tat final qui reconnaisse le langage rationnel repr´sent´
                  e    e         e
par l’expression r´guli`re propos´e : pour ce faire, nous raisonnerons par induction structurelle.
On laisse au lecteur la construction d’un afnd pour le langage vide. . .
                                                      e
Pour le cas des expressions atomiques, on obtient tr`s facilement les automates de la figure 7.1.
                                       ε                                       c



                                                                e    e
                      Fig. 7.1: Automates pour les expressions r´guli`res atomiques

Soit e1 et e2 deux expressions r´guli`res, et q0 , qf (resp. q0 , qf ) les ´tats initial et final de l’automate
                                  e    e                                   e
associ´ ` e1 (resp. e2 ). On construira, conform´ment ` la figure 7.2, l’automate de la somme e1 |e2 en
      e a                                         e      a
ajoutant un ´tat initial duquel on m`nera deux ε-transitions vers q0 et q0 et un ´tat final auquel arriveront
             e                       e                                              e
deux ε-transitions depuis qf et qf .

                                                 Automate pour e1



                                   ε
                                                                                   ε


                                                 Automate pour e2
                                                                                   ε
                                   ε




                                                                          e    e
                    Fig. 7.2: Automate pour la somme de deux expressions r´guli`res

                                   e    e                                  e
Soit e1 et e2 deux expressions r´guli`res, et q0 , qf (resp. q0 , qf ) les ´tats initial et final de l’automate
associ´ ` e1 (resp. e2 ). On construira, conform´ment ` la figure 7.3 page ci-contre, l’automate du produit
       ea                                        e     a
                      e                        e                                      e
e1 e2 en ajoutant un ´tat initial duquel on m`nera une ε-transition vers q0 et un ´tat final auquel arrivera
une ε-transition depuis qf ; on ajoutera enfin une ε-transition depuis qf vers q0 .
Soit e une expression r´guli`re, et q0 , qf les ´tats initial et final de l’automate associ´. On construira,
                          e    e                 e                                           e
conform´ment a la figure 7.4 page suivante, l’automate de l’´toile e en ajoutant un ´tat initial Q0 et un
         e      `                                               e                          e
´tat final Qf . De Q0 on m`nera deux ε-transitions vers q0 et Qf . De Qf on m`nera une ε-transition vers
e                            e                                                     e
Q0 , et enfin une ε-transitions ira depuis qf vers Qf .
          ´  `
7.2. LE THEOREME DE KLEENE                                                                                       79

                                  Automate pour e1                            Automate pour e2

                     ε                                           ε                                           ε




                                                                                 e    e
                         Fig. 7.3: Automate pour le produit de deux expressions r´guli`res
                                                             ε



                                                     Automate pour e

                                          ε                                        ε




                                                             ε

                                                      e                        e    e
                            Fig. 7.4: Automate pour l’´toile d’une expression r´guli`re


      u                                           e                                      ıtront dans la
Bien sˆr, les automates ainsi construits sont truff´s de ε-transitions, mais elles disparaˆ
 e
d´terminisation qu’on ne manquera pas d’effectuer.

7.2.2     Des automates aux langages rationnels
         e                                                                    e
Nous d´crirons ici l’algorithme classique, dit par suppression des ´tats, qui permet de construire une
              e    e          e                                                   e
expression r´guli`re qui repr´sente le langage reconnu par un automate d´terministe fini.
                                                    e                                 e    a a          e
Soit α un tel automate, et q1 , q2 , . . . , qk ses ´tats finals. Notons αi l’automate ´gal ` α ` ceci pr`s que seul
l’´tat qi est consid´r´ comme ´tat final. D’apr`s la d´finition des mots reconnus par α, il est bien ´vident
  e                  ee         e                     e      e                                              e
               k
que L(α) =                                                                                            e
                    L(αi ). C’est ce qui permet, dans la description de notre algorithme, de ne consid´rer
              i=1
                              e                                   e
que le cas d’automates finis d´terministes n’ayant qu’un unique ´tat initial q0 et un unique ´tat final qf .
                                                                                              e
                                   e        e      e                                               e    e
En effet, si ei est une expression r´guli`re qui d´crit le langage reconnu par αi , une expression r´guli`re
solution du probl`me pos´ est e1 |e2 | · · · |ek .
                  e       e

                                e
L’algorithme de suppression des ´tats
L’id´e est de supprimer petit ` petit tous les ´tats distincts de q0 et qf , jusqu’` n’avoir plus qu’un
     e                           a                   e                                   a
            a e                                e e                                e
automate ` 2 ´tats. Il faudra cependant g´n´raliser les transitions, et les ´tiqueter non plus avec des
                                                     e    e
lettres de l’alphabet, mais avec des expressions r´guli`res.
Supposons par exemple qu’on soit dans la situation de la figure 7.5 page suivante. On souhaite supprimer
  e                            e
l’´tat x. Pour chaque couple d’´tats e, s tel qu’il existe une transition de e entrant dans x et une transition
                             e                                          e    e        e
vers s sortant de x, on proc`de comme suit : si A est l’expression r´guli`re qui ´tiquette la transition de
                  a                                            e                                  e
e vers x, B de x ` s, C de x vers x et D de e vers s, on ´crira une transition de e vers s ´tiquet´e pare
l’expression D|AC B. On obtient alors l’automate de la figure 7.6 page suivante.
                                       e                    e
Finalement, il ne restera plus qu’un ´tat initial et un ´tat final : on se retrouve dans la situation de la
                                   e                e                               e   e
figure 7.7 page suivante. Le probl`me est alors r´solu, puisqu’une expression r´guli`re qui convient est la
80                                      CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES


                                                     C


                                                        x
                                               A            B

                                           e                    s
                                                        D

                                                                    e
                                Fig. 7.5: Avant la suppression de l’´tat x




                                           e                    s
                                                   D|AC B


                                             e                      e
                                Fig. 7.6: Apr`s la suppression de l’´tat x

suivante : A B(D|CA B) .

                                                            B

                                                            C

                                                    A           D

                                                         a e
                                      Fig. 7.7: Automate ` 2 ´tats


Un exemple
       e
Consid´rons l’exemple de l’automate de la figure 7.8 page suivante.
                       e      a e                               e
On commence par s’int´resser ` l’´tat final 3. On supprime l’´tat 2, obtenant l’automate de la figure 7.9
page ci-contre.
            e      e                            e
On aura not´ que l’´tiquette de la boucle sur l’´tat initial est devenue a|ba.
                    e
On supprime alors l’´tat 4, obtenant l’automate de la figure 7.10 page 82.
                                     e
On peut maintenant appliquer la r`gle ci-dessus, et annoncer que le langage reconnu par ce dernier
                e
automate est d´crit par le motif suivant :
                                       (a|ba) aa(b|ab|aa(a|ba) bb) .
                                                      e       a e                e                   e
Reprenons maintenant l’automate initial, en nous int´ressant ` l’´tat final 4. Apr`s suppression de l’´tat 2,
nous obtenons l’automate de la figure 7.11 page 82.
                       e
On supprime encore l’´tat 3 obtenant l’automate de la figure 7.12 page 82.
   e                   e    e           e
On ´crit l’expression r´guli`re qui repr´sente le langage reconnu :
                                    (a|ba) bbb a(bb a|a(a|ba) bb a) .
                                 e    e           e
Finalement voici une expression r´guli`re qui repr´sente le langage reconnu par l’automate initial :
                     (a|ba) aa(b|ab|aa(a|ba) bb) |(a|ba) bbb a(bb a|a(a|ba) bb a) .
          ´  `
7.2. LE THEOREME DE KLEENE                                                                                       81

                                                                           b

                                                                   b
                                                      2                    3

                                                  a       b            b       a

                                                      1            a       4


                                                      a

                        Fig. 7.8: Quel est le langage reconnu par cet automate ?

                                                                           b


                                                                           3
                                                              bb
                                                                       b       a

                                                      1            a       4


                                                   a|ba


                                                            e e
                                      Fig. 7.9: On a supprim´ l’´tat 2


                                             e    e
          Personne ne dit que l’expression r´guli`re ci-dessus est la plus simple possible. Sur notre exemple,
                                                                              e   e            e          e
          ce n’est d’ailleurs pas du tout le cas, car voici une expression r´guli`re qui repr´sente le mˆme
          langage :
                                               (a|b) bb(b|ab) (ε|a).
                                   e    e                                 e     e e
 La simplification des expressions r´guli`res n’est pas quelque chose de tr`s ais´, mˆme si les exercices qui
             a
 se trouvent ` la fin de ce chapitre peuvent donner quelques pistes d’inspiration.
82              CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES




                                              b|ab


                                               3
                                bb
                                         aa
                          1


                         a|ba


                     e                  e
       Fig. 7.10: Apr`s suppression des ´tats 2 et 4




                                               b


                                               3
                                bb
                                          b        a

                          1          a         4


                        a|ba


                                              e
     Fig. 7.11: On recommence en supprimant l’´tat 2




                                 bbb a
                          1          a         4


                         a|ba                 bb a


                     e                  e
       Fig. 7.12: Apr`s suppression des ´tats 2 et 3
7.3. LANGAGES NON RATIONNELS                                                                              83

7.3     Langages non rationnels
                                              e                                       c
Nous montrons ici que tout langage n’est pas n´cessairement rationnel. Nous commen¸ons par donner
                                   e         a
deux exemples, pour lesquels nous d´montrons ` la main qu’il ne s’agit pas de langages rationnels, puis
      e                     e e
nous d´montrons un lemme g´n´ral qui permet de discriminer une large classe de langages non rationnels.

7.3.1    Exemples
Montrons a la main que les deux langages L1 et L2 suivants sur l’alphabet {a, b} ne sont pas rationnels :
         `
  1. L1 est le langage constitu´ des mots de la forme an bn ;
                               e
  2. L2 est le langage constitu´ des mots de la forme an bp avec n ≥ p.
                               e

Le langage L1 n’est pas rationnel
Si L1 ´tait rationnel, on pourrait trouver un automate fini d´terministe α qui le reconnaisse. Soit m le
       e                                                        e
                e
nombre de ses ´tats, et q0 son ´tat initial.
                               e
                                                                                w
Soit w la chaˆ compos´e de fois le caract`re a. On d´finit l’´tat q par q0 −→ q , ce qui a bien du sens,
              ıne        e                   e           e       e
puisque l’automate est d´terministe, et qu’il ne peut pas se bloquer sur a comme il accepte la chaˆ
                          e                                                                               ıne
a b . Comme l’automate est fini, il existe deux entiers i et j tels que 0 ≤ i < j ≤ m tels que qi = qj . C’est
               a                                                                       ai+k(j−i)
dire que qj−1 → qi : on a trouv´ une boucle dans l’automate. On en d´duit que q0 −→ qi pour tout
                                 e                                     e
entier k.
                                                                  bi
Or on sait que ai bi est reconnu par l’automate. Ainsi a-t-on qi −→ qf o` qf est un ´tat final. Mais alors
                                                                        u           e
                                 ai+k(j−i) bi
on aura pour tout entier k q0     −→ qf , ce qui prouve que l’automate reconnaˆ des mots qui ne sont
                                                                              ıt
                                             e
pas dans L1 : c’est la contradiction recherch´e.

Le langage L2 n’est pas rationnel
Si L2 ´tait rationnel, on pourrait trouver un automate fini d´terministe α qui le reconnaisse. Soit m le
       e                                                        e
nombre de ses ´tats, et q0 son ´tat initial.
                e              e
                                                                                w
Soit w la chaˆ compos´e de fois le caract`re a. On d´finit l’´tat q par q0 −→ q , ce qui a bien du sens,
              ıne        e                   e           e       e
puisque l’automate est d´terministe, et qu’il ne peut pas se bloquer sur a comme il accepte la chaˆ
                          e                                                                               ıne
a b . Comme l’automate est fini, il existe deux entiers i et j tels que 0 ≤ i < j ≤ m tels que qi = qj . C’est
               a                                                                       ai+k(j−i)
dire que qj−1 → qi : on a trouv´ une boucle dans l’automate. On en d´duit que q0 −→ qi pour tout
                               e                                    e
entier k.
                                                  aj bj                                       bj
On sait que aj bj est dans L2 : c’est dire que q0 −→ qf o` qf est un ´tat final. On a donc qi −→ qf .
                                                         u           e
                         ai bj                  ai
Mais alors on a aussi q0 −→ qf , puisque q0 −→ qi . On en d´duit que l’automate accepte le mot ai bj qui
                                                            e
                          `
n’appartient pourtant pas a L2 puisque i < j : c’est la contradiction recherch´e.
                                                                              e

7.3.2                  e
         Le lemme de l’´toile
                            e
Lemme 7.1 (Lemme de l’´toile) Soit L un langage rationnel. Il existe un entier n tel que tout mot w de L
                   e     a     e                            u                                         e     a
de taille au moins ´gale ` n s’´crit sous la forme w = rst o` s est un mot non vide de taille au plus ´gale `
       u               e
n et o` le motif rs t d´crit des mots qui sont tous dans L.

  4 Soit en effet α un automate fini d´terministe reconnaissant L, et soit n le nombre de ses ´tats, q0
                                          e                                                   e
  son ´tat initial et F l’ensemble de ses ´tats finals.
      e                                   e
  Soit w un mot de L de taille sup´rieure ou ´gale ` L. Notons w les pr´fixes de w : w est compos´
                                     e           e     a                  e                          e
                                                                                            w
  des premiers caract`res de w. D´finissons alors les ´tats q de l’automate en posant q0 −→ q . Ceci
                         e           e                   e
                                       e                                            e
  a bien du sens car l’automate est d´terministe et ne peut pas se bloquer sur un pr´fixe d’un mot qu’il
  reconnaˆ ıt.
                                                     e
  Comme w a au moins autant de lettres que α d’´tats, on est certain de pouvoir trouver deux indices i
  et j tels que 0 ≤ i < j ≤ n avec qi = qj .
84                                              CHAPITRE 7. LANGAGES RATIONNELS ET AUTOMATES

                       e     e                                e                      e
     Soit alors r le pr´fixe (´ventuellement vide) de w form´ des i premiers caract`res de w ; s le mot (non
     vide) form´ des j − i caract`res suivants ; et t le suffixe (´ventuellement vide) de w form´ des caract`res
                e                e                              e                             e           e
     suivants.
                                       r     s            t
     On a bien w = rst. En outre q0 → qi → qj = qi → qf o` qf est un ´tat final.
                                                                u          e
                           rsp t
     On aura bien alors q0 −→ qf pour tout entier p, ce qui ach`ve notre d´monstration. 3
                                                               e          e

            e                      e       e e            e                            e
On aura not´ comment le lemme de l’´toile g´n´ralise les m´thodes que nous avons utilis´es pour les deux
exemples ci-dessus.


7.4        Exercices pour le chapitre 7
                                                       e
Exercice 7.1 Langages rationnels, intersection et compl´mentaire
Soit A un alphabet fini. En utilisant certains exercices du chapitre pr´c´dent, montrer que R(A) est stable
                                                                      e e
par intersection et compl´mentaire, c’est-`-dire que le compl´mentaire (dans A ) d’un langage rationnel
                         e                 a                  e
est un langage rationnel, et que l’intersection de deux langages rationnels est un langage rationnel.

             ´                            e    e
Exercice 7.2 Equivalence des expressions r´guli`res
On dira de deux expressions r´guli`res e1 et e2 qu’elles sont ´quivalentes, ce que nous noterons e1 ≡ e2
                               e    e                         e
          e            e
si elles d´crivent le mˆme langage.
                                                                  e    e
Montrer les formules suivantes, valables pour toutes expressions r´guli`res e1 et e2 :

                                              (e1 e2 )   ≡ ε|e1 (e2 e1 ) e2
                                          (e1 |e2 )      ≡ e1 (e2 e1 )
                                       ∀p ≥ 1, e1        ≡ (ε|e1 | · · · |ep )(ep+1 )
                                                                           1    1




Exercice 7.3 Le langage des facteurs des mots d’un langage
                                                         e                                       ınes de
Soit L un langage rationnel et soit L le langage constitu´ de tous les mots qui sont des sous-chaˆ
mots de L. Montrer que L est aussi rationnel.


                                  e
Exercice 7.4 Reconnaissance d’un mˆme langage
                                                                   e
Montrer que les deux afnd de la figure ci-dessous reconnaissent le mˆme langage.
                   a

                                         a                                              a       a
                          a
                   1               2                3                              1        2         3
                                          b                                             b       b

                   b                                                                b       a


Exercice 7.5 Exemples de langages non rationnels
Montrer que le langage sur {a, b} form´ des mots de la forme an ban , o` n ≥ 0, n’est pas rationnel. Mˆme
                                      e                                u                              e
question avec le langage sur le mˆme alphabet constitu´ des mots de la forme ww o` w est le miroir du
                                 e                     e                              u
             e                                a
mot w (les mˆmes lettres, mais lues de droite ` gauche).
7.4. EXERCICES POUR LE CHAPITRE 7                                                                      85

                          e    e     e                         e
Exercice 7.6 Expressions r´guli`res d´crivant des langages donn´s
´                       e    e         e
Ecrire des expressions r´guli`res qui d´crivent les langages suivants :
  1. les mots sur {a, b} contenant au moins un a ;
  2. les mots sur {a, b} contenant au plus un a ;
  3. les mots sur {a, b} tels que toute s´rie de a ait une longueur paire (bbbaabaaaa, b et aaaab convien-
                                         e
     nent, mais pas abbaa ni aaa) ;
  4. les mots sur {a, b, c} tels que deux lettres cons´cutives sont toujours distinctes.
                                                      e
             e
       Troisi`me partie

      e
Corrig´ de tous les exercices




              87
Chapitre 1

      e
Corrig´ des exercices

Exercice 1.1
               e
Voici une premi`re solution :
     let indexation arbre =
                   e      e
         let rec pr´fixe z´ro_ou_un = function
                                       e
             | Feuille(f) -> Feuille(z´ro_ou_un ^ f)
                                             e      e               e      e
             | Nœud(n,g,d) -> let g’,d’ = (pr´fixe z´ro_ou_un g),(pr´fixe z´ro_ou_un d)
                              in
                                     e
                              Nœud((z´ro_ou_un ^ n),g’,d’)
         in
         let rec indexe = function
             | Feuille(_) -> Feuille("")
             | Nœud(n,g,d) -> let g’,d’ = (indexe g),(indexe d)
                              in
                                         e                 e
                              Nœud("",(pr´fixe "0" g’),(pr´fixe "1" d’))
         in
         indexe arbre ;;
et en voici une seconde :
     let indexation arbre =
                             e
         let rec indexe a pr´fixe = match a with
                                     e
          | Feuille(_) -> Feuille(pr´fixe)
                                                 e
          | Nœud(_,g,d) -> let g’ = indexe g (pr´fixe ^ "0")
                                 e
            and d’ = indexe d (pr´fixe ^ "1")
            in
                   e
            Nœud(pr´fixe,g’,d’)
         in
         indexe arbre "" ;;



Exercice 1.2
               a
     let liste_`_profondeur arbre n =
                         a                  e a     e
         let rec ajoute_`_profondeur a k d´j`_trouv´s =
                                  e a      e
             if k = 0 then a :: d´j`_trouv´s
             else match a with
                                    e a
                  | Feuille(_) -> d´j`_trouv´se
                                          a
                  | Nœud(_,g,d) -> ajoute_`_profondeur g (k - 1)
                                                a                     e a      e
                                      (ajoute_`_profondeur d (k - 1) d´j`_trouv´s)
         in
                 a
         ajoute_`_profondeur arbre n [] ;;




                                                    89
90                                              CHAPITRE 1. EXERCICES SUR ARBRES BINAIRES

Exercice 1.3
              e
     let rec d´shabille = function
         | Feuille(_) -> Vide
                                     e              e
         | Nœud(_,g,d) -> Jointure((d´shabille g),(d´shabille d)) ;;



Exercice 1.4
   e                                  e        e                                            e
On ´crit les deux fonctions sur le mˆme mod`le. Il faudra simplement ajouter des tests suppl´mentaires
             u           e      a
pour le cas o` l’on s’int´resse ` la profondeur.
    e                                                                               e
On ´crit tout d’abord une fonction qui recombine des squelettes pour des listes fix´es de sous-arbres
                                                     e
gauches et de sous-arbres droits possibles, ce qui s’´crit ainsi :
     (* construit les squelettes dont les sous-arbres gauche et droit *)
         e
     (* d´crivent 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) ;;
    e e                                                e     e
La g´n´ration des squelettes de taille et profondeur fix´es s’´crit alors :
                       a
     let rec engendre_`_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
                       e
                  let r´sultat = ref []
                  in
                  for i = 0 to n-1 do
                                                  a
                      let liste_gauche = engendre_`_profondeur i (p-1)
                                                  a
                      and liste_droite = engendre_`_profondeur (n-i-1) (p-1)
                      in
                       e            e
                      r´sultat := !r´sultat @ (recompose liste_gauche liste_droite)
                  done ;
                    e
                  !r´sultat
             end ;;
            e            e e                                          e
On fait de mˆme pour la g´n´ration de tous les squelettes de taille fix´e :
     let rec engendre n =
         if n = 0 then [ Vide ]
         else
              begin
                       e
                  let r´sultat = ref []
                  in
                  for i = 0 to n-1 do
                      let liste_gauche = engendre i
                      and liste_droite = engendre (n-i-1)
                      in
                       e            e
                      r´sultat := !r´sultat @ (recompose liste_gauche liste_droite)
                  done ;
                    e
                  !r´sultat
             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)))
                                                       e
       else failwith "Taille incompatible avec la compl´tude du squelette" ;;



Exercice 1.6
   let est_complet a =
       let rec feuilles_au_bon_niveau k = function
           | Feuille(_) -> k = 0
           | Nœud(_,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
           e       e
   let est_´quilibr´ a =
       let rec feuilles_au_bon_niveau k = function
           | Feuille(_) -> k = 0 || k = 1
           | Nœud(_,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

      e
Corrig´ des exercices

Exercice 2.1
    a
Voil` sans doute l’exercice le plus difficile du chapitre.
 e e                                               suivante
R´fl´chissons sur l’exemple de l’arbre de la figure  :
                                                        a
                                               
                                                
                                                   
                                                    
                                                  
                                                    
                                         b                             d
                                                                  
                                          ¡
                                          ¡ e                       ¡
                                                                    ¡ e
                                        ¡     e
                                              
                                              e                  e
                                                                  ¡     e
                                    1          c                   e        6
                                                                
                                               ¡
                                               ¡ e                 ¡
                                                                   ¡ e
                                             ¡     e
                                                   e             ¡    ee
                                         2         3         4         5


Son parcours militaire est : P = abd1ce62345.
Je propose l’algorithme suivant :
                                                                          ee         ee
    1. remplacer P par son miroir (ici 54326ec1dba), qu’on va lire ´l´ment par ´l´ment par la suite ;
           e
    2. pr´parer une pile vide Π ;
             ee                                                                    a e
    3. si l’´l´ment f lu est une feuille, l’empiler dans la pile Π, et reprendre ` l’´tape 3 ;
             ee                                                                ee
    4. si l’´l´ment n lu est un nœud, retirer de la pile Π ses deux derniers ´l´ments, x et y, et empiler dans
                                                    ` e
        la pile Π l’arbre (n, x, y), puis reprendre a l’´tape 3 ;
                                            ee
    5. sinon, Π ne doit contenir qu’un ´l´ment qui est l’arbre r´sultat.e
Dans notre exemple, on commence par empiler les feuilles 5, 4, 3, 2 , 6 : la pile contient donc dans cet
                                                                                         ee             a
ordre 6; 2; 3; 4; 5. Vient alors le nœud e : on retire de la pile ses deux plus anciens ´l´ments, c’est-`-dire 4
et 5. On construit l’arbre (e, 5, 4) qu’on empile. La pile contient alors (e, 5, 4); 6; 2; 3.
                                  e
On lit alors le nœud c, on d´pile donc 2 et 3, construit l’arbre (c, 2, 3) qu’on empile. La pile contient
(c, 2, 3); (e, 5, 4); 6.
                                                                      e
On lit encore la feuille 1, qu’on empile, puis le nœud d. On d´pile (e, 5, 4) et 6, et construit (d, (e, 5, 4), 6)
qu’on empile. La pile contient ici (d, (e, 5, 4), 6); 1; (c, 2, 3).
On lit le nœud b, et construit (b, 1, (c, 2, 3)) qu’on empile.
                      a
La pile contient ` ce moment (b, 1, (c, 2, 3)); (d, (e, 5, 4), 6).
Lisant enfin le nœud a, on retrouve bien l’arbre souhait´.       e
            e
Le probl`me majeur de programmation vient de ce que Π ne se comporte pas comme une pile : en effet
               ee                                      e            e        e
ce sont les ´l´ments les plus anciens qui doivent ˆtre retir´s en priorit´ (first in, first out), au contraire
                u      ee           e           e                   e             e
d’une pile o` les ´l´ments retir´s en priorit´ sont les plus r´cemment empil´s (last in, first out).

                                                       93
94                                      CHAPITRE 2. EXERCICES SUR PARCOURS D’UN ARBRE

                                                            e           e
C’est pourquoi je propose une nouvelle structure de donn´es pour repr´senter Π : on parle de queue ou
file d’attente.
            e
Pour l’impl´menter en Caml, nous utiliserons ici tout simplement un vecteur d’arbres, dans la mesure o` u
                                                ee
nous savons qu’il y aura dans Π un nombre d’´l´ments plus petit que le nombre d’objets dans P .
                                   `
Il faudra toutefois prendre garde a travailler sur les indices du vecteur modulo la taille du tableau, et
                             ee                 e
garder toujours l’indice des ´l´ments les plus r´cent et ancien.
On obtient cette gestion d’une queue.

     type ’a queue =
         { empile : (’a -> unit) ;
            e
           d´pile : (unit -> ’a) ;
           est_vide : (unit -> bool) } ;;

     exception Queue_Vide ;;
     exception Queue_Pleine ;;

            e
     let cr´e_queue taille initialisateur =
         let n = taille + 1
         in
         let v = make_vect n initialisateur
                e
         and d´but = ref 0
         and fin = ref 0
         in
         { est_vide =
                                 e
               (function () -> !d´but = !fin) ;
            empile =
                                                e
               (function x -> if (!fin + n - !d´but) mod n = taille
                               then raise Queue_Pleine
                               else         e
                                       v.(!d´but) <- x ;
                                        e          e
                                       d´but := (!d´but + taille) mod n ) ;
             e
            d´pile =
                                    e
               (function () -> if !d´but = !fin then raise Queue_Vide
                               else    let x= v.(!fin)
                                       in
                                       fin := (!fin + taille) mod n ;
                                       x ) } ;;


                            e          a                              `
On l’applique comme expliqu´ ci-dessus ` la reconstitution d’un arbre a partir de son parcours militaire,
et on obtient le programme ci-dessous.

     let recompose_militaire l feuille_bidon =
         let p = rev l
                   e
         and q = cr´e_queue (list_length l) (Feuille feuille_bidon)
         in
         let rec avance = function
                                 e
             | [] -> let a = q.d´pile ()
                      in
                      if q.est_vide () then a
                      else failwith "Parcours militaire incorrect"
             | (F f) :: suite
                 -> q.empile (Feuille f) ; avance suite
             | (N n) :: suite
                                 e
                 -> let y = q.d´pile ()
                      in
                                 e
                      let x = q.d´pile ()
                      in
                      q.empile (Nœud(n,x,y)) ; avance suite
         in
         try avance p
         with _ -> failwith "Parcours militaire incorrect" ;;


            e
Le param`tre feuille bidon ne sert qu’au typage de Caml qui doit initialiser ses tableaux avec quelque
                                      o           e
chose. . . C’est d’ailleurs aussi le rˆle du param`tre initialisateur de cr´e queue.
                                                                           e
                                                                                                                            95

Exercice 2.2
                                      e      e                        e
Les deux conversions sont a priori tr`s diff´rentes. La conversion pr´fixe vers suffixe est certainement la
                                 `                e                     e
plus simple, puisqu’il n’y a pas a revenir en arri`re, quand on a trouv´ un nœud, pour trouver ses fils.
                 e     e
Pour l’arbre repr´sent´ dans la figure suivante, on va construire ce tableau :

          lu   a b       1    c       2          3  d    e    4         5        f        g            6       7     8
     pile A    v vv     vf   vf v    vf f        f f v f vv f vf       ff       ffv    f f vv       f f vf   fff
       e
       ´crit             1            2         3cb           4        5e                              6      7g    8f da
     pile B    a   ba   ba    cba    cba         a da eda eda          da       f da   gf da        gf da    f da
                                                    
                                                     a
                                            rr
                                          ¨
                                         ¨¨    r
                                       ¨        rr
                              ¨    ¨             r 
                                   ¨               r
                                 b                   d
                                                   
                               ¡ e
                               ¡                      d
                                                        d 
                             ¡     e
                                   
                                   e                   d
                         1           c                         e                        f
                                                                               
                                     ¡
                                     ¡ e                       ¡
                                                               ¡ e                 ¡
                                                                                   ¡ e
                                   ¡     e
                                         e                   ¡     e
                                                                   e            e
                                                                                 ¡     e
                               2            3            4         5              g             8
                                                                                 
                                                                                  ¡
                                                                                  ¡ e
                                                                                ¡     e
                                                                                      e
                                                                            6           7


                                                 e                     e
La pile A est une pile de v/f (qu’on pourra repr´senter par des bool´ens), la pile B est une pile de nœuds.
                          e                                                    `
Elles sont toujours de mˆme taille, et d’ailleurs la pile A contient v(oid) a chaque fois qu’aucun fils n’a
ee         ee
´t´ compl´t´ pour le nœud correspondant de la pile B, et f(ull) quand le fils gauche est plein.
    e                                                                             e
La r`gle de formation est alors simple : tout nœud nouvellement lu est empil´ dans la pile B, alors qu’on
                              `                               e           o
empile un v dans la pile A ; a la lecture d’une feuille, on l’´crit aussitˆt, et, si le sommet de la pile A est
                                                                    e                                      e
un v, on le remplace par un f , alors que s’il s’agit d’un f , on d´pile tous les f de la pile A, et en mˆme
                                                      e         e
temps les nœuds correspondants de la pile B qu’on ´crit, apr`s quoi on transforme le v qui est au sommet
                        a
de la pile A par un f , ` moins qu’il n’y en ait plus, mais c’est qu’on a termin´.  e
Ceci correspond au programme suivant :
                       e
      let suffixe_de_pr´fixe 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
                                                      e
                      | [] -> failwith "Description pr´fixe 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 []
                                                      e
                         else failwith "Description pr´fixe incorrecte"
                                             e
              | _ -> failwith "Description pr´fixe incorrecte"
          in
          avance [] [] l ;;
                                                                        e                               `
Pour ce qui est de la transformation inverse, le plus simple est — de tr`s loin — de construire l’arbre a
l’aide de recompose suffixe puis de le parcourir en ordre pr´fixe. . .
                                                              e
Chapitre 3

      e
Corrig´ des exercices

Exercice 3.1
          e            e
La seule r´elle difficult´ est dans la suppression de la racine d’un arbre binaire qui a deux fils non vides.
                                       a                       ee                          a        ee
Je propose dans ce cas de substituer ` la racine le plus petit ´l´ment du fils droit, c’est-`-dire l’´l´ment
                 `
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 "´l´ment absent"
                             E e
         | Nœud(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 -> Nœud(x,Vide,Vide)
         | Nœud(a,g,d)
             -> if a = x then arbre
                 else if phi(x) < phi(a)
                     then Nœud(a,(ajout phi g x),d)
                     else Nœud(a,g,(ajout phi d x)) ;;

     let rec supprime phi arbre x =
         let rec cherche_min = function
             | Vide -> failwith "Erreur de programmation"
             | Nœud(a,Vide,d) -> a,d
             | Nœud(a,g,d) -> let mini,g’ = cherche_min g
                               in
                               mini,Nœud(a,g’,d)
         in
             e e
         let ´t^te = function
             | Vide -> Vide
             | Nœud(_,Vide,Vide) -> Vide
             | Nœud(_,Vide,d) -> d
             | Nœud(_,g,Vide) -> g
             | Nœud(_,g,d) -> let min_droit,d’ = cherche_min d
                               in
                               Nœud(min_droit,g,d’)
         in
         match arbre with
             | Vide -> Vide
             | Nœud(a,g,d)
                                    e e
                 -> if a = x then ´t^te arbre
                     else if phi(x) < phi(a)
                              then Nœud(a,(supprime phi g x),d)
                              else Nœud(a,g,(supprime phi d x)) ;;



Exercice 3.2
                e
     let mesure_´quilibrage arbre =


                                                    97
98                                     CHAPITRE 3. EXERCICES SUR ARBRES DE RECHERCHE

         let rec mesure_profondeur = function
             | Vide -> Vide
             | Nœud(a,g,d)
                 -> match (mesure_profondeur g),(mesure_profondeur d) with
                     | Vide,Vide -> Nœud((a,0,0),Vide,Vide)
                     | Vide,(Nœud((_,kgd,kdd),gd,dd) as d)
                         -> Nœud((a,0,max kgd kdd + 1),Vide,d)
                     | (Nœud((_,kgg,kdg),gg,dg) as g),Vide
                         -> Nœud((a,max kgg kdg + 1,0),g,Vide)
                     | (Nœud((_,kgg,kdg),gg,dg) as g),
                             (Nœud((_,kgd,kdd),gd,dd) as d)
                         -> Nœud((a,max kgg kdg + 1,max kgd kdd + 1),g,d)
         in
         let rec mesure = function
             | Vide -> Vide
             | Nœud((a,kg,kd),g,d)
                 -> Nœud((a,kg-kd),(mesure g),(mesure d))
         in
         mesure (mesure_profondeur arbre) ;;




Exercice 3.3
On dispose toujours de l’in´galit´ k ≥ lg n , qui est valable pour tous les arbres. Les arbres complets
                              e    e
 e          e     e
r´alisent l’´galit´, et comme ils sont clairement AVL, cela prouve que cette borne est atteinte.
                    ` e                                                                          e
On cherche donc a d´terminer maintenant les arbres AVL les plus profonds possible pour un n fix´, c’est-
a                         e e      e `           e      e
`-dire encore les plus d´s´quilibr´s. A une sym´trie pr`s, il s’agit des arbres dont chaque nœud interne
        a
penche ` gauche.
Voici les arbres correspondants, pour les profondeurs 1, 2, 3 et 4.
                                                                          
                                                                   
                            ¡
                            ¡     ¡
                                  ¡ e                                   d
                                                                          d 
                         
                          ¡    e
                                ¡     
                                      e                           
                                                                           d
                                                 
                                        ¡
                                        ¡       ¡
                                                ¡ e      ¡
                                                         ¡
                                     
                                      ¡      e
                                              ¡     
                                                    e  ¡
                                                          
                                                            ¡
                                                            ¡
                                                         
                                                          ¡
                                                         

                                                          5 
                                                             ™
                                                          5    ™
                                                      5        ™ 
                                                       5         ™
                                                         
                                                  d        ¡
                                                           ¡ e
                                                    d e
                                             
                                                     d   ¡     
                                                               e
                                                  
                                           ¡
                                           ¡ e      ¡
                                                    ¡   ¡
                                                        ¡
                                        e
                                         ¡     
                                               e  ¡   ¡
                                      
                                      ¡
                                      ¡
                                   
                                    ¡
                                   
                                                                                                         99

                                                                               c                  e
Notons Fk l’arbre de profondeur k ainsi construit. Fk+2 se construit de la fa¸on suivante : on cr´e un
nouveau nœud, on lui accroche comme fils gauche Fk+1 et Fk comme fils droit.
                      e
Ces arbres sont appel´s arbres de Fibonacci. Si nk est la taille de Fk , on obtient aussitˆt nk+2 = 1 +
                                                                                          o
nk+1 + nk , avec comme conditions initiales n1 = 2 et n2 = 4 (on peut aussi poser n0 = 1). Les (1 + nk )
                       √
constituent donc la suite de Fibonacci. .√
                                         .
                      2 5              2 5
On a donc nk = 1 +          ϕk + 1 −         (−1/ϕ)k − 1, ce qui fournit notre majoration asymptotique :
                        5                5

                                          k ≤ 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 fils deux valeurs pour discriminer ces fils. On trouvera dans
la figure suivante un exemple d’arbre 2–3 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
         | Nœud2 of ’n * arbre23 * arbre23
         | Nœud3 of ’n * ’n * arbre23 * arbre23 * arbre23 ;;
100                                     CHAPITRE 3. EXERCICES SUR ARBRES DE RECHERCHE

                           e
La fonction de recherche s’´crit simplement :
      let rec recherche phi arbre x = match arbre with
          | Feuille(f) -> x = f
          | Nœud2(a,g,d) -> recherche phi (if phi x > a then d else g) x
          | Nœud3(a,b,g,m,d)
              -> recherche phi
                      (if phi x > b then d
                       else if phi x > a then m
                       else g) x ;;
                                         e                                         a
Soit a un arbre 2–3 de profondeur k poss´dant n feuilles. Si tous ses nœuds sont ` 2 fils, on sait que
n = 2k . De mˆme si tous ses nœuds ont 3 fils, on aura n = 3k . En g´n´ral on a donc
             e                                                     e e

                                      0,63 lg n ≈ log3 n ≤ k ≤ lg n.
Chapitre 5

      e
Corrig´ des exercices

Exercice 5.1
                                           e
     let recompose_suffixe_naire liste arit´ =
                  e
         let rec d´pile k liste =
             if k = 0 then [],liste
             else match liste with
                 | t :: q
                                       e
                     -> let q1,q2 = d´pile (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
                                  e
                 -> let k = arit´ n
                     in
                                     e
                     let fils,a = d´pile k a
                     in
                     recompose (Nœud(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 =
                    e
         let parenth`se 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 N -AIRES

                              | Cos -> "cos"
                              | Exp -> "exp"
                              | Ln -> "ln") ;
                     e
              parenth`se u
      | Terme(u,‘^‘,v)
          -> if est_atome u then imprime_expression u
                           e
              else parenth`se u ;
              print_char ‘^‘ ;
              if est_atome v then imprime_expression v
                           e
              else parenth`se v
      | Terme(u,‘/‘,v)
          -> ( match u with
                                             e
                  | Terme(_,‘+‘,_) -> parenth`se u
                                             e
                  | Terme(_,‘-‘,_) -> parenth`se 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
                                e
                  | _ -> parenth`se v )
      | Terme(u,‘*‘,v)
          -> ( match u with
                                             e
                  | Terme(_,‘+‘,_) -> parenth`se u
                                             e
                  | Terme(_,‘-‘,_) -> parenth`se u
                  | _ -> imprime_expression u ) ;
              print_char ‘*‘ ;
              ( match v with
                                             e
                  | Terme(_,‘+‘,_) -> parenth`se v
                                             e
                  | Terme(_,‘-‘,_) -> parenth`se 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
                                             e
                  | Terme(_,‘-‘,_) -> parenth`se v
                  | _ -> imprime_expression v ;;
Chapitre 6

      e
Corrig´ des exercices

Exercice 6.1
                      e              e                                         e
On trouve sans difficult´ un automate d´terministe pour le premier langage propos´ :
                                                          b                                 b

                                                                        a
                                                          1                                 2
                                                                        a
    e
De mˆme, pour le second :

                                         b                                                                      a

                                        a                          a                            a
                            1                      2                            3                       4

                                                   b
                       b                                                                                        b
              e                                                   e
Pour le troisi`me, il est plus simple de fournir un automate non d´terministe :
                                         i                    n                     f                   o
                                1                 2                     3                       4                   5




Exercice 6.2
                    e              a              a                    e
On peut tenter une d´terminisation ` la main. Voil` ce qui fut ma premi`re tentative :
                                                      A \ {o}




                                        A \ {n}
                                                                  n                     f                   o
                                    1                 2                     3                       4                   5
                                             i
                  A \ {i}
                                                 A \ {f }                                                           A


                                                                  103
104                                              CHAPITRE 6. EXERCICES SUR AUTOMATES FINIS

Une ´tiquette comma A \ {o} sur une transition signifie qu’elle a lieu sur tout caract`re de l’alphabet
     e                                                                                 e
sauf o.
                  e
Un petit peu de r´flexion montre que cet automate est incorrect. . . On peut par exemple tester cet
                    ıne
automate sur la chaˆ iinf o pour s’en convaincre.
                                       e                  e
En fait, il vaut mieux se fier aux m´thodes du cours (´videmment !), et appliquer l’algorithme de
 e                              e                                  e                         e
d´terminisation. On obtient, apr`s simplification (regroupement des ´tats finals), l’automate d´terministe
suivant :
                                i
                                                     n
                                                      i
                                     2                                    3
                                                 fo
                                                               no
                                             i
                                                      1

                                                               f no
                                         i                fn          f



                                                      4



                                                          o



                                                      5




              e
Cette fois, l’´tiquette                                                            e
                          sur une transition signifie qu’elle a lieu sur tout caract`re qui n’est pas dans
{i, n, f, o}.


Exercice 6.3
                                                                              c,α
Soit α l’afnd propos´, et β l’afd que construit l’algorithme. On notera q1 −→ q2 les transitions de α et
                     e
    c,β
Q1 −→ Q2 celles de β.
                                       e                  e                                    e
La preuve de l’algorithme est alors ais´e : pour chaque ´tat Q de β il suffit de montrer par r´currence
                                                      w,β                              w,α
par r´currence sur la longueur d’un mot w que si Q −→ Q alors Q = {q / ∃q ∈ Q, q −→ q }.
     e
     e                                                    e         e                            e
La d´monstration est claire pour w = ε, puisqu’on a ferm´ tous les ´tats de β. La construction mˆme des
e                                                           e
´tats de β permet de conclure quand w = vc : il suffit de d´couper w en chaˆ        e             e
                                                                            ıne-pr´fixe et caract`re final.
                                   e
On conclut en prenant Q = κ(q0 ), ´tat initial de β : un mot w sera reconnu par β si et seulement si il est
reconnu par α.


Exercice 6.4
                              e
L(β ) est simplement le compl´mentaire (dans l’ensemble de tous les mots sur l’alphabet qu’on s’est fix´)e
de L(α) = L(β).
              a                       e                                                    e
En revanche, ` cause de l’absence d’´tat mort dans α, il faut tenir compte des possibilit´s de blocage de
la reconnaissance. Ainsi L(α ) est-il la partie de L(β ) consistant en tous les mots qui ne provoquent pas
                                                                                                         105

                                                                                             w
de blocage de α et qui ne sont pas accept´s par α. Bref il s’agit des mots w tels que q0 → q avec q non
                                         e
final dans α.


Exercice 6.5
                 u       e                     e       e                          `                `
On obtient bien sˆr le mˆme automate, chaque ´tat de l’´tat initial correspondant a son singleton, a ceci
  e               e    e                         a                      e
pr`s qu’on a ajout´ un ´tat mort (qui correspond ` un ensemble vide d’´tats de l’automate initial).


Exercice 6.6
                                      e
Nous utiliserons ici une nouvelle repr´sentation des afd.
                       e    e                   e          e    e
Un automate sera repr´sent´ par un vecteur d’´tats, chaque ´tat ´tant un objet Caml du type suivant :
          e
     type ´tat_afd_vectoriel == bool * (int vect) ;;

         e           e                                  e                                        e
Le bool´en dit si l’´tat est terminal, et le vecteur d´crit les transitions sur les 256 caract`res : une
                   e    e             e       e     e
transition est repr´sent´e par le num´ro de l’´tat r´sultat.
                                e             e     e
La partition de l’ensemble des ´tats sera repr´sent´e par un vecteur de listes d’entiers : chacune contient
        e        e                       ee
les num´ros des ´tats de la partie consid´r´e de la partition.
                                  e
La fonction suivante partage les ´tats de l’automate en finals et non-finals.
     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) ;;
                                      e
Elle prend en argument le vecteur des ´tats, i qui doit valoir 0 pour tout balayer, et la taille du vecteur.
Elle renvoie un couple de listes.
                                   e                                               e
La fonction suivante renvoie le num´ro du paquet de la partition qui contient un ´tat donn´.  e
                    e
     exception Trouv´ of int ;;

             e
     let num´ro_partie q partition =
         let n = vect_length partition
         in
         try
               for i = 0 to n - 1 do
                                                           e
                   if mem q partition.(i) then raise (Trouv´(i))
               done ;
               n
                      e
         with Trouv´(i) -> i ;;
                                           e
Voici maintenant une fonction plus compliqu´e :
          e
     let r´partit 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
                  e
         let rec r´p l res =
             match l with
                 | [] -> map snd res
                                      e
                 | (q,dest) :: r -> r´p r (ajoute (q,dest) res)
         in
          e
         r´p l [] ;;
                                                                          ee             e
Elle prend en argument une liste de couples (q,dest) dont le premier ´l´ment est un ´tat de l’automate
               e
et le second l’´tat auquel une transition le conduit. Elle renvoie une liste de couples (dest,liste) dont
           ee              e                                       ee             e
le premier ´l´ment est un ´tat-cible et le second est la liste des ´l´ments q de d´part dans la liste fournie
en argument.
                           e
On est alors en mesure d’´crire le cœur de l’algorithme.
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 `Suivre else ()
                                      A
          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,
                                            e
                                        (num´ro_partie (snd qv.(q)).(c) partition))
                                    partition.(i)
                            in
                                        e
                            partage i (r´partit l) ;
                       done
                  done
              with `Suivre -> encore := true
                   A
          done ;
          ( partition,!taille_partition ) ;;
                                         ee                                e
La fonction partage prend la liste cr´´e par la fonction r´partit d´crite ci-dessus, et modifie en
                                                                e
    e                                                `
cons´quence la partition. Il n’y 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
                                                           e
                                               v.(c) <- num´ro_partie (snd x).(c) partition
                                          done
          done ;
          mini ;;
Chapitre 7

      e
Corrig´ des exercices

Exercice 7.1
       ea e         `                           e
On a d´j` r´pondu a la question pour le compl´mentaire dans l’exercice 6.4 : on a su construire un afd qui
         ıt        e
reconnaˆ le compl´mentaire du langage d’un afd fix´.    e
                                                                                                e
On sait que l’union de deux langages rationnels est un langage rationnel, passant aux compl´mentaires,
        e        e                            e                  e
on en d´duit le r´sultat sur l’intersection (mˆme s’il n’est pas ´vident de construire l’automate de l’inter-
section. . . )


Exercice 7.2
          a                          e     e                                                        e
Il s’agit ` chaque fois de prouver l’´galit´ de deux ensembles, donc deux inclusions. On pourra proc´der
par r´currence sur la taille des mots. On montre de fa¸on analogue : (e1 |e2 ) ≡ (e2 e1 ) e2 .
      e                                                 c


Exercice 7.3
                   e                     e                    ıt                        e
Il suffit de consid´rer un automate fini d´terministe qui reconnaˆ le langage, et de consid´rer tous les
e     a
´tats ` la fois comme initiaux et finals.


Exercice 7.4
                                  e                  e           e
Les deux automates ayant la mˆme transition de l’´tat 2 vers l’´tat 3, on peut se contenter de montrer
  e                            e                     e                             e
l’´quivalence des automates d´duits de ceux propos´s par suppression du dernier ´tat.
    e                       e   e                    `
On ´crit les expressions r´guli`res correspondantes a ces automates. On trouve facilement (a|b) a pour
                      a
le premier : ce sont l` les mots qui se terminent par un a. Pour le second, on trouve une expression plus
          e
compliqu´e :
                                               b a(a|bb a) .
                  e          e                           e
En utilisant les r`gles expos´es dans l’exercice 7.2, on ´crit successivement :


                               b a(a|bb a)     ≡ b a|b a(a|bb a) (a|bb a)
                                               ≡ b (ε|a(a|bb a) (ε|bb ))a
                                               ≡ b (ε|a(a|bb a) b )a
                                               ≡ b (ε|a((ε|bb )a) b )a
                                               ≡ b (ε|a(b a) b )a
                                               ≡   b (ε|a(a|b) )a



                                                    107
108                    CHAPITRE 7. EXERCICES SUR LANGAGES RATIONNELS ET AUTOMATES

On conclut en remarquant que :

                                         (a|b) a   ≡ b (ab ) a
                                                   ≡ b (ε|ab (ab ) )a
                                                   ≡ b (ε|a(a|b) )a




Exercice 7.5
Utilisons le lemme de l’´toile : il existe un entier m qui v´rifie les propri´t´s du lemme. Soit n > m, an ban
                        e                                   e               ee
                    e                          u                            e     a      u
est reconnu, donc s’´crit sous la forme rst o` s est de longueur au plus ´gale ` m et o` les mots rs t sont
reconnus. Si s contient un b, on trouverait des mots du langage avec plusieurs b. Sinon, r = ak , s = ap ,
et t = an−k−p ban . Mais alors rsst = an+p ban serait dans le langage.
               e                  e                                e                         ıt
Pour le deuxi`me langage, proc´dons ainsi : soit m le nombre d’´tats d’un afd qui reconnaˆ notre langage,
                                                                  (ab)i
et soit q0 son ´tat initial. Appelons qi l’´tat d´fini par q0 −→ qi (pas de probl`me car (ab)i (ba)i est bien
               e                           e     e                              e
                                                                                                     (ab)i+k(j−i)
reconnu). N´cessairement, on peut trouver 0 ≤ i < j ≤ m tels que qi = qj . Alors q0
           e                                                                                              −→        qi = q j
                                                                                                  (ba)i
pour tout entier k. Alors tous les mots (ab)      (ba) sont reconnus, puisque qi −→ qf avec qf final.
                                               i+k(j−i)       i

Ces mots n’´tant pas de la forme requise pour k ≥ 1, notre langage n’est pas rationnel.
           e


Exercice 7.6
Pour   le   premier langage : (a|b) a(a|b) .
Pour   le         e
            deuxi`me : b (a|ε)b .
Pour   le         e
            troisi`me : (b|aa) .
Pour   le          e
            quatri`me, on peut commencer par construire l’automate correspondant :

                                                                                      2



                                                          a                   b
                                                                                  a


                                                   b
                                     1                               3                    c   a



                                                                                  c
                                                          c
                                                                          b


                                                                                      4

                        e                                         e    e         e
On utilisera alors la m´thode du cours pour obtenir l’expression r´guli`re cherch´e. Mais il est tout aussi
                      a
simple de tout faire ` la main.
Appelons A le motif qui d´crit tous les mots de notre langages qui ne contiennent pas de a. Il est facile
                           e
a
` expliciter :
                                          A = (ε|c)(bc) (ε|b).
                                                                                                    109

                             e                      e    e                          e
Il n’est alors pas difficile d’´crire une expression r´guli`re solution de notre probl`me :

                                             (ε|A)(aA) (ε|a).

On aura not´ qu’il s’agit de la mˆme expression ` substitution pr`s de c en A et de b en a : on pourrait
             e                   e                a                 e
       e e                            e                          e e
ainsi g´n´raliser au langage des mots ´crits sur n lettres sans r´p´tition.

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:55
posted:2/25/2012
language:French
pages:109