Vous êtes sur la page 1sur 304

Algorithmique

Michel Quercia
Ancien lve de lEcole Normale Suprieure ee e Professeur en classes prparatoires au lyce Champollion de Grenoble e e

Corrections
La version ( livre ) diuse par Vuibert comporte quelques erreurs, dcouvertes e e ( ) aprs impression, et qui sont corriges dans cette version lectronique. e e e

p. 62 : inversion des seconds membres dans les formules de distributivit. e p. 154 (automate produit) : A et B sont supposs complets. e p. 248 (exercice 10-5) : correction de lexpression rgulire pour L. e e

Table des mati`res e


Prface e .............................................................. 6

Cours et exercices
Chapitre 1-1 1-2 1-3 1-4 1-5 Chapitre 2-1 2-2 2-3 2-4 2-5 2-6 Chapitre 3-1 3-2 3-3 3-4 3-5 3-6 3-7 3-8 Chapitre 4-1 4-2 4-3 4-4 Chapitre 5-1 5-2 5-3 5-4 5-5 1 Mthodes de programmation . . . . . . . . . . . . . . . . . . . . . . . e Description dun algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Itration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Rcursivit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e Diviser pour rgner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Structure de liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dnitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Reprsentation en mmoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e Parcours dune liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recherche dun lment dans une liste . . . . . . . . . . . . . . . . . . . . . ee Insertion et suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Listes tries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Insertion dans une liste trie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Recherche dans une liste trie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Fusion de listes tries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Tri dune liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tri a bulles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tri par fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tri rapide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Evaluation dune formule . . . . . . . . . . . . . . . . . . . . . . . . . . . Structure de pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Reprsentation linaire dune formule . . . . . . . . . . . . . . . . . . . . . e e Evaluation dune formule postxe . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Logique boolenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Propositions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Circuits logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Synthse des fonctions boolennes . . . . . . . . . . . . . . . . . . . . . . . . . e e Manipulation des formules logiques . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 9 11 14 17 20 24 24 25 27 28 29 32 34 34 35 37 39 41 42 46 50 53 53 55 56 58 60 60 63 65 69 73

Chapitre 6-1 6-2 6-3 6-4 Chapitre 7-1 7-2 7-3 7-4 7-5 Chapitre 8-1 8-2 8-3 8-4 Chapitre 9-1 9-2 9-3 9-4 9-5 Chapitre 10-1 10-2 10-3 10-4 Chapitre 11-1 11-2 11-3 11-4 11-5 11-6 11-7

6 Complexit des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . e Gnralits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e e Equation de rcurrence T (n) = aT (n 1) + f(n) . . . . . . . . . . . e Rcurrence diviser pour rgner . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dnitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Reprsentation en mmoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e Parcours dun arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dnombrements sur les arbres binaires . . . . . . . . . . . . . . . . . . . . e Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76 76 79 82 84 87 87 90 94 99 104

8 Arbres binaires de recherche . . . . . . . . . . . . . . . . . . . . . . . 109 Recherche dans un arbre binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 9 Manipulation dexpressions formelles . . . . . . . . . . . . . . 115 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Reprsentation des formules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 e Drivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 e Simplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 10 Langages rguliers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 e Dnitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 e Oprations sur les langages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 e Appartenance dun mot a un langage rgulier . . . . . . . . . . . . . 135 e Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 11 Automates nis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Dnitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 e Simulation dun automate ni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Dterminisation dun automate . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 e Le thorme de Kleene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 e e Stabilit et algorithmes de dcision . . . . . . . . . . . . . . . . . . . . . . . . 151 e e Langages non rguliers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 e Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

Probl`mes e
Tri par distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interpolation de Lagrange et multiplication rapide . . . . . . . . . . . . . . . . . . . . Plus longue sous-squence commune e ................................... Arbres de priorit quilibrs ee e ........................................... Compilation dune expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recherche dune cha^ de caractres dans un texte . . . . . . . . . . . . . . . . . . . . . ne e 158 159 161 163 166 167

Travaux pratiques
Chemins dans Z2 ...................................................... Files dattente et suite de Hamming ................................... Recherche de contradictions par la mthode des consensus . . . . . . . . . . . . . . e Modlisation dun tableur e ............................................. Analyse syntaxique .................................................... 171 174 176 182 184

Solutions des exercices


Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre Chapitre 1 2 3 4 5 6 7 8 9 10 11 Mthodes de programmation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Structure de liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listes tries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Evaluation dune formule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Logique boolenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Complexit des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arbres binaires de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Manipulation dexpressions formelles . . . . . . . . . . . . . . . . . . . . . Langages rguliers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Automates nis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 199 205 213 216 227 230 238 240 247 250

Solutions des probl`mes e


Tri par distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interpolation de Lagrange et multiplication rapide . . . . . . . . . . . . . . . . . . . . Plus longue sous-squence commune e ................................... Arbres de priorit quilibrs ee e ........................................... Compilation dune expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recherche dune cha^ de caractres dans un texte . . . . . . . . . . . . . . . . . . . . . ne e 260 261 266 272 274 276

Solutions des travaux pratiques


Chemins dans Z2 ...................................................... Files dattente et suite de Hamming ................................... Recherche de contradictions par la mthode des consensus . . . . . . . . . . . . . . e Modlisation dun tableur e ............................................. Analyse syntaxique .................................................... 282 283 287 289 290

Annexes
Bibliographie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Aide mmoire de caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 296 300

Prface e

Cet ouvrage prsente un cours dalgorithmique dispens successivement au e e lyce Carnot de Dijon puis au lyce Poincar de Nancy en classes prparatoires e e e e aux grandes coles, option informatique. Il sadresse donc en premier lieu aux e tudiants de ces classes prparatoires, mais aussi aux tudiants du premier cycle e e e de lUniversit suivant un enseignement dinformatique. Enn, il peut constituer e une base de dpart pour un enseignant de loption informatique voulant construire e son propre cours. Le plan du livre est celui adopt pour lexpos des cours donns a Dijon et a e e e Nancy, les chapitres 1 a 5 recouvrent le programme de premire anne (mthodes e e e de programmation, structure de liste, logique boolenne) et les chapitres 6 a 11 e celui de deuxime anne (complexit des algorithmes, structure darbre, manie e e pulation dexpressions formelles, langage et automates). A la suite de ces onze chapitres, jai inclus quelques sujets de problmes et quelques sujets de travaux e pratiques slectionns pour leur originalit parmi les sujets qui ont t donns aux e e e ee e tudiants de Dijon ou de Nancy ( lexception du sujet de TP intitul ( Recherche e a e ( de contradictions par la mthode des consensus ) qui est inspir dun exercice e e ) similaire prsent dans le cours de Luc Albert, et qui a t donn aux tudiants e e ee e e du lyce Champollion de Grenoble). Tous les sujets proposs sont accompagns e e e dun corrig plus ou moins dtaill. Ces corrigs sont regroups en n douvrage de e e e e e faon a viter au lecteur la tentation de sy reporter trop vite : un corrig nest en c e e aucune faon la solution unique et incontournable au problme pos, mais plut^t c e e o une rponse possible que le lecteur comparera avec sa propre rponse. e e Conformment a lesprit du programme ociel, laccent a t mis sur lcrie ee e ture eective de programmes implmentant les algorithmes tudis. En eet, les e e e raisonnements thoriques sur le comportement dun algorithme et notamment sur e sa complexit temporelle ou spatiale sont facilits par la prcision que confre e e e e la rdaction dun vritable programme. En outre, la programmation eective e e dun algorithme et son excution sur machine permettent de confronter la thorie e e a la ralit par une exprimentation pratique, de dtecter et de corriger les er e e e e reurs lmentaires ou les insusances dun raisonnement ainsi que daermir la ee comprhension du fonctionnement de lalgorithme. Le langage de programmation e servant de support a ce cours est le langage caml. Le nom caml est lacronyme de Categorical Abstract Machine Language, par rfrence a un modle de machine abstraite utilis dans les annes 1980 ee e e e pour implmenter le premier compilateur caml. Les implmentations actuelles e e de caml nutilisent plus ce modle de machine abstraite, mais le nom est rest. e e Le systme Caml-Light est une implmentation de caml pouvant tourner sur e e micro-ordinateur, il a t dvelopp a partir de 1990 par Xavier Leroy. Cest ee e e

Prface e

ce systme qui est actuellement utilis dans la majorit des classes prparatoires e e e e aux grandes coles pour lenseignement de loption informatique. Caml-Light est e distribu gracieusement par lINRIA via son site Internet : e
http://pauillac.inria.fr/caml/index-fra.html

Le cours introduit au fur et a mesure les lments du langage caml ncessaires ee e a lexpos, et seulement ces lments. Il ne constitue donc pas un manuel de e ee programmation en caml. Pour une prsentation plus complte de ce langage, e e on pourra consulter le manuel de rfrence disponible sous forme lectronique ee e sur le site de lINRIA, ainsi le livre de Pierre Weis et Xavier Leroy cit en e bibliographie. Le prsent ouvrage comporte en annexe un aide mmoire pour le e e langage caml, mis en page de faon a pouvoir ^tre photocopi en recto-verso sur c e e une feuille de format A4. Le mode de diusion de ce livre est assez inhabituel : le texte complet est disponible gratuitement sous forme lectronique sur le serveur de lINRIA, et les e ditions Vuibert ont accept de le publier sous forme ( papier ) permettant un e e ( ) plus grand confort de lecture. Je tiens a remercier les ditions Vuibert pour laide e quelles apportent ainsi, dans des conditions commerciales incertaines, a la diu sion de ce cours. Je remercie aussi chaleureusement Jean-Pierre Carpentier qui fut mon professeur de mathmatiques puis mon collgue en mathmatiques e e e et informatique au lyce Carnot de Dijon, et qui a bien voulu relire ce livre et e a minutieusement contr^l toutes les dmonstrations du cours, ainsi que les coroe e rigs des exercices et problmes. Ses remarques et critiques, toujours pertinentes, e e ont permis damliorer notablement la prsentation de certains points obscurs du e e cours, et de corriger les erreurs que comportait la version initiale. Je remercie ene e n messieurs Grard Duchamp professeur a luniversit de Rouen, et Olivier Bouverot professeur en classes prparatoires au lyce Jules Ferry de Versailles, e e qui ont particip a la relecture nale de ce livre. e Michel Quercia, Juillet 2002

Cours et exercices

Chapitre 1 Mthodes de programmation e

1-1

Description dun algorithme

Un algorithme est la description non ambigue en un nombre ni dtapes e dun calcul ou de la rsolution dun problme. Un programme est la traduction e e dun algorithme dans un langage de programmation ( comprhensible ) par une e ( ) machine. Une fonction est une relation entre chaque lment dun ensemble dit ee de dpart et un unique lment dun autre ensemble dit darrive. Considrons e ee e e par exemple le problme de la rsolution dans R dune quation du second degr e e e e a coecients rels : e La fonction : f : Lalgorithme : degr 2(a,b,c) : calcule les racines x , x de lquation ax2 + bx + c = 0 e e si a = 0 alors ERREUR sinon, soit = b2 4ac : b+ b si 0 alors x = ,x = 2a 2a sinon ERREUR n La description est nie (il ny a pas de points de suspension), elle est non ambigue dans la mesure o lon sait raliser les oprations mathmatiques (+, , , /, ) u e e e et o lopration ERREUR est connue. u e Le programme (en caml) : R3 (a, b, c) P(R) {x tq ax2 + bx + c = 0}

10

Mthodes de programmation e let degr_2(a,b,c) = e if a = 0. then failwith "quation incorrecte" e else let delta = b **. 2. -. 4. *. a *. c in if delta >= 0. then ((-. b +. sqrt(delta))/.(2. *. a), (-. b -. sqrt(delta))/.(2. *. a)) else failwith "discriminant ngatif" e ;;

Les symboles +., -., *., /. et **. dsignent en caml les oprations usuelles sur les e e nombres rels : addition, soustraction, multiplication, division et exponentiation. e les oprations entre nombres entiers sont notes +, -, *, / (division entire) et mod e e e (reste). Il ny a pas dlvation a une puissance entire prdnie en caml. ee e e e La version suivante est un peu plus ecace car elle conomise la rptition e e e des calculs de et de 2a :
let degr_2(a,b,c) = e if a = 0. then failwith "quation incorrecte" e else let delta = b **. 2. -. 4. *. a *. c in if delta >= 0. then let d = sqrt(delta) and deux_a = 2. *. a in ((d -. b)/.deux_a, (-. d -. b)/.deux_a) else failwith "discriminant ngatif" e ;;

Remarquons que lalgorithme ne correspond pas tout a fait a la dnition e de f : f(a, b, c) est correctement dnie m^me si a = 0 ou b2 4ac < 0 mais ces e e situations ont t limines pour pouvoir plus facilement traduire lalgorithme en eee e un programme (caml permet de produire un rsultat qui peut ^tre multiforme e e (vide, R, un singleton ou une paire) mais au prix dune complication importante). Par ailleurs la dnition de f nindique aucun moyen de calcul eectif. Il pourrait e exister plusieurs algorithmes foncirement dirents ralisant le calcul de f (dans e e e le cas de lquation de degr 2 on peut eectuer une rsolution par approximations e e e e successives au lieu dappliquer la formule (b )/(2a)), ou m^me aucun. La fonction f ci dessous est bien dnie mais nest pas calculable : e f(x) = 1 si x comporte une innit de 13 dans son dveloppement dcimal ; e e e 0 sinon.

On peut armer que f(0) = 0, f(ln(13/99)/ ln ) = 1, mais en ltat actuel des e connaissances on ne peut pas dterminer f(1), f(2), f(), . . . e Lalgorithmique consiste, partant de la dnition dune fonction f, a crire e e un ou plusieurs algorithmes dcrivant les tapes du calcul de f(x), a prouver que e e ces algorithmes sont corrects, cest--dire que le rsultat calcul est bien f(x), et a e e a dterminer le temps et la quantit de mmoire ncessaires a lexcution de ces e e e e e algorithmes. Le temps est mesur en nombre doprations considres comme e e ee

1-2 Itration e

11

e ( lmentaires ) , et la place mmoire en nombre de valeurs ( lmentaires ) ( ee ) ( ee ) dont on a besoin. Par exemple, lalgorithme degr 2 eectue 4 oprations pour e e calculer , 5 oprations pour calculer x et 5 pour x , soit en tout 14 oprations, e e 16 si lon compte comme oprations les tests si a = 0 et si 0 (on ne compte e pas les oprations eectues en cas derreur). Lespace mmoire ncessaire est de 3 e e e e nombres : , x , x . En pratique il est plus facile de raisonner sur un programme que sur un algorithme car le texte dun programme est plus prcis. Par exemple e les deux programmes degr_2 ci-dessus correspondent au m^me algorithme mais e e le deuxime eectue trois oprations de moins puisque la racine carre de delta e e e et le dnominateur 2.*.a ne sont calculs quune fois, et le numrateur de x est e e e calcul a laide dune soustraction au lieu dun changement de signe suivi dune e addition. En contrepartie, ce deuxime programme requiert deux places mmoires e e supplmentaires pour conserver les valeurs d et deux_a. e

1-2

Itration e

Litration consiste a rpter plusieurs fois un sous-algorithme. Le nombre e e e de rptitions peut ^tre dni lors de la rdaction de lalgorithme, mais on peut e e e e e aussi indiquer a quelle condition litration doit se poursuivre ou non. Dans ce e cas il est ncessaire de sassurer que la condition darr^t sera remplie au bout e e dun nombre ni de tours de boucle pour garantir que lalgorithme comporte un nombre ni dtapes (condition de terminaison). e Exemple, calcul de xn :
(* calcule x^n pour x et n entiers, n >= 1 *) let puissance(x,n) = let p = ref x in for i = 2 to n do p := !p * x done; !p ;; p = ref x signie que p fait rfrence a un nombre entier variable et valant iniee tialement x. Ce nombre est dsign par !p dans la suite de la fonction puissance e e et linstruction p := !p * x a pour eet de modier la valeur de lentier auquel p fait rfrence. En langage machine on dit que p est un pointeur vers une zone ee mmoire et que cette zone mmoire doit ^tre interprte comme la reprsentation e e e ee e machine dun nombre entier.

Lidenticateur i est appel indice de boucle. Il dsigne une valeur entire e e e variable qui augmente de 1 a chaque itration. Bien que reprsentant tous les e e deux des nombres variables, p et i nont pas le m^me statut : p est ladresse dune e variable et !p est la valeur courante de cette variable, tandis que i est la valeur courante de la variable indice de boucle. On na pas accs en caml a ladresse a e laquelle i est rang en mmoire. e e La fonction puissance telle quelle est dnie ci dessus ne produit un rsultat e e correct que lorsque largument n est entier au moins gal a 1. Cette restriction e

12

Mthodes de programmation e

gure en commentaire dans la dnition de puissance, mais il serait peut-^tre e e plus prudent de contr^ler la validit de n dans le corps de puissance par un o e test appropri. Quoi quil en soit, si lon fournit un argument n ngatif ou nul e e alors la boucle nest pas excute, cest une convention du langage caml, et donc e e puissance renvoie le rsultat x. Une autre possibilit de rsultat incorrect est due e e e a la limitation des nombres entiers en machine : le calcul de !p * x peut produire un rsultat suprieur au plus grand nombre entier reprsentable en machine. Dans e e e ce cas, soit lordinateur dtecte ce fait et interrompt le programme, soit, le plus e souvent, ce dbordement nest pas dtect et les calculs continuent avec une valeur e e e incorrecte pour !p. Sur un micro-ordinateur 32 bits cest le cas et on observe que puissance (10,10) = -737418240 . .. Boucle avec arrt conditionnel : e
(* cherche le plus petit diviseur > 1 de n, n >= 2 *) let diviseur(n) = let d = ref 2 in while n mod !d <> 0 do d := !d + 1 done; !d ;;

Preuve de correction : la boucle est nie car il existe au moins un diviseur de n a savoir n lui m^me et !d avance de 1 en 1 a partir de 2 avec 2 e n par hypothse. Lorsque la boucle se termine, !d contient un diviseur de n puisque e cest la condition darr^t, et cest le plus petit a part 1 car sinon la boucle se serait e termine plus t^t. e o Calcul sur les polynmes. Etant donns un polyn^me : o e o P = a0 + a1 X + . .. + an Xn a coecients rels et un nombre rel x, on veut calculer la valeur P(x). La mthode e e e nave conduit a calculer sparment les puissances de x : 1, x, . . ., xn, a les multi e e plier par les coecients ai correspondants et a additionner le tout :
(* calcule p(x) pour un polyn^me p en un point x *) o let valeur p x = let n = vect_length(p) - 1 (* n = deg(p) *) and xk = ref 1.0 (* !xk = x^k *) and vk = ref p.(0) (* !vk = a0 + .. + ak*xk *) in for k = 1 to n do xk := x *. !xk; vk := !vk +. p.(k) *. !xk done; !vk (* rsultat *) e ;;

1-2 Itration e

13

Les coecients de P sont conservs dans le vecteur p, cest--dire que p.(i) e a est la valeur du coecient ai. p.(i) est appel lment dindice i de p, i tant e ee e un nombre entier compris entre 0 et vect_length(p)-1 o vect_length(p) est le u nombre dlments de p. Par ailleurs la fonction valeur est dnie comme une ee e fonction a deux arguments ( dtachs ) : valeur p x et non valeur(p,x). Ceci e ) ( e permet (cest une spcicit de caml) de lutiliser avec le premier argument seul e e sous la forme :
let f = valeur p;;

ce qui dnit f comme une fonction a un argument de sorte que f(x) quivaut a e e valeur p x. On peut ainsi ne pas spcier le polyn^me p a chaque calcul si lon e o doit en faire plusieurs avec le m^me polyn^me. e o Dmontrons que cet algorithme calcule eectivement le nombre P(x) : pour e cela on montre par rcurrence sur k que, a lentre dans la boucle, on a les relae e tions : () !xk = xk1, !vk = a0 + a1 x + . .. + ak1 xk1

et a la sortie : () !xk = xk , !vk = a0 + a1 x + . .. + ak xk

ce qui rsulte clairement des expressions aectes a xk et a vk dans le programme. e e La dernire valeur de !vk est donc a0 +a1 x+ . .. +an xn = P(x). Les proprits () e ee et () sont appeles invariant de boucle en entre et invariant de boucle en e e sortie : tout algorithme comportant une boucle non triviale doit ^tre accompagn e e de la spcication dun tel invariant de boucle permettant de vrier aisment la e e e correction de lalgorithme. Temps dexcution : si lon nglige le temps de calcul de vect_length(p)-1 et la e e mise a jour de k au cours de litration, lalgorithme eectue une addition et deux e multiplication relles a chaque tour de boucle, donc au total n additions et 2n e multiplications. Algorithme de Horner : on peut conduire plus rapidement le calcul de P(x) en eectuant les oprations a lenvers : e
(* calcule p(x) pour un polyn^me p en un point x *) o let Hrner p x = o let n = (vect_length p) - 1 in (* n = deg(p) *) let s = ref p.(n) in (* !s = a_k + ... + a_n*x^(n-k) *) for k = n-1 downto 0 do s := !s *. x +. p.(k) done; !s ;;

On dmontre comme prcdemment que Hrner calcule eectivement P(x), e e e o mais a prsent il nest eectu quune multiplication par tour de boucle donc le e e temps de calcul est de n additions et n multiplications relles. On peut esprer e e un gain en vitesse compris entre 33% et 50% en utilisant cet algorithme suivant que le temps dune addition est ngligeable devant celui dune multiplication ou e lui est comparable.

14

Mthodes de programmation e

1-3

Rcursivit e e

Rcursivit simple e e Un algorithme est dit rcursif lorsquil intervient dans sa description, ceste a-dire lorsquil est dni en fonction de lui m^me. Trs souvent un algorithme e e e rcursif est li a une relation de rcurrence permettant de calculer la valeur dune e e e fonction pour un argument n a laide des valeurs de cette fonction pour des argu ments infrieurs a n. Reprenons lexemple du calcul de xn vu prcdemment ; on e e e peut dnir xn par rcurrence a partir des relations : e e x0 = 1, xn = x xn1 si n 1.

La traduction en caml de ces relations est :


(* calcule x^n pour x et n entiers, n >= 0 *) let rec puissance(x,n) = if n = 0 then 1 else x * puissance(x,n-1) ;;

ou plus lgamment : ee
let rec puissance(x,n) = match n with | 0 -> 1 | _ -> x * puissance(x,n-1) ;;

( _ dsigne une valeur quelconque en caml). Observons cet algorithme tourner : e


trace "puissance";; puissance(5,3);; The function puissance is now traced. - : unit = () #puissance <-- 5, 3 puissance <-- 5, 2 puissance <-- 5, 1 puissance <-- 5, 0 puissance --> 1 puissance --> 5 puissance --> 25 puissance --> 125 - : int = 125

La machine applique la rgle : puissance(x,n) = x * puissance(x,n-1) tant que e lexposant est dirent de 0, ce qui introduit des calculs intermdiaires jusqu e e a aboutir au cas de base : puissance(x,0) = 1. Les calculs en suspens sont alors achevs dans lordre inverse jusqu obtenir le rsultat nal. Comme pour les e a e boucles avec condition darr^t, il faut sassurer que le cas de base sera atteint en e un nombre ni dtapes sinon lalgorithme ( boucle ) . Pour la fonction puissance e ( ) prcdente la terminaison est garantie si n est entier positif ou nul, il y a bouclage e e si n < 0. On peut liminer ce risque de bouclage en remplaant le test if n = 0 e c

1-3 Rcursivit e e

15

par if n <= 0. Dans ce cas lalgorithme ne boucle plus mais il ne fournit pas pour autant un rsultat correct lorsque n < 0. e Les fonctions vriant une relation de rcurrence de la forme : e e f(0) = f0 , f(n) = g(n, f(n 1)) si n 1,

se pr^tent aussi facilement a un codage itratif que rcursif. Les performances des e e e programmes correspondants sont gnralement comparables en termes de temps e e dexcution, mais une programmation rcursive produit autant de calculs en suse e pens que le nombre dtapes ncessaires pour arriver au cas de base, cest--dire n e e a dans cet exemple. La quantit de mmoire ncessaire pour excuter lalgorithme e e e e rcursif est donc proportionnelle a n ce qui peut ^tre g^nant si n est grand, alors e e e quelle est constante pour lalgorithme itratif. e Rcursivit double e e
(* calcule le coefficient du bin^me C(n,p), n >= p >= 0 *) o let rec binome(n,p) = if p = 0 or p = n then 1 else binome(n-1,p) + binome(n-1,p-1) ;;

Lalgorithme de calcul de Cp est dduit la relation de Pascal avec deux cas e n de base regroups : C0 = Cn = 1. Montrons que cet algorithme termine et fournit e n n le rsultat correct dans tous les cas o n p 0 : e u { On remarque dabord que si 0 < p < n alors 0 < p n1 et 0 p1 < n1 donc si le cas de base nest pas atteint les deux appels rcursifs de binome ont e des arguments convenables. { Ensuite, on dmontre par rcurrence sur n la proprit suivante : e e ee si 0 p n alors binome(n, p) termine et retourne le coecient Cp . n

Cest vident si n = 0 puisqualors p = 0, et si cest vrai pour un entier n 1 e alors ca lest aussi pour n car pour p = 0 ou p = n on obtient le rsultat e correct Cp = 1, et si 0 < p < n alors la formule : n
binome(n-1,p) + binome(n-1,p-1)

est calcule par hypothse de rcurrence en un nombre ni dtapes et fournit e e e e la bonne valeur pour Cp . n La correction de binome est donc prouve. Cependant cet algorithme est trs e e peu ecace. La gure 1 montre la trace du calcul de C3 . La fonction binome a t ee 5 appele 19 fois : en eet, on a C3 = C3 + C2 et C3 = C3 + C2, C2 = C2 + C1, do e u 5 4 4 4 3 3 4 3 3 C3 = C3 + 2C2 + C1 mais le calcul de C2 est eectu 2 fois. Au rang suivant, on a e 5 3 3 3 3 C3 = C3 + 2C2 + 3C1 + C0 et lon constate que C2 est calcul deux fois et C1 lest 3 e 5 3 2 2 2 2 2

16 trace "binome";; binome(5,3);; The function binome is now traced. - : unit = () #binome <-- 5, 3 binome <-- 4, 2 binome <-- 3, 1 binome <-- 2, 0 binome --> 1 binome <-- 2, 1 binome <-- 1, 0 binome --> 1 binome <-- 1, 1 binome --> 1 binome --> 2 binome --> 3 binome <-- 3, 2 binome <-- 2, 1 binome <-- 1, 0 binome --> 1 binome <-- 1, 1 binome --> 1

Mthodes de programmation e binome --> 2 binome <-- 2, binome --> 1 binome --> 3 binome --> 6 binome <-- 4, binome <-- 3, binome <-- 2, binome <-- 1, binome --> 1 binome <-- 1, binome --> 1 binome --> 2 binome <-- 2, binome --> 1 binome --> 3 binome <-- 3, binome --> 1 binome --> 4 binome --> 10 - : int = 10

3 2 1 0 1

Figure 1 : calcul rcursif de Cp e n fois... Tout se passe comme si la machine navait ( aucune mmoire ) et refaisait e ( ) sans cesse les m^mes calculs, ce qui est eectivement le cas car le programme e nindique pas quil faut mmoriser les calculs intermdiaires. La programmation e e ecace dune fonction doublement rcursive ncessite de coder la mmorisation des e e e valeurs devant servir plusieurs fois, par exemple dans un vecteur. Lexercice 1-7 propose une meilleure programmation du calcul de Cp . n Rcursivit mutuelle e e Deux algorithmes sont dits mutuellement rcursifs lorsque chacun des deux e fait appel a lautre. Par exemple :
let rec pair(x) = match x with | 0 -> true | _ -> impair(x-1) and impair(x) = match x with | 0 -> false | _ -> pair(x-1) ;;

Les deux dnitions doivent ^tre donnes en une seule instruction de la e e e forme : let rec ... and .... On peut spcier un nombre quelconque de fonce tions dpendant les unes des autres. Les fonctions mutuellement rcursives ape e paraissent naturellement dans les problmes de parcours darbres ou danalyse e syntaxique, en particulier dans les valuateurs de formules et les compilateurs. e

1-4 Diviser pour rgner e

17

1-4

Diviser pour rgner e

La mthode ( diviser pour rgner ) consiste a ramener la rsolution dun e e e ( ) problme dpendant dun entier n a la rsolution de plusieurs problmes identiques e e e e portant sur des entiers n < n ; en gnral n n/2. Il sagit dun cas particulier e e de rcursion avec une dcroissance trs rapide vers le cas de base. e e e Exemple, calcul de xn . On a vu que xn peut ^tre dni par la relation de e e rcurrence : e x0 = 1, xn = x xn1. On peut aussi utiliser la relation mathmatiquement plus complique : e e x0 = 1, x1 = 1, x2k = (xk )2 , x2k+1 = x x2k.

Ici n = 2k ou 2k + 1 et n = k n/2.
let rec | 0 -> | 1 -> | _ -> ;; puiss_2(x,n) = match n with 1 x let y = puiss_2(x,n/2) in if n mod 2 = 0 then y*y else x*y*y

La dirence entre puissance telle quelle est dnie en 1-2 ou en 1-3 et puiss_2 e e se fait sentir ds que n dpasse la dizaine : e e
puissance(x,10) -> x x x x x x x x x x : 9 multiplications puiss_2(x,10) -> (x (x2 )2 )2 : 4 multiplications puiss_2(x,100) -> ((x (((x x2 )2)2 )2 )2 )2 : 8 multiplications

Si lon considre que le temps dune multiplication est constant (cest--dire inde a e pendant des oprandes), alors puiss_2 est deux fois plus rapide que puissance pour e n = 10 et douze fois plus rapide pour n = 100. Cette hypothse de constance du e temps de multiplication est en pratique vrie si lon opre sur des nombres de e e e taille machine xe, ce qui nest pas raliste lorsque n est grand. Elle est par contre e vrie pour toute valeur de n dans le problme de lexponentiation modulaire : e e e calculer xn mod a o a est un entier naturel non nul donn, en remplaant les u e c expressions y*y et x*y*y par y*y mod a et x*y*y mod a. Lexercice 1-9 propose ltude des performances compares de puissance et puiss_2 dans le cas de nombres e e de tailles arbitrairement grandes. Multiplication de polynmes o Soient P(x) = a0 + a1x + . .. + ap xp et Q(x) = b0 + b1 x + . .. + bq xq deux polyn^mes donns par leurs coecients (entiers, rels, .. . ) dont on veut calculer o e e le produit R(x) = c0 + c1 x + . .. + cr xr . En dveloppant le produit P(x)Q(x) on e obtient la relation :
p q

R(x) =
i=0 j=0

ai bj xi+j

18

Mthodes de programmation e

qui est implmente dans le programme suivant : e e


(* calcule le produit polynomial des vecteurs p et q let produit(p,q) = let dp = vect_length(p) - 1 (* degr de p e and dq = vect_length(q) - 1 in (* degr de q e *) *) *)

let r = make_vect (dp + dq + 1) 0 in (* initialisation *) for i = 0 to dp do for j = 0 to dq do (* calcule tous les *) r.(i+j) <- r.(i+j) + p.(i) * q.(j) (* produits ai * bj *) done done; r (* rsultat *) e ;;

Le temps dexcution de ce programme est (p + 1)(q + 1) multiplications ( le ( ee mentaires ) et autant dadditions, soit de lordre de 2n2 oprations pour deux e ) polyn^mes de degr n. Un algorithme de type ( diviser pour rgner ) a t pro e e ( ) ee e sent par Knuth en 1969 : on suppose que les polyn^mes P et Q sont de degrs e o e au plus n 1, on note k = n/2 , = n k = n/2 o u et u dsignent les u e parties entires infrieure et suprieure dun rel u, et on dcompose les polyn^mes e e e e e o P et Q de la manire suivante : e P(x) = (a0 + .. . + ak1 xk1) + xk (ak + .. . + an1x Q(x) = (b0 + .. . + bk1 xk1) + xk (bk + . .. + bn1 x On a alors : R(x) = (P0 + xk P1)(Q0 + xk Q1 ) = P0 Q0 + xk (P0Q1 + P1 Q0 ) + x2kP1 Q1 = P0 Q0 + xk ((P0 + P1 )(Q0 + Q1 ) P0Q0 P1 Q1 ) + x2k P1Q1 . Cette formule fait appara^ trois multiplications de polyn^mes de degr au plus tre o e k 1, ou 1, deux additions de polyn^mes de degr au plus 1 et trois o e additions de polyn^mes de degr au plus 2 2 (le calcul de P0 Q0 + x2kP1 Q1 peut o e ^tre eectu sans addition). Elle est implmente dans le programme suivant : e e e e
(* multiplication de Knuth des polyn^mes p et q o (* on suppose que p et q ont m^me longueur n e let rec mult_Knuth p q n = let r = make_vect (2*n-1) 0 in (* rsultat <- 0 e (* cas de base : p et q sont constants if n = 1 then r.(0) <- p.(0) * q.(0) *) *) *) *)
1 1

) = P 0 + x k P1 ;

) = Q 0 + x k Q1 .

else begin (* cas gnral : on divise pour rgner *) e e e let k = n/2 and l = (n+1)/2 in

1-4 Diviser pour rgner e let and and and p0 p1 q0 q1 = = = = sub_vect sub_vect sub_vect sub_vect p p q q 0 k 0 k k l k l in (* dcoupe p,q en 2 *) e

19

let p01 = make_vect l and q01 = make_vect l for i = 0 to k-1 do p01.(i) <- p0.(i) + q01.(i) <- q0.(i) + done; if k < l then begin p01.(k) <- p1.(k); q01.(k) <- q1.(k) end;

0 (* calcule p0+p1,q0+q1 *) 0 in p1.(i); q1.(i)

let r0 = mult_Knuth p0 q0 k and r1 = mult_Knuth p01 q01 l and r2 = mult_Knuth p1 q1 l in (* assemble les produits *) for i = 0 to 2*k-2 do r.(i) for i = 0 to 2*l-2 do r.(i+2*k) for i = 0 to 2*k-2 do r.(i+k) <- r.(i+k) + r1.(i) done; for i = 2*k-1 to 2*l-2 do r.(i+k) <- r.(i+k) + r1.(i) done; end; r ;;

(* rcursion *) e

<- r0.(i) done; <- r2.(i) done; r0.(i) - r2.(i)

r2.(i)

Temps de calcul : on se limite pour simplier au cas o n est une puissance de 2 u (voir la section 6-3 pour le cas gnral). Soit M(p) le nombre de multiplicae e tions et A(p) le nombre dadditions/soustractions eectues pour multiplier deux e polyn^mes de longueur n = 2p . On a : o M(0) = 1, A(0) = 0, M(p) = 3M(p 1), A(p) = 3A(p 1) + 2 2p1 + 3 (2p 1) = 3A(p 1) + 2p+2 3.
3 On obtient alors par rcurrence : M(p) = 3p et A(p) = 13 3p 2p+3 + 2 . On a e 2 3p = 2p log2 (3) = nlog2 (3) , donc le nombre total doprations eectues est environ e e 25, ce nombre est infrieur au nombre doprations e e gal a 15 nlog2 (3) . Pour n e 2 eectues par produit. Toutefois la complication de lalgorithme de Knuth le rend e moins performant que produit pour de petites valeurs de n. Exprimentalement, e mult_Knuth est aussi rapide que produit pour n = 128 et devient plus rapide pour n 256.

20

Mthodes de programmation e

n
produit mult Knuth produit mult Knuth

1 1 0 1 1

2 4 8 16 32 64 128 256 4 16 64 256 1024 4096 16384 65536 5 28 113 400 1325 4228 13193 40600 4 16 64 256 1024 4096 16384 65536 3 9 27 81 243 729 2187 6561

additions multiplications

Note historique : lalgorithme de multiplication rapide dcrit ci-dessus, bien que e d^ a Knuth, est gnralement appel ( algorithme de Karatsuba ) car il est u e e e ( ) driv dune ide similaire prsente par Karatsuba en 1961. e e e e e

1-5

Exercices

Exercice 1-1 : classement de trois nombres Ecrire un algorithme ou un programme caml permettant de classer trois nombres en eectuant le moins possible de comparaisons. Exercice 1-2 : nombres parfaits Un nombre entier n 2 est dit parfait sil est gal a la somme de tous ses diviseurs e stricts, 1 compris. Ecrire un programme qui teste si son argument est un nombre parfait. Exercice 1-3 : algorithme de Horner et translation de polynmes o On reprsente un polyn^me P = p0 + p1 X + .. . + pn1Xn1 a coecients entiers e o par le vecteur p = [|p0; . ..; pn1|]. En sinspirant de lalgorithme de Horner, crire une fonction caml : e
translate : int vect -> int -> int vect

telle que translate p a calcule le polyn^me Q dni par Q(x) = P(x + a). o e Exercice 1-4 : dcodage de nombres entiers e 1. Soit s une cha^ de caractres reprsentant un nombre entier naturel par ne e e son criture dcimale. Ecrire une fonction caml calculant la valeur (de type e e int) associe a s. La valeur dun caractre reprsentant un chire dcimal e e e e peut ^tre obtenue a laide de la fonction suivante : e
let valeur_chiffre(c) = int_of_char(c) - int_of_char(0);;

2. Soient s et s deux cha^ nes de caractres reprsentant les entiers naturels a e e et b. Il sagit dans cette question de comparer a et b. Une premire solution e est de calculer en machine les nombres a et b puis de comparer les rsultats, e mais cette solution choue si a ou b dpasse la capacit dune variable de e e e type int. On demande ici dcrire un programme qui compare a et b sans les e calculer et en fournissant un rsultat correct quelles que soient les longueurs e de s et s .

1-5 Exercices

21

Exercice 1-5 : racine carre e La racine carre dun rel a > 0 peut ^tre calcule de faon approche par e e e e c e lalgorithme de Heron : choisir x0 > 0 et calculer x1 , ... , xn , ... par la relation xk+1 = (xk + a/xk )/2. Alors la suite (xn ) converge vers a. 1. Montrer que la suite (xn ) dcroissante a partir du rang 1 et quelle est e converge eectivement vers a. Lalgorithme de Heron mrite-t-il vraiment e lappellation dalgorithme ? 2. On suppose maintenant que a est entier et lon souhaite calculer la racine carre entire de a, cest--dire lentier naturel b tel que b2 a < (b + 1)2 . e e a Plut^t que dappliquer ( lalgorithme ) de Heron, on lui substitue une o ( ) version entire : e choisir x0 entier strictement positif et calculer x1, ... , xn, ... par la relation xk+1 = (xk + a/xk )/2 o u dsigne la partie entire de u. u e e Arr^ter les calculs ds que lon obtient deux valeurs successives x n et e e xn+1 telles que xn xn+1 et n > 0. Retourner xn. Dmontrer que cet algorithme est valide (cest--dire quil termine et fournit e a le rsultat correct). e Exercice 1-6 : calcul rcursif de Cp e n Le programme suivant calcule Cp pour n et p entiers naturels en utilisant la n formule de Pascal :
let rec binome(n,p) = if p = 0 or p = n then 1 else binome(n-1,p) + binome(n-1,p-1) ;;

Dterminer le nombre dappels a binome eectus lors du calcul de binome(n,p) en e e fonction de n et p. Exercice 1-7 : calcul amlior de Cp e e n Comment peut-on calculer Cp plus ecacement ? n Exercice 1-8 : dnombrement de chemins e La gure ci-dessous donne le plan dune ville. Ecrire un programme calculant le nombre de chemins reliant A a B. B p sens uniques :

A n

22

Mthodes de programmation e

Exercice 1-9 : exponentiation rapide Les deux programmes suivants calculent xn pour n entier naturel :
let rec puiss_1(x,n) = match n with | 0 -> 1 | _ -> x*puiss_1(x,n-1) ;; let | 0 | 1 | _ ;; rec puiss_2(x,n) = match n with -> 1 -> x -> let y = puiss_2(x,n/2) in if n mod 2 = 0 then y*y else x*y*y

On considre que la multiplication de deux nombres de a et b chires prend un e temps proportionnel a ab et que le rsultat est cod systmatiquement sur a + b e e e chires. Comparer les temps dexcution de puiss_1(x,n) et puiss_2(x,n) lorsque e x est un nombre de a chires (on se limitera au cas o n est une puissance de 2). u Exercice 1-10 : exponentiation itrative e Ecrire un programme itratif calculant xn en temps logarithmique par rapport e a n (on suppose ici que le temps dune multiplication est constant). Exercice 1-11 : exponentiation optimale Quel est le nombre minimal de multiplications ncessaires pour calculer x15 ? e Exercice 1-12 : suite de Fibonacci La suite de Fibonacci est dnie par les relations : e F0 = F1 = 1, Fn+1 = Fn + Fn1 pour n 1. 1. Ecrire un programme rcursif calculant Fn pour n 0. e 2. Pour amliorer le temps dexcution, crire un programme rcursif calculant e e e e le couple (Fn1, Fn). 3. Dmontrer la relation : n, p 1, Fn+p = FnFp + Fn1Fp1. e 4. En dduire un programme de calcul de Fn selon la mthode ( diviser pour e e ( rgner ) . e ) Exercice 1-13 : une fonction mystrieuse e
let rec if x else else ;; f(x) = <= 1 then 1 if x mod 2 = 0 then 2*f(x/2) 1 + f(x+1)

1. Montrer que lappel f(x) termine quel que soit lentier x. 2. Montrer que pour tout x N le nombre f(x) + x est une puissance de 2. 3. Pouvez vous dcrire mathmatiquement la fonction f ? e e

1-5 Exercices

23

Exercice 1-14 : calcul de ppcm Soient a0 , .. ., an1, n nombres entiers naturels dont on veut calculer le plus petit commun multiple. On suppose disposer dune fonction ppcm2 calculant le ppcm de deux entiers. 1. Ecrire un programme itratif calculant ppcm(a0 , . .., an1). Les nombres ai e seront placs dans un vecteur transmis en argument a ce programme. e 2. Ecrire de m^me un programme utilisant la mthode ( diviser pour rgner ) e e e ( ) et comparer les performances de ces deux programmes. Exercice 1-15 : multiplication rapide La multiplication de Karatsuba est construite sur lapplication rcursive de la e dcomposition du produit (a0 + a1 x)(b0 + b1 x) en trois multiplications : e (a0 + a1 x)(b0 + b1 x) = a0 b0 + ((a0 + a1 )(b0 + b1 ) a0 b0 a1 b1 )x + a1 b1 x2 . Chercher un algorithme permettant de calculer (a0 + a1 x + a2 x2)(b0 + b1 x + b2 x2) en cinq multiplications et en dduire un algorithme de multiplication polynomiale e asymptotiquement plus rapide que celui de Karatsuba. Indication : le polyn^me o a calculer est de degr au plus 4, donc il peut ^tre dduit de la connaissance de e e e ses valeurs en 5 points distincts.

Chapitre 2 Structure de liste

2-1

Dnitions e

Une liste est une suite nie dlments note L = (a0 , a1, . . ., an1) o ee e u n N est la longueur de la liste L et a0, a1 , . . . , an1 sont le premier, le e deuxime, .. . , le nme objet de L. Lorsque n = 0 la liste ne contient aucun objet, e on dit que cest une liste vide. Le premier lment dune liste est aussi appel ee e t^te de la liste, et la sous-liste L = (a1 , . .., an1) est la queue de L. e Exemples { Coordonnes dun point dans le plan : L = (x, y). La longueur de L est 2 ; le e premier objet est x (abscisse), cest un nombre rel ; le deuxime objet est y e e (ordonne), cest aussi un nombre rel. e e
e { Polygone dans un plan a n sommets : L = (P1 , .. ., Pn). Le i me objet est Pi = (xi, yi), un point repr par ses coordonnes. Par exemple la liste : ee e L = (0, 0), (1, 0), (1, 1), (0, 1) reprsente un carr. Remarquer que les e e lments de L sont eux-m^mes des listes. ee e

{ Liste des lves de la classe : chaque objet reprsente un lve sous la forme ee e ee de son nom (cha^ de caractres), son prnom (cha^ de caractres) et sa ne e e ne e moyenne gnrale (nombre dcimal). Lordre de rangement dans la liste est e e e par exemple lordre alphabtique des noms. e { Liste des termes dun polyn^me : chaque objet ti est un couple (a, e) repro e sentant un mon^me aXe avec a = 0. Les exposants sont distincts, et les tero mes sont classs par ordre croissant des exposants. Par exemple le polyn^me e o P = X3 X2 + 2 est reprsent par la liste L = (2, 0), (1, 2), (1, 3) . e e Remarque : une liste peut contenir plusieurs fois le m^me objet a des positions e diffrentes, par exemple un point du plan peut avoir deux coordonnes gales. e e e

2-2 Reprsentation en mmoire e e

25

Oprations usuelles sur les listes e { Cration et initialisation dune liste. e { Parcours dune liste pour eectuer un m^me traitement sur chaque lment. e ee Par exemple imprimer llment. ee { Recherche dun lment particulier dans une liste : cet lment est spci ee ee e e par son indice ou une partie de sa valeur. Par exemple dans la liste des lves ee de la classe on peut chercher le troisime dans lordre alphabtique, ou celui e e dont le nom commence par MARTIN. On peut aussi chercher llve ayant la ee plus forte moyenne gnrale. Lorsque plusieurs lments de la liste vrient e e ee e le critre de recherche, on peut les chercher tous ou seulement le premier ou e le dernier. { Insertion dun nouvel lment : en dbut, en n ou au milieu dune liste. Si ee e la liste ne doit pas contenir de rptition alors linsertion peut ^tre prcde e e e e e e dune recherche de llment a insrer pour sassurer quil nest pas dj ee e ea prsent dans la liste. e { Permutation des lments dune liste pour respecter un nouvel ordre de ee classement. Par exemple trier les lves de la classe par moyenne dcroisee e sante. { Concatnation ou fusion de deux listes L1 et L2 : la concatnation produit e e une liste L constitue de tous les lments de L1 puis tous les lments de e ee ee L2 ; la fusion produit une liste L constitue de tous les lments de L1 et de e ee L2 classs suivant un certain ordre. Pour la fusion on suppose que L1 et L2 e sont dj tries suivant lordre choisi. ea e

2-2

Reprsentation en mmoire e e

Le langage caml dnit trois structures de donnes permettant de reprsenter e e e des listes. Reprsentation par un n-uplet e La dclaration : e
let A = (0,0) and B = (1,0) and C = (1,1) and D = (0,1);; let L = (A,B,C,D);;

dnit A, B, C, D comme tant des listes a deux lments entiers et L comme tant e e ee e une liste de quatre lments couples dentiers. Les listes dnies de cette manire ee e e sont appeles ( n-uplets ) o n est la longueur de la liste ; elles sont essentiellement e ( ) u utilises pour grouper plusieurs objets participant a un m^me traitement, par e e exemple les deux coordonnes dun point dans un programme de dessin. Les e

26

Structure de liste

lments dun n-uplet ne sont pas ncessairement de m^me type. Laccs aux ee e e e lments dun n-uplet se fait en indiquant leur position : ee
let (_,_,x,_) = L in ...

e ee ( slectionne ) le troisime lment de L et le nomme x pour la suite des calculs. ( e ) La longueur dun n-uplet est dnie implicitement par son criture. e e Reprsentation par un vecteur e Un vecteur est une liste dobjets de m^me type rangs e e en mmoire. e
let V = [| 1.0; 2.0; 3.0; 4.0 |];;

e ( conscutivement ) ( )

dclare une variable V de type vecteur rel dont les lments sont V.(0) = 1.0, e e ee V.(1) = 2.0, V.(2) = 3.0 et V.(3) = 4.0. La longueur de V est vect length(V) = 4. En mmoire V est reprsent par un bloc de 5 cellules conscutives : e e e e 4 1.0
V.(0)

2.0
V.(1)

3.0
V.(2)

4.0
V.(3)

La premire cellule contient la longueur du vecteur, les cellules suivantes contiene nent les lments placs par indice croissant. La longueur dun vecteur nest pas ee e modiable mais chaque lment peut ^tre modi ( sur place ) , cest--dire sans ee e e ( a ) avoir a construire un nouveau vecteur. Les vecteurs permettent donc de reprsenter des listes de longueur constante, e mais on peut aussi les utiliser pour reprsenter des listes de longueur variable en e ne ( remplissant ) que le dbut du vecteur et en conservant dans une variable a e ( ) part le nombre dlments eectivement prsents. ee e Reprsentation par une liste cha ee e n Une liste cha^ ee est une liste dobjets de m^me type rangs en mmoire n e e e de manire non ncessairement conscutive. A chaque lment de la liste autre e e e ee que le dernier est associ un pointeur qui contient ladresse mmoire de llment e e ee suivant ; au dernier lment est associ un pointeur spcial marquant la n de la ee e e liste.
let L = [ 3; 1; 4; 1 ];;
hd L tl L

3
objet

pointeur

Le premier lment de la liste est hd L = 3 et la queue de la liste est tl L = [1; 4; 1] ee (hd et tl sont les contractions de head et tail). Le deuxime lment est donc e ee

2-3 Parcours dune liste

27

hd(tl L) = 1, le troisime hd(tl(tl L)) = 4 et ainsi de suite. Dans un programme e caml les pointeurs sont reprsents par loprateur :: et les dclarations suivantes e e e e sont quivalentes : e
let let let let let L L L L L = = = = = [ 3 3 3 3 3; :: :: :: :: 1; 4; 1 ];; [ 1; 4; 1 ];; 1 :: [ 4; 1 ];; 1 :: 4 :: [ 1 ];; 1 :: 4 :: 1 :: [];;

mais : let M = [ 3; 1 ] :: [ 4; 1 ] est interprte comme la demande de craee e tion de la liste : [ [ 3; 1 ]; 4; 1 ] ce qui provoque une erreur de typage (liste htrogne). ee e

2-3

Parcours dune liste

Soit L = (a0 , .. ., an1) une liste. Parcourir L consiste a ( passer en revue ) ( ) chaque lment ai pour eectuer un traitement. Par exemple pour conna^ la ee tre longueur dune liste cha^ ee, on la parcourt en incrmentant un compteur a chaque n e lment rencontr. De m^me le calcul de la somme ou du maximum dune liste de ee e e nombres est une opration de type ( parcours ) de la liste. e ( )
(* Applique la fonction traitement aux elments du vecteur v *) e let parcours_vect traitement v = for i=0 to vect_length(v)-1 do traitement(v.(i)) done ;; (* idem pour une liste cha^ne *) e let rec parcours_liste traitement l = match l with | [] -> () | a::suite -> traitement(a); parcours_liste traitement suite ;;

Les fonctions parcours_vect et parcours_liste sont implmentes dans la e e bibliothque standard de caml sous les noms do_vect et do_list. e

28

Structure de liste

2-4

Recherche dun lment dans une liste ee

Recherche dun lment par son rang ee


e Etant donns une liste L et un entier i on veut conna^ e tre le i me lment ee de L. Cette situation se prsente par exemple lorsque L est une table de valeurs e dune fonction f dnie sur les entiers de [[1, n]] : llment cherch est alors la e ee e valeur f(i).

(* recherche dans un vecteur *) let cherche_vect v i = if (i <= 0) or (i > vect_length(v)) then failwith "rang incorrect" else v.(i-1) ;; (* recherche dans une liste *) let rec cherche_liste l i = if (i <= 0) or (l = []) then failwith "rang incorrect" else if i = 1 then hd l else cherche_liste (tl l) (i-1) ;;

Comparaison de ces versions : la version ( vecteur ) sexcute en un temps constant e ( ) tandis que la version ( liste cha^ ee ) ncessite un temps dexcution environ n ) e e ( proportionnel a i (pour i grand). Une liste cha^ ee se comporte comme une bande n magntique, il faut drouler la bande depuis le dbut jusqu la position dsire. e e e a e e De plus le test de non dbordement est eectu a chaque tape dans le cas dune e e e liste cha^ ee car la longueur de la liste nest pas connue. n Recherche dun lment par sa valeur ee Etant donn une liste L on veut savoir sil existe un ou plusieurs lments e ee de L vriant une certaine proprit et ventuellement conna^ e ee e tre ces lments. ee Considrons par exemple le travail dun compilateur analysant un texte source. Il e tient a jour la liste des identicateurs dj dclars, et doit accder a cette liste : ea e e e { lors de la dclaration dun nouvel identicateur pour dterminer sil ny a e e pas double dclaration ; e { lors de la compilation dune expression faisant intervenir une variable pour vrier que cette variable a t dclare et dterminer son type, sa taille et e ee e e e son adresse en mmoire. e Dans cet exemple la proprit a vrier est lgalit du nom de lidenticateur e e e e e avec le nom analys. En principe lidenticateur cherch gure au plus une fois e e dans la liste des identicateurs dclars, mais il peut ^tre prsent plusieurs fois si e e e e le compilateur supporte la notion de porte locale des identicateurs, auquel cas e la recherche doit retourner lidenticateur le plus rcemment dclar ayant le nom e e e

2-5 Insertion et suppression

29

analys. On peut supposer que la liste des identicateurs est organise de sorte e e que les dclarations les plus rcentes gurent en dbut de liste, donc la recherche e e e doit sarr^ter sur le premier lment convenant en partant du dbut de la liste. e ee e
(* Recherche si le vecteur v contient un objet convenant, et (* renvoie le premier objet convenant sil existe, sinon (* dclenche lexception "non trouv". e e (* "convient" est une fonction boolenne disant si un objet e (* convient. let cherche_vect convient v = let i = ref 0 in while (!i < vect_length(v)) & not(convient(v.(!i))) do i := !i+1 done; if !i < vect_length(v) then v.(!i) else failwith "non trouv" e ;; (* idem pour une liste cha^ne *) e let rec cherche_liste convient l = match l with | [] -> failwith "non trouv" e | a::suite -> if convient(a) then a else cherche_liste convient suite ;; *) *) *) *) *)

Dans les deux versions on examine successivement tous les lments de L ee jusqu en trouver un convenant. Le temps de recherche est donc proportionnel a a la position de lobjet trouv ou a la longueur de la liste si aucun lment ne e ee convient. Pour une liste ( alatoire ) de longueur n le temps de recherche est en ( e ) moyenne de n/2 appels a convient sil y a un objet convenant, et le temps dune recherche infructueuse est toujours de n appels a convient.

2-5

Insertion et suppression

Insrer un objet x dans une liste L = (a0 , .. ., an1) consiste a construire une e nouvelle liste L contenant lobjet x et tous les lments de L. Il existe plusieurs ee types dinsertion : { insertion en dbut de liste : e L = (x, a0 , .. ., an1) ; { insertion en n de liste : L = (a0 , .. ., an1, x) ; { insertion aprs le i-me lment : L = (a0 , .. ., ai1, x, ai, . . ., an1). e e ee La suppression dun objet est lopration inverse. Lorsque lordre de classee ment des lments dans L est sans importance on choisit gnralement linsertion ee e e et la suppression en dbut ou en n de liste car ces positions sont les plus accessie bles. Par contre si L est une liste trie et si lon veut que L soit aussi trie, alors e e il faut chercher dans L deux lments conscutifs encadrant x et linsrer entre ces ee e e

30

Structure de liste

lments. La suppression dans une liste trie, quant a elle, ne modie pas le caee e ractre tri. Par ailleurs si L ne doit pas comporter de rptitions il faut sassurer e e e e que x L avant de procder a une insertion, en employant lune des mthodes de / e e recherche vues prcdemment. e e Insertion et suppression a une extrmit de la liste ` e e
let ins`re_dbut_vect v x = e e let n = vect_length(v) in let w = make_vect (n+1) x in for i = 0 to n-1 do w.(i+1) <- v.(i) done; w ;; let supprime_dbut_vect v = e let n = vect_length(v) in if n = 0 then failwith "vecteur vide" else if n = 1 then [||] else begin let w = make_vect (n-1) v.(1) in for i = 2 to n-1 do w.(i-1) <- v.(i) done; w end ;; (* ins`re_fin_vect et supprime_fin_vect sont analogues *) e let ins`re_dbut_liste l x = x :: l;; e e let supprime_dbut_liste l = match l with e | [] -> failwith "liste vide" | _::suite -> suite ;; let rec ins`re_fin_liste l x = match l with e | [] -> [x] | a::suite -> a :: (ins`re_fin_liste suite x) e ;; let rec supprime_fin_liste l = match l with | [] -> failwith "liste vide" | [_] -> [] | a::suite -> a :: (supprime_fin_liste suite) ;;

2-5 Insertion et suppression

31

Remarquer que les oprations ( en n de liste cha^ ee ) imposent de parcourir e n ) ( toute la liste pour accder au dernier lment donc elles ont un temps dexcution e ee e environ proportionnel a la longueur de la liste tandis que les oprations ( en e ( dbut de liste cha^ ee ) sexcutent en temps constant. En ce qui concerne les e n ) e vecteurs, linsertion et la suppression modient la longueur du vecteur considr ee et imposent dallouer en mmoire un nouveau vecteur et dy recopier la partie utile e de lancien, donc ont un temps dexcution environ proportionnel a la longueur e du vecteur initial. Par contre si lon utilise un vecteur partiellement rempli alors linsertion et la suppression peuvent ^tre eectues ( sur place ) en temps constant e e ( ) si la position dinsertion ou de suppression est lextrmit ( libre ) du vecteur e e ( ) partiellement rempli. Concatnation e Concatner L1 = (a0 , . .., an1) et L2 = (b0 , .. ., bp1) consiste a construire e la liste (a0 , . . ., an1, b0, . .., bp1 ).
let concat_vect v1 v2 = let n1 = vect_length(v1) and n2 = vect_length(v2) in if (n1 = 0) & (n2 = 0) then [| |] else begin let x = if n1 > 0 then v1.(0) else v2.(0) in let w = make_vect (n1 + n2) x in for i = 0 to n1-1 do w.(i) <- v1.(i) done; for i = 0 to n2-1 do w.(i+n1) <- v2.(i) done; w end ;; let rec concat_liste l1 l2 = match l1 with | [] -> l2 | a::suite -> a :: (concat_liste suite l2) ;;

La fonction concat_vect comporte une dicult technique car on doit fournir e a make_vect un lment servant a initialiser le vecteur cr, m^me quand la longueur ee ee e n1 +n2 est nulle. On utilise pour cela le premier lment de lun des deux vecteurs ee v1 ou v2 sil en existe, et on cre explicitement un vecteur vide dans le cas conee traire. Le temps dexcution de concat_vect est environ proportionnel a la somme e des longueurs des vecteurs a concatner ; le temps dexcution de concat_liste e e est environ proportionnel a la longueur de L1 . La bibliothque standard de caml e comporte des fonctions de concatnation notes concat_vect et @ (oprateur inxe) e e e codes sensiblement de la m^me manire que celles donnes ci-dessus. e e e e

32

Structure de liste

2-6

Exercices

Exercice 2-1 : maximum dune liste Ecrire une fonction maximum qui renvoie le plus grand lment dun vecteur entier. ee M^me question avec une liste cha^ ee. e n Exercice 2-2 : itration sur une liste e La fonctionnelle caml standard do_list prend en argument une fonction f et une liste l = [a0; . ..; an1] et calcule dans cet ordre les expressions f(a0 ), f(a1 ), .. . , f(an1 ) (sans conserver les rsultats). Ecrire une fonctionnelle do_list_rev telle e que do_list_rev f [a0; . ..; an1] calcule successivement les expressions f(an1 ), . . . , f(a1 ), f(a0 ). Exercice 2-3 : image miroir Soit L = (a0 , a1, . .., an1) une liste. Limage miroir de L est L = (an1, . .., a0). La bibliothque standard de caml comporte une fonction rev calculant limage e miroir dune liste. Donner deux implmentations possibles en caml de rev, une e utilisant la concatnation en queue @ et une utilisant la concatnation en t^te ::. e e e Dterminer les complexits asymptotiques de ces deux implmentations. e e e Exercice 2-4 : rotation dune liste Soit L = (a0 , .. ., an1) une liste et k [[1, n 1]]. On veut faire tourner L de k positions vers la gauche pour obtenir la liste L = (ak , . .., an1, a0, . . ., ak1). 1. Donner des algorithmes rsolvant ce problme pour une liste cha^ ee et pour e e n un vecteur ; tudier leurs complexits asymptotiques. e e 2. Dans le cas dun vecteur, on peut eectuer une rotation sur place cest--dire a sans utiliser de deuxime vecteur, le vecteur initial tant alors perdu. Ecrire e e un programme ralisant une telle rotation. e 3. Le professeur Tournesol a prsent le programme suivant : e e
let rotation v k = (* fait tourner v de k positions vers la gauche *) let n = vect_length v and compte = ref 0 and i0 = ref 0 in while !compte < n do let temp = v.(!i0) and i = ref !i0 and j = ref((!i0 + k) mod n) in while !j <> !i0 do v.(!i) <- v.(!j); i := !j; j := (!i + k) mod n; compte := !compte + 1 done; v.(!i) <- temp;

2-6 Exercices compte := !compte + 1; i0 := !i0 + 1 done ;;

33

Malheureusement, il a oubli de rdiger les commentaires permettant de come e prendre son programme. Pourriez vous laider ? Indication : le faire tourner a la main sur quelques exemples, tudier le cas particulier o k est un di e u viseur de n, puis le cas gnral. Voyez vous un intr^t a ce programme ? e e ee Exercice 2-5 : recherche dun lment dans une liste ee Un prdicat est une fonction retournant un rsultat boolen, true si le ou les are e e guments passs vrient un certain critre, false sinon. Etant donns un prdicat e e e e e f a un argument et une liste cha^ ee l on veut dterminer si l contient au moins n e un lment satisfaisant le critre dni par f, et le cas chant retourner le dernier ee e e e e lment de l satisfaisant ce critre. Ecrire des fonctions caml contient et dernier ee e rsolvant ces problmes. e e Exercice 2-6 : recherche dune sous-liste Soient A = (a0 , . . ., an1) et B = (b0 , .. ., bp1) deux listes dont les lments ee ont m^me type, B tant non vide. On dsire savoir si B est une sous-liste de A, e e e cest--dire sil existe i tel que B = (ai , . .., ai+p1 ). Ecrire des fonctions caml a cherche_sous_liste et cherche_sous_vect qui rpondent a cette question pour des e listes cha^ ees ou pour des vecteurs et renvoient le rang de la premire apparition n e de B dans A sil y en a une. Exercice 2-7 : listes a double entre ` e Une liste a double entre est une structure de donnes permettant de reprsenter e e e une liste L = (a0 , . . ., an1) et deectuer en temps constant les oprations dine sertion en t^te et en queue et lextraction du premier ou du dernier lment de la e ee liste. Les listes a double entre ne sont pas prdnies en caml mais elles peuvent e e e ^tre implmentes par des vecteurs circulaires cest--dire des vecteurs dont les e e e a deux extrmits sont conceptuellement ( relies ) . Une liste occupe un segment e e ( e ) de ce vecteur dni par son indice de dbut et son indice de n, ou mieux, par e e son indice de dbut et sa longueur eective (on peut ainsi distinguer une liste vide e dune liste pleine).
partie occupe e ... ..... .... ... ..... .... ... ..... .... ... ..... .... ... ..... .... ... ..... .... .... ..... ... .... ..... ... .... ..... ... .... ..... ... .... ..... ... .... ..... ... ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... ..
lg dbut e

fin

.. ..... .... . .. ..... .... . .. ..... .... . .. ..... .... . .. ..... .... . .. ..... .... .

partie occupe e
fin

partie occupe e ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... .. ..... ..... ..
lg dbut e

.... ..... ... .... ..... ... .... ..... ... .... ..... ... .... ..... ... .... ..... ...

Donner les dclarations en caml pour ce type de donnes et les programmes e e associs eectuant les oprations dinsertion en t^te et en queue et dextraction e e e du premier et du dernier lment. ee

Chapitre 3 Listes tries e

Une relation de comparaison sur un ensemble E est une relation binaire sur E rexive, transitive et telle que pour deux lments quelconques a, b de e ee E lune au moins des relations a b ou b a est vraie. On dit que a et b sont quivalents pour e si lon a a la fois a b et b a, ce qui est not a b. e Une relation dordre total est une relation de comparaison pour laquelle chaque lment nest quivalent qu lui-m^me. ee e a e Par exemple un dictionnaire peut ^tre vu comme un ensemble de dnitions, e e une dnition tant un couple (nom,texte) de cha^ e e nes de caractres : le nom que e lon dnit et la dnition proprement dite. Lordre alphabtique sur les noms e e e est une relation de comparaison sur les objets du dictionnaire, cest une relation dordre totale si chaque nom na quune seule dnition. e Une liste L = (a0 , . . ., an1) dlments de E est dite trie selon si lon a ee e ai ai+1 pour tout i compris entre 0 et n 2. Les listes tries permettent de e reprsenter des parties dun ensemble totalement ordonn avec la proprit que e e ee deux parties sont gales si et seulement si les listes associes le sont. e e

3-1

Insertion dans une liste trie e

Soit L une liste trie par ordre croissant pour une relation de comparaison . e On veut insrer un objet x ( a la bonne place ) dans L pour que la nouvelle liste e ( ) soit encore trie. Lide est de chercher x dans L pour dterminer a quelle place il e e e doit ^tre insr, puis de procder a linsertion. On suppose disposer dune fonction e ee e compare telle que compare a b renvoie lun des rsultats PLUSGRAND lorsque a b, e PLUSPETIT lorsque a b et EQUIV lorsque a b o PLUSGRAND, PLUSPETIT et EQUIV u sont des constantes symboliques introduites par la dnition suivante : e

3-2 Recherche dans une liste trie e (* rsultat dune comparaison *) e type cmp_res = PLUSGRAND | PLUSPETIT | EQUIV;; (* insertion dans un vecteur tri *) e let ins`re_vect compare v x = e let n = vect_length(v) in let w = make_vect (n+1) x in (* recopie les elments de v infrieurs a x *) e e ` let i = ref(0) in while (!i < n) & (compare v.(!i) x = PLUSPETIT) do w.(!i) <- v.(!i); i := !i + 1 done; (* recopie la fin de v (x est dj` en place) *) e a while !i < n do w.(!i+1) <- v.(!i); i := !i + 1 done; w ;; (* insertion dans une liste cha^ne trie *) e e let rec ins`re_liste compare l x = match l with e | [] -> [x] | a::suite -> match compare a x with | PLUSPETIT -> a :: (ins`re_liste compare suite x) e | _ -> x :: l ;;

35

Temps dinsertion : le temps dinsertion dans un vecteur tri de longueur n est e O(n) puisquil faut recopier tout le vecteur. Le temps dinsertion dans une liste trie de longueur n est approximativement proportionnel au nombre dlments e ee de l infrieurs a x, cest aussi O(n) dans le pire des cas. e

3-2

Recherche dans une liste trie e

Considrons le problme de la recherche dun objet x dans une liste L trie par e e e valeurs croissantes pour une relation dordre total . Lalgorithme de recherche vu au chapitre prcdent peut ^tre modi pour interrompre la recherche ds que e e e e e lon rencontre un lment ai de L tel que ai x. En eet dans ce cas x ne peut ee pas gurer dans L aprs ai puisque L est trie par valeurs croissantes, donc on e e est s^r que x L. Cette amlioration ne diminue que le temps des recherches u / e infructueuses : pour une liste alatoire de longueur n, le temps moyen dune e recherche infructueuse passe de n comparaisons pour une liste quelconque a n/2

36

Listes tries e

comparaisons pour une liste trie. Une autre amlioration consiste a rechercher e e x dans L par dichotomie : on divise L = (a0 , . .., an1) en deux sous-listes L1 = (a0 , . . ., ai1), L2 = (ai+1 , .. ., an1) spares par un lment ai puis on e e ee compare x a ai : { si ai x, soit x L, soit x L2 ; / { si ai x, soit x L, soit x L1 ; / { si ai x, alors x L et on la trouv. e Dans les deux premiers cas on itre la mthode de dichotomie a la sous-liste L1 ou e e L2 qui a t dtermine. ee e e
(* Recherche si lobjet x figure dans le vecteur tri v. e (* Si oui, renvoie un indice de x dans v, (* sinon l`ve lexception "non trouv". e e (* "compare" est la fonction dfinissant la relation dordre. e let dichotomie compare v x = let a = ref 0 and b = ref (vect_length(v)-1) and trouv = ref false in e *) *) *) *)

while (!a <= !b) & not(!trouv) do e (* x na pas encore et trouv, et sil appartient a v *) e e ` (* alors son indice est compris entre a et b inclus. *) let c = (!a + !b)/2 in match (compare v.(c) x) with | PLUSGRAND -> b := c - 1 | PLUSPETIT -> a := c + 1 | EQUIV -> trouv := true; a := c e done; if !trouv then !a else failwith "non trouv" e e ;;

Preuve de lalgorithme : le commentaire plac dans dans la boucle while nonce e e un invariant de boucle en entre. Vrions sa validit. e e e { Au dbut, x nest pas encore trouv et sil appartient a v alors son indice est e e a compris entre 0 et vect length(v) 1, cest--dire entre a et b.
e { Si la proprit est vrie au dbut de la kme itration, et sil y a une (k+1)ee e e e e me itration alors : e e

1. Lindice c calcul est eectivement compris entre a et b que a + b soit e pair ou impair, 2. Les deux premiers cas du match modient a ou b sans changer le fait que x, sil appartient a v, se trouve entre les objets dindices a et b de v. { La boucle while se termine ncessairement car tant que x nest pas trouv la e e quantit b a dcro^ strictement a chaque itration. En eet, e e t e

3-3 Fusion de listes tries e

37

si a + b = 2p alors c = p = (a + b)/2 donc : (c 1) a = b (c + 1) = (b a)/2 1 < b a ; si a + b = 2p + 1 alors c = p = (a + b 1)/2 donc : (c 1) a = (b a 3)/2 < b a; b (c + 1) = (b a 1)/2 < b a.

{ Quand la boucle est termine, si trouv vaut true alors x a t trouv e e ee e (troisime cas du match) et son indice est a tandis que si trouv vaut false e e alors on a a > b donc il nexiste aucun lment de v dindice compris entre ee a et b dans cet ordre et en particulier x v. / Remarque : si v comporte plusieurs lments gaux a x alors dichotomie en trouve ee e un, mais on ne sait pas si cest le premier, le dernier ou un autre. Temps dexcution : notons n la longueur de v et ak , bk les valeurs de a, b e e au dbut de la kme itration de la boucle while : on a b1 a1 + 1 = n et tant e e que la boucle continue : bk+1 ak+1 + 1 (bk ak + 1)/2 daprs les calculs e prcdents. Donc par rcurrence on a bk ak + 1 e e e n/2k1 sil y a au moins k itrations, mais bk ak + 1 e 1 donc 2k1 n cest--dire k a log2(n) + 1. Ainsi, le nombre de comparaisons eectues, qui est gal au nombre ditrations, e e e est au plus gal a log 2(n) + 1 que x appartienne a v ou non. Ce minorant est e dailleurs atteint si x est strictement plus grand que le dernier lment de v car ee on a alors par rcurrence ak = (n + 1)(1 21k) et bk = n 1 au dbut de la e e e kme itration, donc ak e n 1/n = bk tant que 2k1 n. Lorsque n est grand on a log2 (n) + 1 = o(n) donc la mthode de recherche e dichotomique est bien plus ecace que la recherche dans une liste non trie. Voici e par exemple quelques valeurs du nombre maximal de comparaisons eectues en e fonction de n : n log2 (n) + 1 10 100 1000 10000 4 7 10 14

3-3

Fusion de listes tries e

Etant donnes deux listes L1 = (a0 , . .., an1) et L2 = (b0 , .. ., bp1 ) dobjets e de m^me type tries par ordre croissant pour une relation de comparaison , on e e veut constituer la liste L forme de tous les lments de L1 et L2 , trie elle aussi e ee e par ordre croissant. Lopration passant de (L1 , L2) a L est appele fusion de L1 e e et L2 dans L. La fusion appara^ dans certains algorithmes de tri, mais aussi dans t le cas de mise a jour de chiers tris : par exemple on peut vouloir fusionner les e listes des lves de deux classes pour obtenir la liste de tous les lves de ces deux ee ee classes.

38

Listes tries e

La mthode gnrale de fusion consiste a comparer les t^tes de L1 et L2, a0 e e e e et b0 , et a placer en t^te de L le plus petit de ces lments. Si cest a0 alors il e ee reste a fusionner la queue de L1 avec L2 , si cest b0 alors il reste a fusionner L1 avec la queue de L2 . Fusion de vecteurs
(* fusionne les deux vecteurs tris v1 et v2 dans v *) e (* "compare" est la fonction de comparaison. *) let fusion_vec compare v1 v2 v = let i = ref 0 and j = ref 0 and k = ref 0 in (* indice de v1 *) (* indice de v2 *) (* indice de v *)

while (!i < vect_length(v1)) & (!j < vect_length(v2)) do match compare v1.(!i) v2.(!j) with | PLUSGRAND -> v.(!k) <- v2.(!j); k := !k+1; j := !j+1 | _ -> v.(!k) <- v1.(!i); k := !k+1; i := !i+1 done; (* ici, un des deux vecteurs est epuis *) e (* on recopie la fin de lautre *) while !i < vect_length(v1) do v.(!k) <- v1.(!i); k := !k+1; i := !i+1 done; while !j < vect_length(v2) do v.(!k) <- v2.(!j); k := !k+1; j := !j+1 done ;;

Preuve du programme On dmontre par une rcurrence immdiate la proprit : e e e ee a lentre de la premire boucle while, les lments v1.(0 .. !i 1) et e e ee v2.(0 .. !j 1) sont les !k plus petits lments de v1 v2 et ont t placs ee ee e dans le bon ordre dans v.(0 .. !k 1). La boucle sarr^te quand !i vect length(v1) ou !j vect length(v2) ce e qui se produit en un nombre ni dtapes car lune des quantits !i ou !j augmente e e dune unit a chaque itration. A la n de la boucle un au moins des vecteurs v1 e e ou v2 a t transfr entirement dans v (et un seulement si v1 et v2 ne sont pas ee ee e initialement vides, car la boucle ne place dans v quun seul lment a la fois). Les ee deux boucles while suivantes recopient sil y a lieu la n de lautre vecteur a la n de v (au plus une de ces deux boucles est eectivement excute). e e

3-4 Tri dune liste

39

Temps dexcution e La premire boucle while eectue une comparaison entre un objet de v1 et e un objet de v2 a chaque fois quelle place un objet dans v. Les deux autres boucles neectuant pas de comparaisons, le nombre total de comparaisons eectues, e Ncomp, vrie : e min( 1 , 2) Ncomp 1+ 21 o 1 et 2 dsignent les longueurs des vecteurs v1 et v2 . Ces deux bornes peuvent u e ^tre atteintes : Ncomp = min( 1 , 2) lorsque le plus court des deux vecteurs vient e entirement avant lautre dans v, et Ncomp = 1 + 2 1 lorsque le dernier lment e ee dun vecteur est strictement compris entre les deux derniers lments de lautre. ee Nombre de transferts : un transfert est la copie dun objet dun vecteur dans un autre. Comme chaque lment de v est plac par un seul transfert, le nombre total ee e de transferts eectus est Ntransf = 1 + 2 . e Le temps dexcution dune itration de la premire boucle while est la somme e e e des temps dune comparaison, dun transfert et de la gestion des variables i, j, k. En caml le temps dun transfert est constant puisque le transfert se rsume a e une copie de pointeur. Ainsi, en supposant que compare a un temps dexcution e born, on voit que le temps de fusion de deux vecteurs de longueurs 1 et 2 est e O( 1 + 2 ). Fusion de listes cha ees n
(* fusionne les listes l1 et l2. *) (* "compare" est la fonction de comparaison. *) let rec fusion_liste compare l1 l2 = match (l1,l2) with | ([], _) -> l2 | (_, []) -> l1 | ((a::suite1),(b::suite2)) -> match compare a b with | PLUSGRAND -> b :: (fusion_liste compare l1 suite2) | _ -> a :: (fusion_liste compare suite1 l2) ;;

Temps dexcution : chaque appel a fusion_liste ( place ) un lment dans la liste e ( ) ee rsultat en cours de construction par une comparaison et une concatnation en e e t^te, donc le temps de fusion de deux listes L1, L2 de longueurs 1 , 2 est O( 1 + 2 ) e si lon suppose que compare a un temps dexcution born. e e

3-4

Tri dune liste

Soit L = (a0 , . . ., an1) une liste dlments comparables. Trier L consiste ee a construire une liste L trie contenant les m^mes lments que L, en conservant e e ee les rptitions. Trier sur place un vecteur consiste a permuter les lments du e e ee vecteur de sorte quils forment une liste trie, en utilisant une mmoire auxiliaire e e de taille borne (indpendante de la taille du vecteur a trier). e e

40

Listes tries e

Les algorithmes usuels de tri se rangent en deux catgories : e { tri en temps quadratique : le temps de tri est asymptotiquement proportionnel au carr de la taille de la liste a trier (tri a bulles) ; e { tri en temps quasi linaire : le temps de tri dans le pire des cas ou en moyenne e est asymptotiquement proportionnel a n ln(n) o n est la taille de la liste a u trier (tri par fusion, quicksort). Un algorithme de tri par comparaisons est un algorithme de tri dans lequel il nest eectu que des comparaisons entre lments pour dcider quelle permutae ee e tion de la liste L doit ^tre ralise. On dmontre quun tel algorithme doit eectuer e e e e au moins log2 (n!) n log2(n) comparaisons pour trier une liste quelconque de longueur n (cf. section 7-4). Un algorithme de tri par comparaisons ne peut donc avoir une complexit dans le pire des cas ngligeable devant n ln(n). Le tri par e e fusion atteint cette complexit minimale si lon suppose que le temps dune come paraison est constant (constant signie ici indpendant de n) ; on dit que cest un e algorithme de tri optimal. En ce qui concerne la complexit moyenne, on dmontre que le nombre moyen e e de comparaisons eectues par un algorithme de tri par comparaisons est suprieur e e ou gal a log2 (n! 1) lorsque la moyenne est calcule sur les n! permutations des e e lments dun ensemble totalement ordonn de cardinal n (cf. exercice 7-19). ee e La complexit moyenne dun algorithme de tri par comparaisons ne peut donc, e elle non plus, ^tre ngligeable devant n ln(n) dans ce modle dquirpartition e e e e e des permutations. Le tri par fusion et le quicksort atteignent cette complexit e en moyenne lorsque le temps dune comparaison est constant, ce sont des tris optimaux en moyenne. Par ailleurs il existe des algorithmes de tri ne procdant pas par comparaie sons, et donc pour lesquels les minorations de complexit prcdentes ne sont pas e e e applicables. En particulier, le tri par distribution est un algorithme de tri ayant un temps dexcution approximativement proportionnel a la taille de la liste a e trier (cf. le problme ( Tri par distribution ) dans la partie ( Problmes ) ). e e ( ) ( ) Un algorithme de tri est dit stable si la disposition relative des lments ee quivalents dans L est conserve dans L . Par exemple, si lon dispose dune liste e e alphabtique des lves de la classe que lon veut trier par moyenne dcroissante, e ee e il est souhaitable que des lves ayant m^me moyenne restent classs par ordre ee e e alphabtique pour ne pas faire de jaloux. Remarquons que lon peut toujours e rendre stable un algorithme de tri en dnissant la fonction de comparaison de e telle sorte quelle tienne compte des indices des objets quelle compare lorsquils sont quivalents (ceci peut ^tre obtenu en ajoutant a chaque objet un champ e e contenant son indice initial).

3-5 Tri a bulles

41

3-5

Tri ` bulles a

On parcourt la liste a trier en examinant si chaque couple dlments cons ee e cutifs, (ai , ai+1 ), est dans le bon ordre (ai ai+1 ) ou est mal class (ai ai+1 ). e Dans ce dernier cas on change les lments du couple et le processus est rpt e ee e ee tant quil reste des couples mal classs. e
(* trie le vecteur v par ordre croissant *) (* compare est la fonction de comparaison *) let tri_bulles compare v = let fini = ref false in while not !fini do fini := true; (* esprons *) e

for i = 0 to vect_length(v)-2 do if (compare v.(i) v.(i+1)) = PLUSGRAND then begin (* un couple est mal class, echange les elments *) e e let x = v.(i) in v.(i) <- v.(i+1); v.(i+1) <- x; fini := false (* il faut refaire une passe *) end done (* for i *) done ;; (* while not !fini *)

Preuve de lalgorithme : notons Ninv le nombre de couples (i, j) tels que i < j et ai aj (Ninv est le nombre dinversions du vecteur v) et examinons une itration de la boucle while : e { sil existe un indice i tel que ai ai+1 alors ces lments sont changs et ee e e fini est mis a false donc le nombre dinversions diminue dune unit et le e test de n de boucle sera ngatif ; e { si pour tout i on a ai ai+1 alors v est tri et fini garde la valeur true tout e au long de la boucle, donc cette itration est la dernire. e e Donc lalgorithme ne sarr^te que lorsque le vecteur est tri, et il sarr^te ncessaie e e e rement puisque Ninv diminue strictement a chaque itration tant que le vecteur e nest pas tri. e On peut prouver larr^t dune autre manire en vriant par rcurrence que, e e e e e a la n de la kme itration de la boucle while, les k derniers lments de v e ee sont les k lments les plus grands et sont placs dans lordre croissant. Il en ee e rsulte que le nombre ditrations est major par la longueur de v. Par ailleurs, e e e

42

Listes tries e

on peut remplacer la borne vect_length(v)-2 de la boucle for par une borne variable, initialise a vect_length(v)-2 et dcrmente dune unit a la n de e e e e e chaque itration de la boucle while. e Temps dexcution : le temps total pass dans le bloc begin ... end est environ e e proportionnel au nombre dchanges et on a remarqu que chaque change diminue e e e dune unit le nombre dinversions, donc il y a exactement Ninv changes eectus, e e e et Ninv C2 (nombre de couples (i, j) tels que i < j). Le nombre dappels a la n fonction compare est gal au produit de n 1 par le nombre ditrations donc est e e major par n(n 1). Ces majorants sont atteints quand le vecteur v est ( tri e ( e a lenvers ) cest--dire quand ai a ai+1 pour tout i. Par consquent le temps e ) dexcution maximal est O(n2 ) en supposant que compare a un temps dexcution e e born. e Stabilit : soient ai aj avec i = j. A chaque change la distance entre ai e e et aj ne peut diminuer que dune unit au plus, et si ces lments deviennent e ee adjacents alors ils ne peuvent ^tre changs puisquun change porte toujours e e e e sur des lments non quivalents. Donc la disposition relative de ai et aj reste ee e constante au cours du tri ; lalgorithme de tri a bulles est stable. Complexit spatiale : la fonction tri_bulles utilise seulement trois variables e locales (fini, i et j) donc le tri a bulles est un tri sur place.

3-6

Tri par fusion

On divise la liste L = (a0 , .. ., an1) que lon veut trier en deux demi listes, L1 = (a0 , . . ., ap1) et L2 = (ap , .. ., an1) que lon trie sparment rcursivement, e e e puis on fusionne les deux listes tries obtenues L1 et L2. e Tri par fusion pour un vecteur
(* fusionne les sous-vecteurs tris v1(a..c) et v1(c+1..b) *) e (* dans v2(a..b). On suppose a <= c < b. *) let fusion compare v1 v2 a c b = ... (* adapter ici le code de fusion_vect donn en section 3-3 *) e ;; (* Trie par ordre croissant v1(a..b) a laide du vecteur *) ` (* auxiliaire v2. Si vers_v1 = true, le rsultat est plac *) e e (* dans v1(a..b), sinon dans v2(a..b). On suppose a <= b. *) let rec tri_partiel compare v1 v2 a b vers_v1 = if a < b then begin let c = (a+b)/2 in tri_partiel compare v1 v2 a c (not vers_v1); tri_partiel compare v1 v2 (c+1) b (not vers_v1);

3-6 Tri par fusion if vers_v1 then fusion compare v2 v1 a c b else fusion compare v1 v2 a c b end (* cas a = b : transf`re llment au besoin *) e e e else if not vers_v1 then v2.(a) <- v1.(a) ;; (* trie par ordre croissant le vecteur v *) let tri_fusion compare v = let n = vect_length(v) in if n > 1 then begin let v = make_vect n v.(0) in tri_partiel compare v v 0 (n-1) true end ;;

43

Le tri est ralis avec un vecteur auxiliaire v permettant de fusionner les e e deux sous-vecteurs qui ont t rcursivement tris. A chaque niveau de rcursion ee e e e la fusion se fait de v vers v ou de v vers v suivant la valeur de lindicateur vers_v1. Preuve de lalgorithme : on dmontre la correction de tri_partiel par rcure e rence sur n = b a + 1. Pour n = 1 on a b = a donc le sous-vecteur v1 (a .. b) est dj tri, et il est correctement plac dans v1 ou dans v2 selon la valeur de ea e e lindicateur vers_v1. Supposons que tri_partiel fournit un rsultat juste pour tous les souse vecteurs de longueur p [[1, n[[ avec n 2, et considrons le tri dun sous-vecteur e v1(a .. b) avec b = a + n 1. On a c = (a + b)/2 = a + (n 1)/2 [[a, b[[ donc les appels :
tri_partiel compare v1 v2 a c (not vers_v1); tri_partiel compare v1 v2 (c+1) b (not vers_v1);

sont licites et portent sur des sous-vecteurs de longueurs : (n 1)/2 + 1 = n/2 et n n/2 = n/2 .

Ces longueurs sont strictement infrieures a n car n 2, donc, daprs lhypothse e e e de rcurrence, les appels rcursifs trient v1(a .. c) et v1 (c + 1 .. b) en plaant le e e c rsultat dans v2 ou dans v1 selon que vers v1 = true ou vers v1 = false. La e fusion les deux sous-vecteurs obtenus fournit alors le rsultat attendu : un souse vecteur tri et plac dans le vecteur dsign par lindicateur vers_v1. Ceci achve e e e e e la dmonstration de validit. e e Temps dexcution. Le temps ncessaire pour trier un vecteur v est de la forme : e e T = Ncomp + Ntransf + Nrec

44

Listes tries e

tape v e v 1 31415 xxxxx

acb 024

31415 xxxxx

012

31415 xxxxx

001

8 9 10 6 7 3

31415 xxxxx 31415 3xxxx 31415 31xxx 13415 31xxx 13415 31xxx 13415 134xx

0 1

0 1

a faire 2: tri_partiel 3: tri_partiel 4: fusion v v false 5: tri_partiel 6: tri_partiel 7: fusion v v true 8: tri_partiel 9: tri_partiel 10: fusion v v false v (0) v(0)
vers_v1 true false

v v 0 v v 0 v v 0

v 0 v 3 2 4 v 0 v 2 1 2 v 0 v 1 0 1

2 false 4 false 1 true 2 true 0 false 1 false

001 2 2 012 334


true false

v (1) v(1)

v(0..1) fusion(v (0..0), v (1..1)) v (0..2) fusion(v(0..1), v(2..2))

11: tri_partiel v v 3 3 true 12: tri_partiel v v 4 4 true 13: fusion v v 3 3 4

11 12 13 4

13415 134xx 13415 134xx 13415 134xx 13415 13415 11345

3 3 4 4 334 024

true true

v (3..4) fusion(v(3..3), v(4..4))

v(0..4) fusion(v (0..2), v (3..4))

Figure 3 : tri par fusion du vecteur [|3; 1; 4; 1; 5|] o Ncomp est le nombre dappels a la fonction compare, Ntransf est le nombre de u transferts dun lment de lun des vecteurs v1 ou v2 dans lautre vecteur, et Nrec ee est le nombre dappels rcursifs a la fonction tri_partiel. Les coecients , , e reprsentent les dures dune comparaison, dun transfert et de la gestion des e e variables locales aux fonctions tri_partiel et fusion. Notons Ncomp(n), Ntransf (n) et Nrec (n) les valeurs maximales de Ncomp, Ntransf et Nrec pour le tri dun sous-vecteur v1(a .. b) de longueur n = b a + 1. Si n = 1 on a : Ncomp(1) = 0, Ntransf (1) = 1, Nrec (1) = 1.

Si n 2 alors on divise v1 (a .. b) en deux sous-vecteurs v1(a .. c) et v1(c + 1 .. b) de longueurs n/2 et n/2 , que lon trie rcursivement, do : e u Ncomp(n) = Ncomp( n/2 ) + Ncomp( n/2 ) + n/2 + n/2 1, Ntransf (n) = Ntransf ( n/2 ) + Ntransf ( n/2 ) + n/2 + n/2 , Nrec (n) = Nrec ( n/2 ) + Nrec ( n/2 ) + 1.

3-6 Tri par fusion

45

On en dduit, par rcurrence sur n : e e Nrec (n) = 2n 1 ; si 2k n

Ncomp(n) + Nrec (n) = Ntransf (n) ; 2k+1 alors (k + 1)n Ntransf (n) (k + 2)n.

Daprs ces relations, Ntransf (n) n log2(n), Nrec (n) = o(n log2 n) et donc e Ncomp(n) n log2(n). Finalement : le tri par fusion dun vecteur de taille n sexcute en temps O(n log2 n) e si le temps dune comparaison est constant. Stabilit : la position relative de deux lments quivalents ne peut ^tre modie e ee e e e quau cours dune fusion, et lalgorithme de fusion dcrit en section 3-3 ne permute e jamais deux lments quivalents appartenant au m^me sous-vecteur, et place ee e e en premier les lments du premier sous-vecteur en cas dquivalence avec des ee e lments du deuxime. Il en rsulte que lalgorithme de tri par fusion tel quil a ee e e t dcrit est stable. ee e Complexit spatiale : lalgorithme de tri par fusion ncessite un vecteur auxie e liaire v de longueur n et une pile de rcursion dans laquelle sont stockes les e e variables locales aux direntes instances de tri_partiel et de fusion actives. La e taille de cette pile de rcursion est proportionnelle au nombre maximum dappels e a tri_partiel imbriqus, et on voit par rcurrence sur n que ce nombre est au plus e e gal a 1 + log 2 n . Donc le tri par fusion dun vecteur de longueur n a une e complexit spatiale asymptotiquement proportionnelle a n. En particulier, le e tri par fusion nest pas un tri sur place. Tri par fusion pour une liste cha ee n
(* Dcoupe l en deux sous-listes de tailles n et lg(l)-n *) e (* Il est suppos que lg(l) >= n e *) let rec dcoupe l n = match n,l with e | 0,_ -> ([], l) | _,x::suite -> let (a,b) = dcoupe suite (n-1) in (x::a, b) e | _,_ -> failwith "cas impossible" ;; (* Trie par fusion la liste l de n elments *) e let rec tri_partiel compare l n = if n <= 1 then l else let n1 = n/2 in let n2 = n-n1 in let (l1, l2) = dcoupe l n1 in e fusion_liste compare (tri_partiel compare l1 n1) (tri_partiel compare l2 n2) ;;

46

Listes tries e (* Trie par fusion la liste l *) let tri_fusion compare l = tri_partiel compare l (list_length l) ;;

3-7

Tri rapide

Le tri rapide, aussi appel tri de Hoare, tri par segmentation, ou quicke sort, consiste a rorganiser une liste L = (a0 , . . ., an1) en trois sous-listes : e L1 = (b0 , . .., bp1 ), L2 = (a0 ), L3 = (c0 , .. ., cq1)

dont la concatnation est une permutation de L et telles que tous les lments de e ee L1 sont infrieurs ou quivalents a a0 et tous les lments de L3 sont suprieurs e e ee e ou quivalents a a0 . Pour trier L, il reste a trier sparment L1 et L3 ce que lon e e e fait rcursivement. e
(* echange les elments dindices i et j dans v *) e let echange v i j = let x = v.(i) in v.(i) <- v.(j); v.(j) <- x;; (* On suppose a < b et on note x = v.(a). (* Rorganise v(a..b) de sorte quen sortie tous les elments e e (* dindice < c soient infrieurs a x, tous ceux dindice > c e ` (* soient plus grands que x et v(c) = x. (* Retourne c en rsultat. e let segmentation compare v a b = let i = ref(a+1) and j = ref(b) and x = v.(a) in while !i <= !j do (* ici, tous les elments de v(a+1..i-1) sont <= x e (* et tous les elments de v(j+1..b) sont >= x e (* avance i et recule j tant que cette proprit e e (* reste vraie et que lon a i <= j. while (!i <= !j) & (compare x v.(!i)) <> PLUSPETIT do i := !i+1 done; while (!j > !i) & (compare x v.(!j)) <> PLUSGRAND do j := !j-1 done; (* echange les elments trouvs *) e e if !i < !j then begin echange v !i !j; i := !i+1; j := !j-1; end else if !i = !j then j := !j-1; done; (* while !i <= !j *) *) *) *) *) *) *) *) *) *)

3-7 Tri rapide

47

(* met x en place et retourne sa nouvelle position *) if a <> !j then echange v a !j; !j ;; (* trie le sous-vecteur v(a..b) par ordre croissant *) (* on suppose a < b *) let rec tri_partiel compare v a b = let c = segmentation compare v a b in if a < c-1 then tri_partiel compare v a (c-1); if c+1 < b then tri_partiel compare v (c+1) b ;; (* trie le vecteur v par ordre croissant *) let tri_rapide compare v = let n = vect_length(v) in if n >= 2 then tri_partiel compare v 0 (n-1) ;;

Preuve de correction pour la fonction segmentation : la proprit place ee e en commentaire au dbut de la boucle while !i <= !j se dmontre aisment par e e e rcurrence sur le nombre ditrations eectues. Lorsque cette boucle est termine, e e e e on a !i = !j + 1, !j a et v.(!j) x. Lchange de v.(!j) et v.(a) est donc licite e et produit les listes L1 , L2 et L3 annonces. La gure 4 illustre le tri rapide du e vecteur [|1; 4; 1; 4; 2; 1; 3; 5|]. Temps dexcution. Le temps ncessaire pour trier un vecteur v de longueur n e e avec n 2 est de la forme : T = Ncomp + Nech + Nrec o Ncomp est le nombre dappels a la fonction compare, Nech est le nombre dappels u a la fonction echange et Nrec est le nombre dappels a la fonction tri_partiel. Les coecients , , reprsentent les dures dune comparaison, dun change et de e e e la gestion des variables locales aux fonctions tri_partiel et segmentation. Chaque appel a tri_partiel pour un sous-vecteur v(a .. b) tel que a < b met a sa place dnitive au moins un lment, v(c). On a donc Nrec n. e ee Montrons par rcurrence sur n que le nombre dchanges est major par e e e Cest immdiat si n = 2. Si n > 2, soit c lindice retourn par la e e segmentation de v (avec a = 0 et b = n 1). Si 2 c n 3, alors :
1 2 n log2 (n).

Nech

c log2 (c) + (n c 1) log2 (n c 1) 2

(n 1) log2(n) 2

n log2(n) 2

par hypothse de rcurrence. On obtient la m^me ingalit lorsque c < 2 ou e e e e e c > n 3 en remplaant le terme c log2 (c) ou (n c 1) log2 (n c 1) par 0. c

48

Listes tries e

v [|1 [|1
j

action 1 1 1 1 1 1 1|] 1|]


j

4
i

1 1 1 1
i

4 4 4 4 4 4 4 4 4
i

2 2 2 2 2 2 2 2 2 2
ij

3 3 3 3 3
j

5|]
j

segmentation(0, 7) while !i <= !j done

4
i

5|] 5|] 5|]


j

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

[|4 [|4 [|4 [|4 [|3 [|3 [|3 [|3 [|3 [|3 [|2 [|2 [|2 [|2 [|1 [|1 [|1 [|1 [|1|] 1

c=0
segmentation(1, 7) while !i <= !j done echange(1, 6)

1 1 1 1
i

5|]
i

3
j

5|]
i

4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4

[|5|] 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5

c=6
segmentation(1, 5) while !i <= !j echange(3, 5) while !i <= !j done echange(1, 4)

1 1 1 1 1 1
i

1|]
j

1 1 1 1|] 1|]
j

4|] 4|]
i

2
j

2
j

4|]
i

3 3 3
i

[|4|] 4 4 4 4 4 4 4 4 4

c=4
segmentation(1, 3) while !i <= !j done echange(1, 3)

1 1 1|] 1|]
ij

1|]
j

1|]
j

3
i

2[| |] 3 2 2
i

c=3
segmentation(1, 2) while !i <= !j done echange(1, 2)

3 3 3 3 3

1|]
j

1|]
j

2
i

1[| |] 2 1 2

c=2

Figure 4 : tri rapide du vecteur [|1; 4; 1; 4; 2; 1; 3; 5|]

3-7 Tri rapide

49

En remarquant que segmentation eectue n 1 appels a compare pour un vecteur de longueur n, on montre de m^me que Ncomp 1 n(n 1). Ce majorant e 2 est atteint, entre autres, lorsque le vecteur v est dj tri : en eet dans ce cas, la ea e segmentation de v compare v(0) aux n 1 autres lments de v et retourne c = 0, ee donc on est ramen au tri du sous-vecteur v(1 .. n 1) lui aussi dj tri. e ea e En conclusion, le tri rapide dun vecteur de taille n sexcute en temps e O(n2) si le temps dune comparaison est constant, et cette complexit e quadratique est atteinte lorsque le vecteur est dj tri. ea e Ainsi le tri rapide nest pas particulirement rapide si lon considre la come e plexit dans le pire des cas. Cependant, on montre que pour une liste ( alatoire ) e ( e ) de n lments distincts, le nombre moyen de comparaisons eectues est de lordre ee e de 2n ln(n) 1.4n log2 (n) (cf. exercice 8-6 et aussi [Knuth] vol. 3, p. 114). Il en rsulte que le temps moyen dexcution du tri rapide est O(n ln n) si le temps e e dune comparaison est constant. Complexit spatiale : la segmentation dun sous vecteur est eectue sur place e e puisque la fonction segmentation utilise une nombre xe de variables locales. Par contre, la fonction tri_partiel ne sexcute pas sur place du fait des ape pels rcursifs. Dans le pire des cas il peut y avoir jusqu n 1 instances de e a tri_partiel en suspens si le vecteur v est initialement tri a lenvers (cest--dire e a v(i) v(i + 1) pour tout i), donc la complexit mmoire de tri_rapide dans le e e pire des cas est asymptotiquement proportionnelle a n. Lexercice 3-12 montre que lon peut eectuer un tri rapide avec O(ln n) units de mmoire auxiliaire e e seulement, en ordonnant convenablement les appels rcursifs a tri_partiel. En e tout tat de cause, le tri rapide nest pas un tri sur place. e Stabilit : lexemple du tri de [|1; 4; 1; 4; 2; 1; 3; 5|] montre que le tri rapide nest e pas stable (les deux 4 sont intervertis). On peut le rendre stable en utilisant un vecteur dindexation, cest--dire un vecteur p a lments entiers dans lequel on a ee calcule une permutation de [[0, n 1]] telle que la liste (v.(p.(0)), . . ., v.(p.(n 1))) soit trie, avec conservation de la disposition relative des lments quivalents. e ee e Le vecteur p sobtient en triant la permutation identit avec une fonction de e comparaison entre indices qui compare les lments de v ayant ces indices, puis ee compare les indices en cas dquivalence. e
(* Calcule une permutation p telle que la liste (* [v(p(0)), .., v(p(n-1))] est trie par ordre e (* croissant. En cas dquivalence, utilise les e (* indices des elments pour les dpartager. e e let tr_stable compare v = let n = vect_length(v) in let p = make_vect n 0 in for i = 1 to n-1 do p.(i) <- i done; let comp x y = match compare v.(x) v.(y) with | EQUIV when x < y -> PLUSPETIT *) *) *) *)

50 | EQUIV when x > y -> PLUSGRAND | res -> res in tri_rapide comp p; p ;;

Listes tries e

Avec cette mthode, on obtient un algorithme de tri stable qui ne modie e pas le vecteur a trier, ce qui peut ^tre intressant dans certaines applications. e e

3-8

Exercices

Exercice 3-1 : insertion sans rptition e e Modier les fonctions ins`re_vect et ins`re_liste prsentes a la section 3-1 pour e e e e quelles ne procdent pas a linsertion si le vecteur ou la liste fourni contient dj e ea un lment quivalent a x. ee e Exercice 3-2 : fusion sans rptition e e Programmer en caml les oprations de fusion sans rptition pour des listes e e e cha^ ees et pour des listes reprsentes par des vecteurs (on supposera que les n e e listes a fusionner ne comportent pas de rptitions). e e Exercice 3-3 : oprations sur les ensembles e On reprsente les parties dun ensemble totalement ordonn E par des listes tries e e e sans rptitions. Comment peut-on raliser ecacement les oprations de runion, e e e e e intersection, dirence et dirence symtrique ? e e e Exercice 3-4 : polynmes creux o On reprsente les polyn^mes a une variable a coecients entiers par des listes e o cha^ ees de mon^mes, un mon^me aXe tant reprsent par le couple dentiers n o o e e e (a, e). Les mon^mes dun polyn^me sont classs par degr croissant et chaque o o e e mon^me a un coecient a = 0. Ecrire une fonction daddition de deux polyn^mes o o pour cette reprsentation. e Exercice 3-5 : fusion multiple Etudier les problmes suivants (on cherchera a minimiser le temps dexcution e e compt en nombre maximal de comparaisons eectues) : e e 1. Fusion de trois listes tries, L1, L2 , L3 . e 2. Fusion de quatre listes tries, L1 , L2 , L3 , L4 . e Exercice 3-6 : tri a bulles ` Programmer lalgorithme du tri a bulles dans le cas du tri dune liste cha^ ee. n

3-8 Exercices

51

Exercice 3-7 : complexit moyenne du tri a bulles e ` On suppose que les lments dun vecteur v = [|a0, .. ., an1|] sont des entiers ee compris entre 0 et K 1 o K et n sont des constantes, et que les Kn vecteurs de u n lments sont quiprobables. Dterminer le nombre moyen dchanges eectus ee e e e e lors du tri a bulles de v. Exercice 3-8 : liste presque trie e Soit p N. On dit quune liste L = (a0 , . . ., an1) est p-presque trie a gauche e si, pour tout entier i, le nombre dindices j < i tels que aj ai est major par p. e Soit L une liste p-presque trie a gauche. e 1. Est-ce que L est aussi p-presque trie a droite, cest--dire le nombre dindices e a j > i tels que aj ai est-il major par p ? e 2. Montrer que la complexit asymptotique du tri a bulles dune liste p-presque e trie a gauche est O(np). e Exercice 3-9 : le tri de caml La bibliothque standard de caml contient la fonction de tri suivante : e
(* Merging and sorting *) let merge order = merge_rec where rec merge_rec = fun [] l2 -> l2 | l1 [] -> l1 | (h1::t1 as l1) (h2::t2 as l2) -> if order h1 h2 then h1 :: merge_rec t1 l2 else h2 :: merge_rec l1 t2 ;; let sort order l = let rec initlist = function [] -> [] | [e] -> [[e]] | e1::e2::rest -> (if order e1 e2 then [e1;e2] else [e2;e1]) :: initlist rest in let rec merge2 = function l1::l2::rest -> merge order l1 l2 :: merge2 rest | x -> x in let rec mergeall = function [] -> [] | [l] -> l | llist -> mergeall (merge2 llist) in mergeall(initlist l) ;;

Expliquer et justier le fonctionnement de sort.

52

Listes tries e

Exercice 3-10 : tri par fusion naturelle Soit L = (a0 , . .., an1) une liste dlments comparables. On appelle squence ee e croissante toute sous-liste (ai , . .., aj) trie par ordre croissant, et squence croise e sante maximale toute squence croissante qui nest pas contenue dans une autre e squence croissante. Etudier lalgorithme de tri suivant : e Pour trier L : { parcourir L en fusionnant deux par deux les squences croissantes maxie males ; { recommencer jusqu ce quil ne reste plus quune squence croissante a e maximale. Ltude consiste a crire un programme implmentant cet algorithme, a en prouver e e e la correction et a en dterminer la complexit asymptotique. e e Exercice 3-11 : tri rapide Programmer lalgorithme du tri rapide pour des listes cha^ ees. n Exercice 3-12 : drcursication du tri rapide e e Pour liminer les appels rcursifs dans le tri rapide dun vecteur, on utilise une e e liste auxiliaire dans laquelle on place les indices limites des sous-vecteurs restant a trier. Ecrire une fonction itrative eectuant le tri dun vecteur suivant cette e mthode. Montrer que la longueur de la liste auxiliaire peut ^tre majore par e e e 1 + log2 n si lon choisit de trier en premier le plus petit des sous-vecteurs produits par la phase de segmentation.

Chapitre 4 Evaluation dune formule

4-1

Structure de pile

Une pile est une liste ne permettant des insertions ou des suppressions qu a une seule extrmit, appele sommet de la pile. Empiler un objet sur une pile e e e P consiste a insrer cet objet au sommet de P, et dpiler un objet de P consiste e e a supprimer de P lobjet plac au sommet. Lobjet dpil est retourn par la e e e e fonction de dpilement pour ^tre trait par le programme. e e e sommet de la pile c b a

d empiler d d c b a dpiler e c b a

Figure 5 : fonctionnement dune pile Une proprit remarquable des piles est quun objet ne peut ^tre dpil ee e e e quaprs avoir dpil tous les objets qui sont placs ( au dessus ) de lui, ce qui e e e e ( ) fait que les objets quittent la pile dans lordre inverse de leur ordre darrive. e Pour cette raison une pile est aussi appele structure LIFO (Last In, First Out). e On peut comparer le fonctionnement dune pile a celui dun journal tldius ee e o le prsentateur donne la parole a un reporter. Le reporter rend compte de u e son enqu^te et donne a son tour la parole a un tmoin. Lorsque le tmoin a e e e ni de tmoigner, le reporter reprend la parole pour conclure et la rend enn au e prsentateur. e En informatique une pile sert essentiellement a stocker des donnes qui ne e peuvent pas ^tre traites immdiatement car le programme a une t^che plus ure e e a gente ou pralable a accomplir auparavant. En particulier les appels et retours e

54

Evaluation dune formule

de fonctions sont grs gr^ce a une pile appele pile dexcution : si au cours ee a e e de lexcution dune fonction A la machine doit excuter une fonction B alors e e elle place au sommet de la pile dexcution ladresse a laquelle le code de A est e interrompu, excute le code de B et, lorsque B est termine, reprend lexcution e e e a ladresse gurant au sommet de la pile, cest--dire l o A a t interrompue. a a u ee Ce mcanisme permet dimbriquer des fonctions thoriquement sans limitation de e e profondeur, en pratique dans les limites de la mmoire alloue a la pile dexcution. e e e La gestion des variables locales est ralise de la m^me manire en rangeant ces e e e e variables dans la pile dexcution ou dans une pile ddie. e e e Reprsentation dune pile par un vecteur e On peut reprsenter une pile en mmoire par un couple constitu dun vecteur e e e sur-dimensionn et dun entier indiquant la premire position libre sur la pile. La e e reprsentation ci-dessous utilise un record caml cest--dire un couple dont les e a deux composantes sont dsignes par les noms symboliques objet et sommet plut^t e e o que par leur position dans le couple. objet et sommet sont appels champs du e record. Le champ sommet est dclar mutable ce qui signie quon peut le modier e e sur place.
type a v_pile = {objet:a vect; mutable sommet:int};; (* cration dune pile vide de taille maximale n e *) (* x est un objet du type de ceux qui seront empils *) e let cre_pile n x = {objet = make_vect n x; sommet = 0};; e (* empile x *) let empile pile x = if pile.sommet >= vect_length(pile.objet) then failwith "pile pleine" else begin pile.objet.(pile.sommet) <- x; pile.sommet <- pile.sommet+1 end ;; (* dpile le sommet de pile et le retourne comme rsultat *) e e let dpile pile = e if pile.sommet <= 0 then failwith "pile vide" else begin pile.sommet <- pile.sommet-1; pile.objet.(pile.sommet) end ;; (* dit si la pile est vide *) let est_vide pile = (pile.sommet = 0);;

4-2 Reprsentation linaire dune formule e e

55

Reprsentation dune pile par une liste cha ee e n On peut aussi reprsenter une pile par une rfrence sur liste cha^ ee, le e ee n sommet de la pile tant la t^te de la liste. e e
type a ch_pile == a list ref;; (* cration dune pile vide *) e let cre_pile() = ref [];; e (* empile x *) let empile pile x = pile := x :: !pile;; (* dpile le sommet de pile et le retourne comme rsultat *) e e let dpile pile = match !pile with e | [] -> failwith "pile vide" | a::suite -> pile := suite; a ;; (* dit si la pile est vide *) let est_vide pile = !pile = [];;

4-2

Reprsentation linaire dune formule e e

Une formule mathmatique peut ^tre reprsente linairement de trois mae e e e e nires : e { forme inxe : les oprateurs binaires sont placs entre leurs arguments, des e e parenthses peuvent imposer un ordre dexcution des oprations ; e e e { forme prxe : tous les oprateurs sont placs avant leurs arguments ; e e e { forme postxe : tous les oprateurs sont placs aprs leurs arguments. e e e Par exemple la formule : 3 + 2 36 6 / 6

est reprsente sous .. . e e forme inxe : ( 3 + 2 sqrt ( 36 ) ) forme prxe : / + 3 2 sqrt 36 6 e forme postxe : 3 2 36 sqrt + 6 /

Formellement une formule est reprsente par une suite de lexmes, un e e e lexme tant un nombre, un oprateur unaire, un oprateur binaire ou une pae e e e renthse. La valeur dune formule est dnie rcursivement a laide de rgles e e e e de rduction remplaant une partie de la formule par sa valeur. En notant x, y e c des nombres, f1 un oprateur unaire, f2 un oprateur binaire, f1 [x] et f2 [x, y] les e e rsultats des applications de ces oprateurs, on a les rgles de rduction suivantes : e e e e

56

Evaluation dune formule

rductions dune formule inxe e ( x ) x f1 x f1 [x] x f2 y f2 [x, y] rductions dune formule prxe e e f1 x f1 [x] f2 x y f2 [x, y] rductions dune formule postxe e x f1 f1 [x] x y f2 f2 [x, y] Une suite quelconque de lexmes, f, constitue une formule inxe, prxe ou e e postxe correcte si et seulement si elle peut ^tre rduite en un nombre a laide e e des rgles prcdentes. Dans le cas des formules prxes ou postxes le nombre e e e e obtenu est indpendant de la suite de rductions utilise (cf. exercice 4-1) et est la e e e valeur de f. Dans le cas des formules inxes le nombre obtenu dpend de la suite e de rductions utilise, la valeur dune formule inxe est rendue non ambigue par e e utilisation de rgles de priorit et dassociativit interdisant certaines rductions. e e e e

4-3

Evaluation dune formule postxe

Une formule postxe peut ^tre value a laide dune pile par lalgorithme e e e suivant : { initialiser la pile a vide et parcourir la formule ( de gauche a droite ) ; ( )

{ a chaque fois que lon trouve une valeur, empiler cette valeur ; { a chaque fois que lon trouve un oprateur unaire f, dpiler le sommet e e de la pile, soit x, et empiler la valeur f[x] ; { a chaque fois que lon trouve un oprateur binaire g, dpiler les deux e e valeurs au sommet de la pile, soit x, y avec x dpile en premier, et e e empiler la valeur g[y, x] ; { lorsque le parcours de la formule est termin, la pile ne contient plus e quune valeur qui est la valeur de la formule. Par exemple la formule postxe : 3 2 36 sqrt + est value selon les tapes : e e e 6 /

4-3 Evaluation dune formule postfixe

57

pile [ [ [ [ [ [ [ [ [ ] 3] 3 3 3 3 15 ] 2.5 ] 2.5 ]

formule 3 2 36 sqrt 2 36 sqrt 36 sqrt + sqrt + 6 + 6 / + 6 / 6 / / + 6 / + 6 / 6 / /

2] 2 36 ] 2 6] 12 ]

On prouve la validit de cet algorithme en remarquant qu chaque tape la e a e concatnation de la pile et du reste de la formule est une formule dduite de la e e formule initiale selon les rgles de rduction des formules postxes. Le nombre e e dtapes est gal a la longueur de la formule initiale, il est donc ni. Enn, si la e e formule initiale est une formule postxe correcte, alors la formule nale obtenue est une formule postxe correcte constitue uniquement de valeurs, donc elle contient e une seule valeur qui est la valeur de la formule initiale.
(* elments syntaxiques dune formule portant *) e (* sur des valeurs de type a *) type a lex`me = e | VALEUR of a | OP_UNAIRE of a -> a | OP_BINAIRE of a -> a -> a ;; (* evalue une formule postfixe *) let evalue formule = let pile = cre_pile() (* pile conservant les valeurs en attente *) e and reste = ref(formule) (* reste de la formule *) in while !reste <> [] do (* traite un lex`me : si cest une valeur, lempile *) e (* si cest un oprateur, effectue lopration et e e *) (* empile le rsultat. e *) begin match hd(!reste) with | VALEUR a -> empile pile a | OP_UNAIRE f -> let x = dpile pile in empile pile (f x) e | OP_BINAIRE g -> let x = dpile pile in e let y = dpile pile in empile pile (g y x) e end; reste := tl(!reste) (* retire le lex`me trait *) e e done;

58

Evaluation dune formule (* normalement, la pile ne contient plus que le rsultat *) e let v = dpile pile in e if est_vide(pile) then v else failwith "pile non vide" ;; (* Exemple *) evalue [ VALEUR VALEUR VALEUR OP_UNAIRE OP_BINAIRE OP_BINAIRE VALEUR OP_BINAIRE ;; - : float = 2.5

3.0; 2.0; 36.0; sqrt; mult_float; add_float; 6.0; div_float ]

En prsence dune formule incorrecte, evalue et dclenche lerreur "pile e e vide" sil manque un argument a un oprateur, et lerreur "pile non vide" sil e y a plus quune valeur dans la pile aprs valuation de tous les oprateurs. e e e Temps dexcution : en supposant que lvaluation des oprations intervenant e e e dans formule et les oprations sur les piles ont un temps dexcution constant, le e e temps dvaluation dune formule postxe de longueur n est O(n). e Remarque : lusage des fonctions cre_pile, empile et dpile permet de coder e e lalgorithme dvaluation dune formule postxe indpendamment de limplmene e e tation eective des piles ( ce dtail prs que dans limplmentation des piles sous a e e e forme de vecteurs, la fonction cre_pile prend un paramtre de taille et un objet e e du type de ceux qui seront empils). e

4-4

Exercices

Exercice 4-1 : non ambigu e des formules postxes t Dmontrer que la valeur dune formule postxe correcte est bien dnie, cest-e e a dire est indpendante de lordre des rductions eectues. e e e Exercice 4-2 : expressions conditionnelles postxes On envisage dajouter a la liste des oprateurs un oprateur conditionnel du e e type : si condition alors exp1 sinon exp2. Quelles sont les modications a apporter a lalgorithme dvaluation dune formule postxe pour traiter ce type e dexpressions ?

4-4 Exercices

59

Exercice 4-3 : valuation dune formule prxe e e Etudier le problme de lvaluation dune formule prxe. e e e Exercice 4-4 : valuation dune formule inxe a laide de deux piles e ` Lvaluation dune formule inxe non compltement parenthse impose de dnir e e ee e des rgles de priorit de faon a rendre non ambigue les formules du type : e e c x f y g z

o x, y, z sont des nombres et f, g des oprateurs binaires. On adopte ici la convenu e tion dassociativit a gauche : e valuer les oprations prioritaires en premier ; en cas de priorits gales e e e e valuer lopration de gauche en premier. e e On peut alors valuer une formule inxe a laide de deux piles, une pile de valeurs e et une pile doprateurs de la manire suivante : e e parcourir la formule en plaant les valeurs rencontres dans la pile c e des valeurs, les oprateurs et parenthses ouvrantes dans la pile des e e oprateurs et en eectuant toutes les oprations prioritaires empiles e e e lorsquon doit empiler un oprateur binaire ou une parenthse fermante. e e Une opration unaire est eectue au moment o lon doit empiler e e u largument correspondant. A la n du parcours, eectuer les oprations e en instance et retourner le sommet de la pile des valeurs. Coder cet algorithme en caml. On utilisera la dclaration suivante pour repre e senter les lments dune formule inxe : ee
type a lex`me = e | VALEUR of a | OP_UNAIRE of a -> a | OP_BINAIRE of int * (a -> a -> a) (* priorit, opration *) e e | PARENTH`SE_OUVRANTE E | PARENTH`SE_FERMANTE E ;;

Exercice 4-5 : compilation dune formule inxe Ecrire une fonction compile qui prend en argument une formule inxe f suppose e bien forme et renvoie une formule postxe f constitue des m^mes nombres et e e e des m^mes oprateurs et ayant m^me valeur que f. e e e Exercice 4-6 : non ambigu e des formules inxes t Montrer que si lon remplace les valeurs par des variables indpendantes et si lon e ne fait aucune hypothse sur la commutativit ou lassociativit des oprateurs e e e e alors une formule inxe bien forme f admet une unique formule postxe f e quivalente. e

Chapitre 5 Logique boolenne e

5-1

Propositions

Une proposition est une phrase non ambigue a laquelle on peut attribuer une valeur de vrit : vrai ou faux. Cette valeur peut dpendre de paramtres e e e e contenus dans la proposition. Par exemple les phrases : { Il fait beau aujourdhui. { x admet une racine carre entire. e e { est un nombre ngatif. e sont des propositions, la deuxime dpendant du paramtre x. Par contre les e e e phrases : { Cette phrase est fausse. { Pourquoi pas ? nen sont pas. En logique boolenne on ne sintresse qu la valeur de vrit dune propoe e a e e sition et on ignore le sens de la phrase associe. Deux propositions p et q ayant e la m^me valeur de vrit sont dites identiques, ce que lon note : p q. Par e e e exemple avec : p : Mercredi vient aprs Mardi. e q : Mardi vient aprs Mercredi. e r : Noel est un jour fri. e e s : < 0. on a p r et q s. Si les propositions p et q dpendent de paramtres x1 , .. ., xn, e e on convient que p q si et seulement si, pour toute valeur de (x1 , .. ., xn), p(x1 , . .., xn) et q(x1 , . .., xn) ont m^me valeur de vrit. Une proposition est e e e une tautologie si elle est identique a vrai. Connecteurs logiques Etant donnes deux propositions p et q, on convient que les expressions e suivantes sont aussi des propositions :

5-1 Propositions

61

{ non p : not aussi p ou p. (non p) est vrai lorsque p est faux, faux e lorsque p est vrai. { p et q : not aussi pq ou pq. (p et q) est vrai lorsque p et q valent vrai, e (p et q) est faux dans les autres cas. Lopration et est appele conjonction e e ou produit boolen. e { p ou q : not aussi p q ou p + q. (p ou q) est vrai lorsque lune au moins e des deux propositions vaut vrai, (p ou q) est faux lorsque les deux valent faux. Lopration ou est appele disjonction ou somme boolenne. e e e { p oubien q : not aussi p q. (p oubien q) est vrai lorsquune et une seule e des propositions p, q est vrai. On peut aussi dire que (p oubien q) vaut vrai si et seulement si p et q ont des valeurs de vrits direntes. e e e { p q : (p q) est vrai lorsque p et q ont la m^me valeur de vrit. e e e Cette notion est dirente de lidentit : p q est un fait tandis que e e p q est une proposition qui peut ^tre vraie ou fausse. e { p = q : (p = q) est une proposition identique a ((non p) ou q), ce qui se lit : limplication p = q vaut faux si et seulement si p vaut vrai et q vaut faux ; dans tous les autres cas, en particulier lorsque p vaut faux, limplication vaut vrai. Remarquons que limplication boolenne ainsi e dnie ne traduit pas un lien de cause a eet entre p et q mais seulement e une comparaison de leurs valeurs de vrit. Par exemple les implications : e e (Mercredi vient aprs Mardi) = (2 + 2 = 4) e (Il neige en Novembre) = (Noel sera en Dcembre) e valent vrai. De m^me, tant donn trois propositions p, q, r quelconques et e e e sans aucun rapport entre elles, la proposition : (p = q) ou (q = r) vaut toujours vrai. Tables de vrit e e Soit f(p1 , .. ., pn ) une proposition dpendant de paramtres p1 , .. . , pn qui e e sont des propositions indtermines. Les propositions p1 , . . . , pn sont appeles : e e e variables propositionnelles de f. On dit aussi que f est une fonction boolenne e de n variables. La table de vrit de f est un tableau donnant la valeur de vrit de e e e e f(p1 , .. ., pn ) pour chaque valeur possible du n-uplet (p1 , . .., pn ). Chaque variable propositionnelle peut prendre la valeur vrai ou faux, donc lensemble des valeurs possibles pour (p1 , . .., pn) est {vrai, faux}n. En particulier, la table de vrit e e de f a 2n lignes. Ces lignes sont gnralement classes par ordre lexicographique e e e du n-uplet valeur de (p1 , . .., pn ). Les tables de vrit des connecteurs logiques e e dnis a la section prcdente sont : e e e p V F
non p

F V

62

Logique boolenne e

p V V F F

q V F V F

p et q p ou q p oubien q V V F F V V F V V F F F

p q V F F V

p = q V F V V

o V et F reprsentent vrai et faux. u e Une table de vrit peut ^tre utilise pour dnir une fonction boolenne ou e e e e e e pour vrier une identit remarquable, cest--dire une tautologie. Par exemple la e e a table : p V V F F q V F V F p F F V V q F V F V q = p p = q V V F F V V V V

dmontre lidentit : (p = q) (q = p) qui est a la base du raisonnement par e e contraposition. On dmontre de m^me les identits suivantes : e e e p q non(p q) (p q) (pq + pq) p non(non p) non(p et q) p ou q non(p ou q) p et q p et (q et r) (p et q) et r p ou (q ou r) (p ou q) ou r p et (q ou r) (p et q) ou (p et r) p ou (q et r) (p ou q) et (p ou r)

lois de de Morgan associativit e distributivit e

On convient souvent de reprsenter les valeurs de vrit vrai et faux par les e e e nombres 1 et 0 ce qui donne les tables de vrit numriques : e e e p 0 0 1 1 q 0 1 0 1 p et q p ou q p q p = q 0 0 0 1 0 1 1 1 0 1 1 0 1 1 0 1

Ce tableau justie la notation pq pour (p et q). Lopration ou ne correspond a e une addition que si lon admet que 1 + 1 = 1 (!) et il aurait t plus judicieux de ee noter max(p, q) pour p ou q. Lopration correspond a laddition modulo 2, en e particulier elle est associative et distributive sur et. Enn limplication peut ^tre e vue comme une opration de comparaison : (p = q) (p q). e

5-2 Circuits logiques

63

5-2

Circuits logiques

Un circuit logique est un dispositif physique (lectronique, mcanique, ope e tique ou autre) muni dentres et de sorties nayant que deux tats stables nots e e e 0 et 1. Les tats des entres sont imposs par ( lextrieur ) , les tats des sore e e e e ( ) ties sont imposs par le circuit en fonction des tats des entres. Le circuit est e e e dit combinatoire si les tats des sorties a un instant donn ne dpendent que des e e e tats des entres a cet instant, et squentiel si les tats des sorties dpendent aussi e e e e e des tats antrieurs des entres. Les circuits logiques lmentaires sont reprsents e e e ee e e sur la gure 6. relais : E S=E
or :

A B A B A B

S= A+B

not:

E A B A B

S=E

nor :

S= A+B

and :

S = AB

xor :

S= AB

nand :

S = AB

Figure 6 : circuits lmentaires ee Le relais est utilis pour amplier un signal logique dans un montage come portant beaucoup de circuits, il na pas dutilit au sens logique. Les portes et et e ou sont appeles ainsi car elles permettent de bloquer ou laisser passer un signal e logique (cf. gure 7).

E 1 E 0

S = E : porte passante

E 1

S = 1 : porte bloque e

S = 0 : porte bloque e

E 0

S = E : porte passante

Figure 7 : portes Les portes nand et nor agissent comme des portes inverseuses : soit la porte est bloque, soit elle laisse passer la ngation de son entre libre. La porte oubien e e e transmet ou inverse un signal prsent sur une entre suivant que lautre entre est e e e maintenue a 0 ou a 1. Un circuit logique non lmentaire est constitu de circuits lmentaires ee e ee inter-connects de sorte que toute entre dun composant est relie soit a une entre e e e e

64

Logique boolenne e

du circuit complet soit a une sortie dun autre composant, et toute sortie dun composant est relie a une sortie du circuit complet ou a une ou plusieurs entres e e dautres composants. On dmontre quun circuit est combinatoire si aucune sortie e dun composant nest relie a une des entres de ce composant, directement ou e e indirectement a travers dautres portes (cest une condition susante seulement).

circuit combinatoire

A B 1 1 1 0 0 1 0 0

1 0 0 0

S 1 0 1 1 1 1 0 0

S circuit squentiel e

R S 1 1 1 0 0 1 0 0

Q x 0 1 1

Q x 1 0 1

Le circuit squentiel ci-dessus est appel bascule RS. Il constitue une mmoire e e e simplie : on enregistre un 0 en mettant R a 1 et S a 0 puis en ramenant S a 1. e De m^me, en maintenant S a 1, on enregistre un 1 en mettant R a 0 puis en le e ramenant a 1. Lorsque R = S = 1, le bit mmoris est disponible sur Q et son e e complment est disponible sur Q . Les tats de Q et Q dpendent donc du pass. e e e e Remarque technique Par assemblage de circuits lmentaires on peut raliser nimporte quelle ee e fonction boolenne (voir la section suivante). Cependant, lors de la ralisation e e physique, il faut tenir compte des points suivants : { Une sortie ne peut alimenter quun nombre limit dentres. La sortance e e dun circuit est le nombre maximal dentres qui peuvent ^tre connectes sur e e e une sortie de ce circuit ; elle est gnralement comprise entre 10 et 100 suivant e e la technologie employe. Dans un circuit complexe il peut ^tre ncessaire e e e dintercaler des relais amplicateurs sur les sorties trs demandes. e e { Chaque porte a un temps de propagation non nul : lorsquune entre change e de valeur la sortie nest garantie stable quau bout de ce dlai de propagae tion. Le temps de rponse dun assemblage de portes lmentaires est donc e ee proportionnel au plus grand nombre de portes intercales entre une entre et e e une sortie du circuit complet. Ce nombre est appel profondeur du circuit e et on a gnralement intr^t a minimiser cette profondeur pour obtenir un e e ee fonctionnement rapide.

5-3 Synthse des fonctions boolennes e e

65

5-3

Synth`se des fonctions boolennes e e

Reprsentation et-ou-non e Thor`me : soit f une fonction boolenne des variables p1 , ..., pn . Alors e e e f peut ^tre exprime uniquement a laide des connecteurs et, ou, non, des e e variables pi et des propositions constantes vrai et faux. Consquence : toute fonction boolenne peut ^tre ralise par assemblage e e e e e de portes lmentaires and, or et not. ee Dmonstration : on procde par rcurrence sur n. Pour n = 0, f est une e e e proposition sans variable, donc f vrai ou f faux. Si le thorme est vri e e e e pour toute fonction boolenne a n1 variables, considrons une fonction boolenne e e e f a n variables et les deux fonctions : g : (p1 , .. ., pn1) f(p1 , . . ., pn1, vrai),

h : (p1 , .. ., pn1) f(p1 , . . ., pn1, faux), de sorte que :

f(p1 , .. ., pn) (pn et g(p1 , . .., pn1)) ou (pn et h(p1 , .. ., pn1)). Lhypothse de rcurrence applique a g et h fournit alors une dcomposition de e e e e f a laide des connecteurs et, ou et non, des variables pi et des constantes vrai et faux. Exemple : additionneur 1-bit. Etant donns deux nombres A et B cods sur e e un bit (cest--dire compris entre 0 et 1) et une retenue, C code aussi sur un a e bit, on veut calculer la somme A + B + C (+ a ici le sens de laddition des entiers naturels). Cette somme est comprise entre 0 et 3, donc peut ^tre reprsente sur e e e deux bits : A + B + C = 2S1 + S0. On peut crire la table de vrit de (S1 , S0) : e e e A B 0 0 0 0 0 1 0 1 1 0 1 0 1 1 1 1 C 0 1 0 1 0 1 0 1 S1 0 0 0 1 0 1 1 1 S0 0 1 1 0 1 0 0 1 La premire moiti donne la table de vrit de e e e e (S0 , S1) lorsque A 0. Il appara^ que dans t ce cas S0 B C et S1 BC. De m^me, e dans le cas A 1 on obtient : S0 B C et S1 B + C (addition logique) ce qui donne : S0 A(B C) + A(B C) ; S1 A(B + C) + A(BC). On a de m^me : B C BC + BC, ce qui e donne le circuit additionneur de la gure 8.

Additionneur n-bits Soient a = an1 . . .a0 2 et b = bn1 . ..b0 deux nombres entiers naturels dcomposs en base 2 et c = c0 2 {0, 1}. Pour calculer la somme a + b + c, on peut e e
2

66

Logique boolenne e

C B BC C A

S0
A

A
A BC A B+C

S1

Figure 8 : additionneur 1-bit c a 0 b0 b s1 a 1 b1 c a s0 s1 Figure 9 : additionneur n-bits additionner les bits de m^me rang de a et b en propageant les retenues, c jouant le e r^le de retenue entrante. Il sut donc de disposer n additionneurs 1-bit en caso cade (cf. gure 9). Linconvnient de ce montage est que son temps de rponse est e e proportionnel a n car chaque additionneur 1-bit doit ( attendre ) que la retenue ( ) de ladditionneur prcdent soit disponible pour produire un rsultat correct. On e e e peut raliser laddition de deux nombres de n bits et dune retenue entrante plus e rapidement en calculant au pralable toutes les retenues. Notons ck la retenue e entrant dans le k-me additionneur 1-bit, cest--dire la sortie s1 du (k 1)-me e a e additionneur dans le montage prcdent (on convient ici de numroter les addie e e tionneurs a partir de 0). ck est une fonction boolenne des entres a0, . . ., ak1, e e b0 , . .., bk1 et c0 et on dmontre par rcurrence sur k que lon a : e e ck = fk (a0 , . . ., bk1) + c0 gk (a0 , .. ., bk1) avec : xi = ai + bi , y i = a i bi , b s1 an1 bn1 c a s0 sn1 b s1 sn

c a s0 s0

gk (a0 , . .., bk1 ) = x0 . ..xk1, fk (a0 , . .., bk1 ) = y0 x1 .. .xk1 + y1x2 . ..xk1 + . .. + yk2xk1 + yk1.

5-3 Synthse des fonctions boolennes e e

67

Notons n(a, b, c0 ) = (c0 , . .., cn1) et supposons que n est pair, n = 2p. En dcomposant a = a +2p a et b = b +2p b , on obtient les relations de rcurrence : e e fn (a, b) = fp (a , b ) gp(a , b ) + fp (a , b ), gn (a, b) = gp (a , b ) gp(a , b ), n(a, b, c0 ) = p (a , b , c0 ) @ p (a , b , fp (a , b ) + c0 gp (a , b )), o @ dsigne la concatnation des listes. Ces relations permettent de construire un u e e circuit calculant rcursivement les coecients fn (a, b), gn(a, b) et la liste complte e e des retenues selon la stratgie ( diviser pour rgner ) (cf. gure 10). Soient Pn la e e ( ) profondeur de ce circuit et Kn le nombre de portes quil contient. On a : P1 = 1, K1 = 2, Pn = Pn/2 + 2, Kn = 2Kn/2 + 5.

Do, lorsque n est une puissance de 2, Pn = 1 + 2 log2(n) et Kn = 7n 5. u Il est ainsi possible de calculer la somme de deux nombres de n bits en temps logarithmique par rapport a n et avec un nombre de portes linaire en n (voir e lexercice 5-8 pour une minoration de la profondeur dun additionneur n-bits quelconque). a b f g a b f g f FG c0 g

FG

FG

Figure 10 : calcul rapide des retenues Formes normales Soient p1 , . . . , pn des variables propositionnelles. On appelle littraux les e propositions p1 , . . . , pn et p1 , . .. , pn . Un mon^me est un produit de littraux o e comme par exemple m = p1 p2 p3 . Un minterme est un mon^me dans lequel o chaque variable pi appara^ une et une seule fois, avec ou sans ngation. Il y a t e

68

Logique boolenne e

donc 2n mintermes de n variables, et un minterme m donn vaut vrai pour une e et une seule distribution de vrit des variables p1 , . . . , pn : celle pour laquelle e e pi vaut vrai si pi est facteur de m et faux si pi est facteur de m. Soit f une fonction boolenne des variables p1 , . .., pn. Un mon^me m est e o appel impliquant de f si la proposition m = f est une tautologie, cest--dire e a si f vaut vrai a chaque fois que m vaut vrai. Thor`me : toute fonction boolenne f est la somme boolenne des mintere e e e mes limpliquant. En eet f et la somme de ses mintermes ont la m^me table de vrit. Ceci e e e permet dexprimer f comme une disjonction de mintermes, donc uniquement a laide des connecteurs et, ou et non. La dcomposition de f ainsi obtenue est ape pele forme normale disjonctive. Par exemple, pour ladditionneur 1-bit tudi e e e prcdemment, on a daprs la table de vrit de (S1 , S0) : e e e e e S0 A.B.C + A.B.C + A.B.C + A.B.C

S1 A.B.C + A.B.C + A.B.C + A.B.C A B C

S0 Figure 11 : additionneur 1-bit

S1

Cette expression permet de raliser ladditionneur a laide de portes a 3 ou e 4 entres (cf. gure 11). De manire gnrale, en utilisant la forme normale e e e e disjonctive on peut raliser nimporte quelle fonction boolenne avec un circuit de e e profondeur au plus 3, mais ceci impose dutiliser des portes et et ou a plus que deux entres (jusqu n entres pour les portes et et jusqu 2n entres pour les e a e a e portes ou) ce qui peut poser des problmes de ralisation technique. e e

5-4 Manipulation des formules logiques

69

En intervertissant les r^les des connecteurs et et ou on peut aussi reprsenter o e une fonction boolenne de n variables comme un produit de sommes de n littraux e e o chaque variable appara^ une et une seule fois dans chaque somme. Cette u t reprsentation est appele forme normale conjonctive. Pour obtenir la forme e e normale conjonctive de f il sut dappliquer les rgles de de Morgan a la ngation e e de la forme normale disjonctive de f.

5-4

Manipulation des formules logiques

Une formule logique est une reprsentation dune fonction boolenne au e e m^me titre quune expression arithmtique est une reprsentation dune fonction e e e algbrique. Par exemple si p, q, r sont trois variables boolennes alors les formules : e e p et (q et r), (p et q) et r sont direntes par leur forme mais elles reprsentent la m^me fonction boolenne, e e e e celle qui vaut vrai si et seulement si les propositions p, q et r valent vrai. On tudie ici les problmes suivants : e e { reprsentation en mmoire dune formule logique ; e e { valuation dune formule lorsque les valeurs de vrit des variables de la e e e formule sont connues ; { satisabilit : existe-t-il une distribution de vrit pour laquelle cette formule e e e vaut vrai ? { tautologie : la formule tudie vaut-elle vrai pour toute distribution de e e vrit ? e e { identit fonctionnelle : deux formules logiques reprsentent-elles la m^me e e e fonction boolenne ? e Les trois derniers problmes sont lis. En eet, la formule f est une tautologie si e e et seulement si f nest pas satisable, et les formules f et g sont identiques si et seulement si f g est une tautologie. Un problme qui nest pas abord est e e celui de la simplication dune formule logique, ou de la recherche dune formule logique ( la plus simple possible ) reprsentant une fonction boolenne donne. e e e ( ) Reprsentation en mmoire e e La notion de formule logique est intrinsquement rcursive : une formule e e logique est soit une valeur constante vrai ou faux, soit une variable propositionnelle, soit lapplication dun connecteur logique (non, et, ou, oubien, nand, nor, = , ) a une ou deux formules logiques. On dnira donc le type formule en e caml par :
type formule = | Const of bool | Var of string | Mono of op1 * formule | Bin of op2 * formule * formule and op1 == bool -> bool and op2 == bool -> bool -> bool ;; (* (* (* (* valeur constante variable connecteur a un argument ` connecteur binaire *) *) *) *)

70

Logique boolenne e

Les connecteurs logiques sont reprsents par des fonctions oprant sur le type e e e bool. Les connecteurs usuels peuvent ^tre dnis par : e e
let let let let ;; let let let let non et ou equiv = = = = fun fun fun fun true true true false false false false -> -> -> -> false true false true | | | | _ -> true;; _ _ -> false;; _ _ -> true;; true true -> true | _ _ -> false

nand nor oubien impl

x x x x

y y y y

= = = =

non(et x y);; non(ou x y);; non (equiv x y);; ou (non x) y;;

La formule logique f = (p et (q r)) est donc reprsente par : e e


Bin(et, (Var "p"), Bin(equiv, (Var "q"), Mono(non, Var "r")))

En interne la formule est reprsente par un ensemble de cellules relies par des e e e pointeurs comme pour les listes cha^ ees (cf. gure 12). Pour des raisons de comn modit typographique, on prfre dcrire les formules par des arbres syntaxiques e ee e tels que celui de la gure 13.
Bin et et

Var

Bin

p q

non

Var

Mono non

Var

r Figure 13 : reprsentation abstraite e

Figure 12 : reprsentation e mmoire dune formule e

Pour analyser une formule, lvaluer ou plus gnralement procder a un e e e e traitement quelconque, on est amen a parcourir la formule, ce qui se fait suivant e le schma rcursif : e e
let rec parcours | Const(c) -> | Var(v) -> | Mono(op,g) -> | Bin(op,g,h) -> ;; f = match f with traite_constante(c) traite_variable(v) traite_mono(op,g) traite_bin(op,g,h)

o traite_constante, traite_variable, traite_mono et traite_bin sont des acu tions appropries au traitement a eectuer. En gnral les actions traite_mono et e e e traite_bin procdent au parcours des sous-formules g et h. e

5-4 Manipulation des formules logiques

71

Evaluation dune formule logique Pour valuer une formule logique il faut disposer des valeurs de toutes les e variables apparaissant dans la formule. On peut reprsenter une distribution e de vrit par une liste de couples (nom de la variable, valeur ) transmise en e e argument a la fonction dvaluation. Comme les connecteurs sont directement e reprsents par des fonctions caml, il sut dvaluer rcursivement les arguments e e e e dun connecteur puis dappliquer la fonction associe aux valeurs obtenues : e
(* Recherche la variable de nom "nom" dans la distribution *) (* de vrit "distribution" et renvoie sa valeur. e e *) let rec valeur_variable distribution nom = match distribution with | [] -> failwith "variable inconnue" | (x,y)::suite -> if x = nom then y else valeur_variable suite nom ;; (* Evalue la formule f *) let rec evalue distribution f = match f with | Const(c) -> c | Var(nom) -> valeur_variable distribution nom | Mono(op,g) -> op (value distribution g) e | Bin(op,g,h) -> op (value distribution g) (value distribution h) e e ;;

Complexit : le temps ncessaire a lvaluation de f dpend de plusieurs parame e e e e tres. Chaque variable apparaissant dans f donne lieu a une recherche squentielle e dans la distribution de vrit, ncessitant en moyenne n/2 comparaisons. Lvae e e e luation dune constante ou dun connecteur prend un temps constant une fois que les arguments du connecteur sont valus, donc le temps total dvaluation est de e e e la forme : T = aN + bVn o a, b sont des constantes, N est le nombre de connecteurs et de constantes dans u la formule, V est le nombre de variables de f comptes avec rptitions et n est e e e la longueur de la liste distribution. Pour une formule de longueur le temps dvaluation est donc O(n ). e Satisabilit, reconnaissance de tautologies e Etant donne une formule logique f dpendant de variables p1 , . . ., pn, on e e veut dterminer une distribution de vrit pour p1 , . . ., pn qui rend f vrai. La e e e mthode la plus simple est de ( parcourir ) la table de vrit de f jusqu trouver e e e a ( ) la valeur vrai. Il nest pas ncessaire de construire explicitement cette table de e vrit, il sut dengendrer lune aprs lautre toutes les distributions de vrit e e e e e pour (p1 , . .., pn ) et dvaluer a chaque fois f. e

72 type rsultat = e | TROUV of (string * bool) list E | NONTROUV E ;;

Logique boolenne e

(* dist. de vrit trouve *) e e e (* formule non satisfaite *)

(* cherche une distribution de vrit satisfaisant la formule f e e (* vlibres est la liste des variables non encore affectes e (* vlies est la distribution de vrit en construction e e e

*) *) *)

let rec satisfait vlibres vlies f = match vlibres with e | [] -> if evalue vlies f then TROUV(vlies) else NONTROUV e E e E | p :: suite -> match satisfait suite ((p,true) :: vlies) f with e | NONTROUV -> satisfait suite ((p,false) :: vlies) f E e | res -> res ;; (* dtection dune tautologie, e voir lexercice 5-5 pour la dfinition de liste_variables *) e let tautologie f = (satisfait (liste_variables f) [] (Mono(non,f))) = NONTROUV E ;;

Complexit : pour une formule f a n variables de longueur , la recherche e dune distribution de vrit satisfaisant f peut ncessiter jusqu 2n tapes, chae e e a e cune de ces tapes consistant a construire une distribution de vrit dans la liste e e e vlies puis a valuer f. Le temps dexcution dune tape est O(n ) donc le e e e e temps ncessaire pour constater quune formule a n variables est une tautologie e est O(n2n ) car dans ce cas on parcourt eectivement toute la table de vrit. e e On peut obtenir un temps O(2n ) si la distribution de vrit est stocke dans un e e e vecteur au lieu dune liste cha^ ee, mais m^me avec cette amlioration la dtection n e e e des tautologies est impraticable pour des valeurs de n dpassant la vingtaine. e Il existe dautres mthodes pour reconna^ e tre les tautologies, mais elles ont elles aussi un temps dexcution exponentiel dans le pire des cas : la mthode e e de Davis et Putnam consiste a simplier la formule a contr^ler a chaque fois o que lon choisit la valeur de vrit dune variable. On utilise pour cela les rgles e e e de simplication des connecteurs et et ou ayant un oprande constant ainsi que e des rgles similaires pour les autres connecteurs (cf. exercice 5-6). Ceci permet e dobtenir une formule plus courte, ayant au moins une variable de moins que la formule de dpart, la variable que lon vient daecter. Lordre dans lequel on e aecte les variables nest pas indirent : on a intr^t a choisir parmi les variables e ee encore libres celle qui donnera aprs simplication la formule la plus simple en e nombre de variables libres restant. La recherche de la meilleure variable a aecter complique le code du vricateur et co^te du temps, mais semble ^tre la mthode e u e e la plus ecace connue a ce jour pour la vrication de tautologies. e Une autre mthode de vrication dune tautologie consiste a mettre la fore e mule f sous forme conjonctive, non ncessairement normale, cest--dire a transe a former f en un produit de sommes de littraux. On peut obtenir une telle forme e

5-5 Exercices

73

pour f en traduisant tous les connecteurs a laide des connecteurs de base et, ou, e ) tous les et et ( descendre ) tous les non par les rgles ) ( ) de de Morgan et la distributivit de ou sur et. Aprs limination des sommes e e e contenant un littral et sa ngation, il ne reste plus que des sommes non triviales e e qui fournissent les cas o f vaut faux. Donc f est une tautologie si et seulement si u la forme conjonctive obtenue pour f est vide aprs simplications. Cette mthode e e a aussi un co^t exponentiel dans le pire des cas, car une forme conjonctive a n u variables peut contenir jusqu 2n1 facteurs dirents (cf. exercice 5-3). Donc a e cette mthode est non seulement co^teuse en temps, mais aussi en mmoire. e u e
non, et en ( faisant remonter (

5-5

Exercices

Exercice 5-1 : synth`se des fonctions boolennes e e Montrer que toute fonction boolenne peut ^tre exprime uniquement a laide du e e e connecteur nand. Montrer quil existe des fonctions boolennes non exprimables e uniquement a laide des connecteurs et et ou. Exercice 5-2 : logique ternaire Les Normands utilisent un systme logique a trois valeurs de vrit : vrai, faux e e e et peutetre avec les connecteurs suivants : { non(vrai) = faux, non(faux) = vrai, non(peutetre) = peutetre ; { p et q vaut vrai quand p = q = vrai, faux quand p ou q vaut faux et peutetre dans tous les autres cas ; { p ou q = p et q ; { p oubien q = (p ou q) et non(p et q). Calculer vrai et (faux oubien peutetre). Ecrire en caml les dnitions du type normand et des connecteurs prcdents. e e e Vrier que les identits usuelles des connecteurs logiques sont encore valae e bles en Normandie (associativit, commutativit, distributivit). On pourra e e e eectuer cette vrication par programme. e 4. Est-ce que toute ( fonction normande ) est exprimable a laide des connec ( ) teurs et ou et non ? Exercice 5-3 : taille dune forme conjonctive 1. Montrer que toute forme conjonctive (conjonction de disjonctions de littraux, non ncessairement normale) qui quivalente a la formule logique e e e f = p1 p2 .. . pn comporte au moins 2n1 facteurs. 2. Existe-t-il des fonctions boolennes a n variables ncessitant encore plus de e e facteurs, m^me aprs simplications ? e e 1. 2. 3.

74

Logique boolenne e

Exercice 5-4 : forme normale exclusive Montrer que toute formule logique peut ^tre transforme en une somme exclusive e e ( laide du connecteur ) de produits de variables et des constantes vrai et faux. a Montrer quil y a unicit dune telle forme a lordre des termes prs si lon retire e e les produits nuls (cest--dire contenant un littral et sa ngation) et les produits a e e rpts (car f f 0). Peut-on utiliser cette mise en forme pour dtecter les e ee e tautologies ? Exercice 5-5 : variables dune formule logique Soit f une formule logique. Ecrire une fonction caml liste_variables calculant la liste sans rptition des variables de f. e e Exercice 5-6 : simplication dune formule logique Ecrire une fonction simplifie qui simplie une formule logique en valuant les e oprandes constants. Noter que si un seul des oprandes dun connecteur binaire e e est constant alors la formule peut quand m^me ^tre simplie : e e e p et vrai p, p et faux faux, p oubien vrai p, .. .

Exercice 5-7 : additionneur 1-bit Vrier que le circuit ci-dessous ralise laddition de deux bits et dune retenue. e e Existe-t-il un additionneur 1-bit comportant moins de 5 portes lmentaires ? ee E0 E1 S1 S0

E2

Exercice 5-8 : profondeur minimale dun additionneur Montrer que tout additionneur n-bits constitu de portes a une ou deux entres a e e une profondeur au moins gale a log2 (n). e Exercice 5-9 : division par 3 Construire un circuit logique calculant le reste de la division par 3 dun nombre entier naturel exprim sur n bits. e Exercice 5-10 : comparateur Un comparateur n-bits est un circuit logique comportant 2n entres A0 .. .An1, e B0 .. .Bn1, et trois sorties : I, E, S telles que si a et b sont les nombres reprsents e e en binaire par A0, . . ., An1, B0, . . ., Bn1 alors : I = 1 si et seulement si a < b, E = 1 si et seulement si a = b, et S = 1 si et seulement si a > b. 1. Construire un comparateur 1-bit. 2. Construire un comparateur 2-bits. 3. Construire un comparateur n2-bits a laide de n + 1 comparateurs n-bits.

5-5 Exercices

75

4. Peut-on utiliser la technique prcdente pour construire un comparateur ne e bits quelconque ? a Exercice 5-11 : achage 7 segments f b Concevoir un circuit logique a 4 entres, A, B, C, D et 7 sorties a, b, e g c, d, e, f, g permettant de reprsenter un entier n = A + 2B + 4C + 8D e suppos compris entre 0 et 9 sur un acheur 7 segments disposs e e e c comme ci-contre (un segment est allum lorsque son entre vaut 1). e e d

Chapitre 6 Complexit des algorithmes e

6-1

Gnralits e e e

An de comparer plusieurs algorithmes rsolvant un m^me problme, on e e e introduit des mesures de ces algorithmes appeles complexits. e e { Complexit temporelle : cest le nombre doprations ( lmentaires ) efe e (ee ) fectues par une machine qui excute lalgorithme. e e { Complexit spatiale : cest le nombre de ( positions mmoire ) utilises par e e e ( ) une machine qui excute lalgorithme. e Ces deux complexits dpendent de la machine utilise mais aussi des donnes e e e e traites. Considrons par exemple les algorithmes prod1 et prod2 suivants qui e e calculent le produit des lments dun vecteur : ee
let prod1(v) = let p = ref(1.0) in for i = 0 to (vect_length(v)-1) do p := !p *. v.(i) done; !p ;; let prod2(v) = let p = ref(1.0) and i = ref(0) in while (!i < vect_length(v)) & (!p <> 0.0) do p := !p *. v.(!i); i := !i + 1 done; !p ;;

Si lon fait excuter ces deux algorithmes par une machine caml, la come plexit temporelle de prod1 est T1 = 4n + 2 o n est la longueur de v (on a e u

6-1 Gnralits e e e

77

compt 4 oprations lmentaires dans le corps de la boucle : incrmentation de e e ee e i, accs a v.(i), multiplication et aectation du rsultat a p) tandis que la come e plexit temporelle de prod2 est T2 = 6n + 4 si v ne comporte pas dlment nul, et e ee T2 = 6m + 5 si v comporte un zro, en notant m le rang dapparition du premier e zro de v. Si les deux algorithmes sont excuts sur la m^me machine alors prod2 e e e e est plus ecace que prod1 sil y a un zro dans les deux premiers tiers de v, moins e ecace sil ny a pas de zro ou sil est dans le dernier tiers. Cette limite ape 2 ee u e proximative 3 ne vaut que pour la machine considre o chaque opration prend une unit de temps : si lon utilise une machine o une multiplication compte e u pour 100 oprations lmentaires, on obtient T1 = 103n + 2 et T2 = 105n + 4 ou e ee T2 = 105m + 5 donc lavantage revient a prod2 si v comporte un zro situ a au e e moins 2% de la n du vecteur. Si lon veut sabstraire de la dpendance de la complexit par rapport a la mae e chine, on considre que prod1 et prod2 eectuent un nombre constant doprations e e lmentaires a chaque itration, auquel cas les complexits sont T 1 = a1 n + b1 et ee e e T2 = a2n + b2 ou T2 = a2 m + b2 pour certaines constantes a1 , b1 , a2 , b2 et b2 . Il nest plus possible dans ce cas de dire si prod1 est plus ou moins rapide que prod2. Pour sabstraire de la dpendance de la complexit par rapport aux donnes e e e prcises traites on considre gnralement la complexit dans le pire des cas, ceste e e e e e a-dire la complexit maximale pour toutes les valeurs de v possibles. Si la taille e n de v est borne alors prod1 et prod2 sexcutent en temps constant, constant e e signiant en fait born. Si la taille nest pas borne a priori, on considre le pire e e e des cas pour un vecteur quelconque de taille n, ce qui donne : T1 = a1n + b1 et T2 = a2 n + b2 . Comme les constantes a1, a2 , b1 et b2 sont indtermines (ceste e a-dire dpendent de la machine utilise), on peut ne retenir que les complexits e e e asymptotiques : T1 = O(n) et T2 = O(n). On peut aussi tudier la complexit en moyenne, cest--dire la moyenne des e e a complexits dun algorithme pour toutes les valeurs possibles des donnes a traiter e e selon un certain modle de probabilit. Supposons par exemple que les lments e e ee de v sont en fait des entiers alatoires compris entre 0 et 9, chaque lment tant e ee e indpendant des autres. Il y a donc a n x 10n vecteurs v possibles qui se rangent e e en catgories suivant le rang dapparition du premier zro : e e m = 1 : 10n1 vecteurs, m = 2 : 9 10n2 vecteurs, . .. m = k : 9k1 10nk vecteurs, . .. m = n : 9n1 vecteurs. pas de zro : 9n vecteurs. e La complexit moyenne de prod2 est alors : e

78

Complexit des algorithmes e

T2 =

1 10n

1 = 10

k=1 n

(a2 k + b2 ) 9k1 10nk +

9n (a2 n + b2 ) 10n

k=1

(a2 k + b2 ) 0, 9k1 + 0.9n(a2 n + b2 )


k=1

1 10

(a2 k + b2 ) 0, 9k1 = 10a2 + b2 .

La complexit moyenne de prod2 est donc borne, alors que celle de prod1 est e e asymptotiquement proportionnelle a n. Ce phnomne se produit quelle que e e soit la distribution de probabilit retenue, pourvu que les lments de v soient e ee indpendants et que la probabilit dapparition de zro soit non nulle. Incideme e e ment, on apprend que le rang moyen du premier zro est environ gal a 10 (ou e e plus gnralement 1/p o p est la probabilit dapparition dun zro) lorsque n e e u e e est grand, et non n/2. La complexit spatiale mesure la quantit de mmoire ncessaire a lexcution e e e e e dun algorithme, en comptant les variables temporaires et le rsultat, mais pas les e donnes (de m^me quon ne compte pas le temps dintroduction des donnes dans e e e la complexit temporelle). Lunit de mesure est le ( mot mmoire ) , mais cette e e e ( ) unit dpend de la machine utilise et on calcule gnralement une complexit e e e e e e mmoire asymptotique. Sur une machine squentielle o il y a un seul processeur e e u excutant une seule instruction par unit de temps, la complexit mmoire est e e e e au plus gale a la complexit temporelle puisquil faut au moins une unit de e e e temps pour ( remplir ) une position mmoire. Ceci nest pas vrai sur des mae ( ) chines hautement parallles disposant dun nombre arbitraire de processeurs. Par e exemple le calcul du produit des lments dun vecteur de longueur n peut ^tre ee e eectu selon la mthode ( diviser pour rgner ) avec n/2 processeurs calculant e e e ( ) en m^me temps les produits de deux termes conscutifs, puis en calculant par la e e m^me mthode le produit des n/2 sous-produits obtenus (cf. gure 14). e e

Figure 14 : multiplication parallle e

6-2 Equation de rcurrence T (n) = aT (n 1) + f(n) e

79

On obtient ainsi le produit des termes dun vecteur de longueur n = 2p en p units e de temps, avec 1+2+4+.. .+2p1 = n1 processeurs utilisant chacun une position mmoire pour leur rsultat. Donc la complexit temporelle est T = O(ln n) tandis e e e que la complexit spatiale est M = O(n). e Lexemple prcdent montre que lon peut changer la complexit temporelle e e e dun problme en augmentant la complexit spatiale (et la complexit matrielle). e e e e Un autre exemple est le calcul dune suite vriant une relation de rcurrence e e double :
let rec fib1(n) = if n < 2 then 1 else fib1(n-1) + fib1(n-2);; let fib2(n) = let v = make_vect (n+1) 1 in for i = 2 to n do v.(i) <- v.(i-1) + v.(i-2) done; v.(n) ;; fib1 et fib2 calculent toutes les deux le n-me terme de la suite de Fibonacci, e mais fib1 a une complexit temporelle exponentielle (cf. exercice 6-4) tandis que e fib2 a une complexit temporelle linaire. Dans cet exemple il ny a pas augmene e tation de la complexit spatiale car fib1 a une complexit spatiale linaire due e e e au stockage des calculs en suspens. Par ailleurs, on peut crire une fonction fib3 e calculant Fn en temps linaire et mmoire constante, et m^me, par la technique e e e diviser pour rgner ) , une fonction fib4 calculant Fn en temps logarithmique et e ( ( ) mmoire constante (cf. exercice 1-12). e

6-2

Equation de rcurrence T (n) = aT (n 1) + f(n) e

Le calcul de la complexit dun algorithme conduit gnralement a une ree e e lation de rcurrence, en particulier si cet algorithme est rcursif. On tudie ici le e e e cas o le temps T dexcution dun algorithme pour une donne de taille n suit u e e une relation de la forme : T (n) = aT (n 1) + f(n) o f est une fonction a valeurs entires donne. Cela signie que la rsolution du u e e e problme pour une donne de taille n se ramne a la rsolution de a sous-problmes e e e e e pour des donnes de taille n1. f(n) reprsente le temps ncessaire pour dcouper e e e e le problme initial en sous-problmes et pour recombiner les rsultats de ces souse e e problmes. e Exemples Parcours dune liste de n lments : T (n) = T (n 1) + b o b est le temps ee u ncessaire pour traiter un lment. e ee

80

Complexit des algorithmes e

Lalgorithme de tri par slection consiste a parcourir un vecteur de longueur e n en reprant la position du plus grand lment, a dplacer cet lment en dernire e ee e ee e position par change, puis a trier le sous-vecteur de taille n 1 restant. Le temps e de recherche du plus grand lment est proportionnel a n (il faut parcourir tout ee le vecteur), le temps dun change est constant, donc le temps de tri par slection e e suit la relation : T (n) = T (n 1) + bn + c. Le problme des tours de Hanoi : n disques de tailles distinctes sont empils e e sur un piquet A par tailles croissantes, il faut les empiler sur un piquet B en utilisant un piquet intermdiaire C avec les contraintes de ne dplacer quun disque e e a la fois et de respecter a tout instant la condition de croissance des tailles des disques sur chaque piquet. Ce problme se ramne a trois sous-problmes : e e e { dplacer les n 1 premiers disques de A vers C en utilisant B comme piquet e intermdiaire ; e { dplacer le dernier disque de A vers B ; e { dplacer les n 1 disques de C vers B en utilisant A comme piquet ine termdiaire. e Le nombre total de dplacements eectus vrie donc : T (n) = 2T (n 1) + 1. e e e On supposera dans toute la suite que a est un entier suprieur ou gal a 1, et e e que le temps de sparation-recombinaison, f(n), est strictement positif. Lobjectif e de ltude de ces quations de rcurrence est dobtenir, dans la mesure du possible, e e e une expression asymptotique pour T (n). Manipulation dingalits par rcurrence e e e On considre deux fonctions, T , U dnies sur N et vriant les quations : e e e e T (n) = aT (n 1) + f(n), U(n) = aU(n 1) + g(n),

pour n 1, o a N et f, g sont des fonctions de N dans N . On a alors les u proprits suivantes : ee 1. Les fonctions T et U sont strictement croissantes. 2. Si T (0) U(0) et si f(n) g(n) pour tout n N alors T (n) U(n) pour tout n N. 3. Si f(n) = O(g(n)) pour n alors T (n) = O(U(n)) pour n . En eet, 1 et 2 sont videntes. Pour 3, puisque f(n) = O(g(n)) et g(n) > 0, e il existe une constante C telle que f(n) Cg(n) pour tout n et, quitte a aug menter C, on peut supposer que T (1) CU(1) (car U(1) = aU(0) + g(1) > 0) donc T (n) CU(n) pour tout n 1 par rcurrence. e Cette proprit permet de remplacer une quation de rcurrence complique ee e e e par une quation plus simple o lon ne garde que le terme dominant du temps e u de sparation-recombinaison. Par exemple le coecient c peut ^tre ignor dans e e e

6-2 Equation de rcurrence T (n) = aT (n 1) + f(n) e

81

ltude du tri par slection si lon ne veut quune estimation asymptotique du e e temps de tri. Plus prcisment, si T et U sont solution des quations : e e e alors on a T (n) = O(U(n)), mais aussi U(n) = O(T (n)), cest--dire que lon ne a risque pas dobtenir une majoration trop grossire en calculant U a la place de T . e On utilise la notation : T (n) = (U(n)) pour indiquer que les deux relations T (n) = O(U(n)) et U(n) = O(T (n)) ont lieu. Equation T (n) = T (n 1) + f(n) Cette quation se rsout de manire immdiate : e e e e
n

T (n) = T (n 1) + bn + c,

U(n) = U(n 1) + bn,

T (n) = T (0) +
k=1

f(k).
n

Il reste a estimer asymptotiquement la somme


k=1

f(k).

e Thor`me : (lemme de Csaro) e e Soient (un) et (vn ) deux suites de rels telles que : e un vn > 0, [0, +] et v0 + v1 + ... + vn +. n vn n Alors le rapport u0 + u1 + ... + un tend vers v0 + v1 + ... + vn quand n .

Thor`me : (variante) e e Soient (un) et (vn ) deux suites de rels telles que : e vn > 0, un = O(vn ) pour n et v0 + v1 + ... + vn +.
n

Alors u0 + u1 + ... + un = O(v0 + v1 + ... + vn ) pour n . Ces deux noncs sont admis. Ils permettent dobtenir un quivalent ou un e e e majorant asymptotique dune somme en remplaant le terme gnral par celui c e e dune somme connue ou plus facile a calculer. Par exemple pour lquation de e rcurrence T (n) = T (n 1) + f(n), si lon sait que f(n) np pour n avec e n > 0 et p 0 alors on obtient : T (n) k=1 kp pour n . La somme des puissances p-mes des premiers entiers est connue pour les petites valeurs de p : e
n n

k0 = n,
k=1 k=1

k1 =

n(n + 1) , 2

k2 =
k=1

n(n + 1)(2n + 1) , 6

ce qui sut pour les rcurrences usuelles. Ainsi le temps de parcours dune liste e 1 vrie : T (n) bn et celui du tri par slection : T (n) 2 bn2 . Dans le cas e e n gnral, k=1 kp peut ^tre estim par comparaison srie-intgrale, et lon a : e e e e e e
n

k=1

kp

np+1 p+1

pour p

0 et n .

Equation T (n) = aT (n 1) + f(n) On se ramne a une quation du type prcdent en posant U(n) = T (n)/a n e e e e ce qui donne :

82

Complexit des algorithmes e

U(n) = U(n 1) +

f(n) , an n f(k) U(n) = U(0) + , ak k=1 T (n) = an T (0) + f(k) . ak k=1


n

Si a 2 alors le temps dexcution de lalgorithme tudi est au moins e e e exponentiel. Par exemple pour le problme des tours de Hanoi : e
n

T (n) = 2n
k=1

2k

= 2n 1.

Dans le cas gnral on peut obtenir une conclusion plus prcise selon la vitesse de e e e croissance de f : { si la srie f(k)/ak converge (ce qui est en particulier le cas lorsque e k=1 f(n) est a croissance polynomiale) alors T (n) an pour une certaine constante en gnral non calculable explicitement ; e e { si f(n) an pour n alors T (n) nan ; b n { si f(n) bn pour n avec b > a alors T (n) b . ba

6-3

Rcurrence diviser pour rgner e e

Le principe ( diviser pour rgner ) conduit gnralement a ramener la rsoe e e e ( ) lution dun problme de taille n a celle dun ou plusieurs sous-problmes de taille e e approximativement n/2 puis a combiner les rsultats. Cest en particulier le cas e pour la recherche par dichotomie dans un vecteur tri, pour le tri par fusion, la e multiplication rapide des polyn^mes (mthodes de Knuth et transformation de o e Fourier rapide), et dans une moindre mesure pour le tri ( rapide ) : dans ce ( ) dernier cas, il nest pas garanti que la segmentation produise des sous-vecteurs de taille approximativement n/2. Les quations de rcurrence pour les algorithmes e e de type diviser pour rgner sont gnralement de la forme : e e e T (n) = aT ( n/2 ) + bT ( n/2 ) + f(n) (n 2)

o a et b sont des entiers naturels tels que a + b 1 et f est une fonction de N u dans N (le cas de base correspond a n = 1 plut^t qu n = 0). o a Cas o` n est une puissance de 2 u Lorsque n est une puissance de 2, n = 2p , on introduit une fonction auxiliaire U dnie par U(p) = T (2p ) et qui vrie donc : e e U(p) = (a + b)U(p 1) + f(2p ).

6-3 Rcurrence diviser pour rgner e e

83

On obtient alors : T (2p ) = U(p) = (a + b)p U(0) + f(2k ) . (a + b)k k=1


p

Posons a + b = 2 . Daprs la section 6-2, le comportement asymptotique e de T (2p ) est li a celui de la srie k=1 f(2k )/2k . e e { Si la srie f(2k )/2k converge, ce qui est ralis entre autres si e e e k=1 f(n) = O(n ) avec < , alors U(p) 2p soit T (n) n pour un certain > 0. { Si f(n) n alors U(p) p2p , soit T (n) n log2 (n). { Si f(n) n avec > alors U(p) 2p, soit T (n) n avec 2 = . 2 2 Par exemple le tri par fusion vrie T (n) = T ( n/2 ) + T ( n/2 ) + cn + d donc e = 1 et f(n) cn1 ce qui implique : T (n) cn log2 (n) lorsque n est une puissance de 2. Pour la multiplication polynomiale de Knuth, on a : T (n) = T ( n/2 ) + 2T ( n/2 ) + cn + d, donc = log2(3) 1.58 et f(n) cn1 do T (n) nlog2 3 pour un certain > 0. u Cas o` n nest pas une puissance de 2 u Si f est croissante, on prouve par rcurrence que la fonction T est croissante. e Lnonc de rcurrence est : e e e Hn pour 1 p q n, on a T (p) T (q).

n = 1 : il ny a rien a dmontrer. e n = 2 : il sut de constater que T (2) T (1) ce qui rsulte de lhypothse e e a + b 1. n 1 = n : par transitivit de la relation et en utilisant Hn1, il sut e de considrer le cas p = n 1 et q = n. Comme n 3 on a 2 p < q donc e on peut appliquer la relation de rcurrence a T (p) et T (q) : e T (p) = aT ( p/2 ) + bT ( p/2 ) + f(p) T (q) = aT ( q/2 ) + bT ( q/2 ) + f(q). Et lon a 1 p/2 q/2 < n, 1 et la croissance de f, on a bien T (p) p/2 T (q). q/2 < n donc daprs Hn1 e

Lhypothse de croissance de f peut ^tre dicile a prouver si f est complique, e e e mais, comme a la section 6-2, on constate que lon peut remplacer f par une fonction quivalente sans modier le comportement asymptotique de T (n), et si e lon obtient un quivalent de la forme n alors la croissance de lquivalent est e e vidente. e

84

Complexit des algorithmes e

Maintenant que lon sait que T est croissante, il sut dencadrer n par deux puissances successives de 2 pour obtenir une estimation asymptotique de T (n). Si 2p n < 2p+1 et T (2p ) 2p , alors : T (2p ) 2(p+1) T (n) n T (2p+1 ) 2p

et les deux termes extr^mes convergent pour n vers /2 et 2 donc e le rapport T (n)/n est born, cest--dire : T (n) = (n ). On obtient une e a conclusion similaire lorsque T (2p ) p2p , do le rsultat gnral : u e e e Thor`me : Soit T une fonction de N dans N vriant une quation de e e e e rcurrence de la forme : T (n) = aT ( n/2 ) + bT ( n/2 ) + f(n) avec a, b N e et a + b 1. On note = log2 (a + b). { Si f(n) = O(n ) avec < alors T (n) = (n ). { Si f(n) = (n ) alors T (n) = (n ln(n)). { Si f(n) = (n ) avec > alors T (n) = (n ). Schmatiquement, on peut retenir que T (n) est gnralement (n ), sauf si e e e le temps de sparation-recombinaison des sous-problmes est comparable ou supe e e rieur a cette borne, auquel cas T (n) est (n ln(n)) (cas comparable) ou (f(n)) (cas suprieur). e

6-4

Exercices

Exercice 6-1 : calcul de dterminant e 1. On veut calculer un dterminant nn en dveloppant rcursivement suivant e e e la premire colonne. Quelle est la complexit temporelle de ce projet ? e e 2. Pour amliorer le temps de calcul, on dcide de mmoriser tous les dtere e e e minants mineurs ncessaires de faon a viter de les calculer plusieurs fois. e c e Quelle est la nouvelle complexit temporelle, et quelle est la complexit spae e tiale ? Exercice 6-2 : multiplication matricielle Pour multiplier deux matrices n n il faut eectuer n3 multiplications scalaires et n2(n 1) additions en utilisant la formule du produit matriciel. Strassen a prsent un algorithme permettant de multiplier deux matrices 2 2 avec 7 e e multiplications seulement et 18 additions/soustractions : a c avec : p1 = a(f h), p2 = (a + b)h, p3 = d(e g), b d e f g h = p5 p 7 p 2 p 3 p4 p 3 p1 + p 2 p1 p 4 + p 5 p 6 p7 = (d b)(g + h).

p4 = (c + d)e, p5 = (a + d)(e + h), p6 = (a c)(e + f),

6-4 Exercices

85

De plus, cet algorithme peut stendre a des matrices n n en eectuant 7 mule tiplications et 18 additions/soustractions de matrices (n/2) (n/2). Si lon utilise la mthode de Strassen rcursivement pour calculer les proe e duits des matrices (n/2) (n/2), quelle complexit atteint-on pour le produit de e deux matrices n n ? Exercice 6-3 : temps moyen dune comparaison Pour classer deux cha^ nes de caractres par ordre alphabtique on compare leurs e e caractres de m^me rang jusqu puiser une cha^ ou a trouver deux caractres e e ae ne e dirents. Quel est le nombre moyen de comparaisons de caractres eectues e e e pour comparer deux cha^ nes de longueur n en supposant que toutes les cha^ nes sont quiprobables ? Etudier de m^me le temps moyen de comparaison de deux e e cha^ nes de longueur infrieure ou gale a n. e e Exercice 6-4 : relation de rcurrence e On considre la relation de rcurrence : e e T (n) = T (n 1) + T (n 2) + f(n) o f est une fonction positive donne a croissance polynomiale. u e 1. Donner un exemple dalgorithme dont le temps dexcution vrie cette ree e lation. 2. Chercher une estimation asymptotique de T (n). Exercice 6-5 : relation de rcurrence e Rsoudre asymptotiquement la relation de rcurrence : e e T (n) = 2T ( n/2 ) + n log2 (n). Exercice 6-6 : relation de rcurrence e Rsoudre asymptotiquement la relation de rcurrence : e e T (n) = 2T ( (n 1)/2 ) + n. Exercice 6-7 : comparaison dalgorithmes On veut calculer les termes de la suite (un) dnie par : e u0 = 1, un = u0 un1 un2 + + . .. + 1 2 n pour n 1.

Les deux programmes suivants calculent un :


let rec u_rec(n) = match n with | 0 -> 1.0 | _ -> let s = ref 0.0 in for k = 1 to n do s := !s +. u_rec(n-k)/.float_of_int(k) done; !s ;;

86

Complexit des algorithmes e let u_iter(n) = let v = make_vect (n+1) 0.0 in v.(0) <- 1.0; for p = 1 to n do for k = 1 to p do v.(p) <- v.(p) +. v.(p-k)/.float_of_int(k) done done; v.(n) ;;

Calculer les complexits asymptotiques temporelles et spatiales de ces fonctions. e Exercice 6-8 : comparaison dalgorithmes M^me question avec la relation de rcurrence et les programmes suivants : e e u0 = 1, un = u
n/2

+u

n/3

pour n

1.

let rec u_rec(n) = if n = 0 then 1 else u_rec(n/2) + u_rec(n/3) ;; let u_iter(n) = let v = make_vect (n+1) 0 in v.(0) <- 1; for i = 1 to n do v.(i) <- v.(i/2) + v.(i/3) done; v.(n) ;;

Chapitre 7 Arbres

7-1

Dnitions e

Arbres gnraux e e Un arbre gnral est un ensemble non vide et ni dobjets appels nuds e e e et lis par une ( relation de parent ) : e e ) ( xF y x F y x est un ls de y y est le pre de x ; e x est un descendant de y y est un anc^tre (ascendant) de x e x = y ou il existe un chemin : x = x0 F x1 F . .. F xn = y tel que chaque lment est le pre de llment prcdent ; ee e ee e e

avec les proprits : ee { il existe un unique lment nayant pas de pre, appel racine de larbre ; ee e e { tout lment a part la racine a un et un seul pre ; ee e { tout lment est un descendant de la racine. ee Vocabulaire : { Un nud nayant pas de ls est appel feuille ou nud terminal et un nud e ayant au moins un ls est appel nud interne ou nud intrieur. e e { Les ls dun m^me nud sont appels frres. e e e { Le degr dun nud est son nombre de ls, le degr maximal de larbre est e e le plus grand des degrs des nuds. e { La profondeur dun nud est le nombre dascendants stricts de ce nud, la hauteur dun arbre est la profondeur maximale de ses nuds. { Le nombre de nuds dans un arbre est la taille de larbre. { Lensemble des descendants dun nud x forme un sous-arbre de racine x.

88

Arbres

{ Une for^t est un ensemble ni darbres sans nuds communs ; lensemble e des descendants stricts dun nud x forme une for^t, vide si le nud est e terminal. Les arbres de cette for^t sont appels branches issues de x. e e { Un arbre ordonn est un arbre pour lequel lensemble des branches issues e dun nud est totalement ordonn. e { Un arbre est tiquet lorsqu chaque nud est associe une information e e a e appele tiquette du nud. Des nuds distincts peuvent porter la m^me e e e tiquette. e Exemples darbres : (cf. gure 15) { Larbre dune expression arithmtique ou logique est un arbre dont les nuds e intrieurs sont tiquets avec les oprateurs composant cette expression et les e e e e branches reprsentent les oprandes associs. Cest un arbre ordonn. e e e e { Un systme de chiers est reprsent par un arbre dont les nuds sont e e e tiquets avec des noms de chiers ou de rpertoires. Les nuds intrieurs e e e e correspondent aux rpertoires non vides et les feuilles aux chiers de donnes e e et aux rpertoires vides. e { Une taxinomie classe des objets suivant une description hirarchique. Chae que nud correspond a une sous-classe incluse dans celle du nud pre. e { Un arbre de dcision modlise la rsolution dun problme par une suite de e e e e tests imbriqus. e { Larbre dappels dune fonction rcursive reprsente le calcul de cette fonce e tion, les feuilles correspondant aux cas de base et les nuds intrieurs aux e cas rcursifs. e { Un arbre dynastique reprsente les descendants (gnralement m^les) dun e e e a individu et correspond a la notion usuelle de parent. Un arbre gnalogique e e e reprsente les ascendants dun individu. Par drogation un arbre gnalogique e e e e a sa racine en bas, mais il ne sagit rellement dun arbre que si lon ne ree monte pas trop loin dans le pass sinon un m^me ascendant risque dappae e ra^ dans plusieurs branches. tre Arbres binaires Un arbre binaire est un ensemble ni, ventuellement vide, de nuds lis e e par une relation de parent oriente : e e x Fd y x Fg y x est le ls droit de y = y est le pre de x ; e x est le ls gauche de y = y est le pre de x ; e

avec les proprits : ee { si larbre est non vide alors il existe un unique lment nayant pas de pre, ee e appel racine de larbre ; e { tout lment a part la racine a un et un seul pre ; ee e

7-1 Dfinitions e

89

sin x y z
dos command.com

C:\ windows win.ini system win32.dll caml camlc emacs

expression sin(x yz)

systme de chiers e
a=0?

oui b=0? oui c=0? oui S=R non S= S = {c/b} S = {(b )/2a} non >0

non ? =0 <0

S = {b/2a}

S=

arbre de dcision pour ax2 + bx + c = 0 sur R e C2 4 vgtal e e C1 3 a feuilles eur herbe a aiguilles C0 = 1 2 sapin C0 = 1 1 taxinomie C1 = 1 1 C0 = 1 1 C1 = 1 1 C1 2 C1 2 C2 = 1 2 C2 3

arbre dappels pour le calcul de C2 4

Figure 15 : exemples darbres

90

Arbres

{ tout lment a au plus un ls droit et au plus un ls gauche ; ee { tout lment est un descendant de la racine. ee Si x est un nud dun arbre binaire, alors x possde deux branches qui sont e des arbres binaires : la branche droite est larbre des descendants de son ls droit sil existe, larbre vide sinon ; la branche gauche est larbre des descendants de son ls gauche sil existe, larbre vide sinon. Les notions darbre gnral ordonn et e e e darbre binaire dirent par lexistence de larbre vide dans la catgorie des arbres e e binaires, et par le fait quun nud dun arbre binaire a toujours deux branches, ventuellement vides. En particulier, un arbre binaire na pas de feuilles. e a b c d a b c d a b c d arbre gnral e e

arbres binaires dirents e

7-2

Reprsentation en mmoire e e

Reprsentation des arbres binaires e


type a b_arbre = | B_vide | B_noeud of a * (a b_arbre) * (a b_arbre) ;; let etiquette(a) = match a with | B_vide -> failwith "arbre vide" | B_noeud(e,_,_) -> e and gauche(a) = match a with | B_vide -> failwith "arbre vide" | B_noeud(_,g,_) -> g and droite(a) = match a with | B_vide -> failwith "arbre vide" | B_noeud(_,_,d) -> d ;;

Un arbre binaire non vide est reprsent par un triplet (e, g, d) o e est e e u ltiquette de la racine et g, d sont les branches gauche et droite issues de la e racine. B_vide et B_noeud sont des identicateurs symboliques appels construce teurs permettant de discriminer les deux cas possibles pour un arbre binaire. En mmoire un arbre binaire est reprsent par le code du constructeur suivi des e e e

7-2 Reprsentation en mmoire e e

91

reprsentations des arguments dans le cas B_noeud. En caml, avec la dnition e e prcdente, les sous-arbres gauche et droit sont matrialiss par des pointeurs, de e e e e m^me que ltiquette e si elle est plus complexe quun entier, ce qui permet de e e garantir un temps daccs constant a chacune des composantes dun nud. e
B vide B noeud

e g d

La construction explicite dun arbre peut ^tre pnible. Le code suivant : e e


let a = B_noeud(1, B_noeud(2, B_noeud(3, B_noeud(4, B_noeud(5, B_noeud(6, B_noeud(7, ;;

B_vide, B_vide, B_vide, B_vide,

B_vide), B_vide)), B_vide), B_vide)))

1 dnit larbre a tiquettes entires : e e e 2 5

3 4 6 7 Reprsentation par un vecteur e Les nuds dun arbre binaire peuvent ^tre numrots par profondeur croise e e sante et ( de gauche a droite ) a profondeur gale : e ( ) 1 2 4 8 9 5 6 3 7

10 11 12 13 14 15

De manire gnrale, le nud numro i a pour ls ventuels les nuds numro e e e e e e 2i et 2i + 1, et le pre du nud numro j est le nud numro j/2 . Cette e e e numrotation permet de mettre un arbre binaire a en correspondance avec un e vecteur v : ltiquette du nud numro i est place dans la cellule v.(i) et, e e e lorsquun nud nest pas prsent dans a, la cellule correspondante est ignore. e e Cette reprsentation est surtout utilise pour les arbres binaires parfaits o tous e e u les niveaux de profondeur sauf le dernier sont complets et o les nuds du dernier u niveau sont situs le plus a gauche possible. e

92

Arbres

Reprsentation des arbres gnraux e e e


type a g_arbre = G_noeud of a * (a g_arbre list);; let etiquette(a) = match a with | G_noeud(e,_) -> e and for^t(a) = match a with e | G_noeud(_,f) -> f ;;

Un arbre est reprsent par ltiquette de sa racine et la liste des branches e e e issues de la racine. Pour un arbre ordonn, lordre des branches dans cette liste e est important et un ordre dirent dnit un arbre dirent ; pour un arbre non e e e ordonn lordre des branches doit ^tre ignor et un m^me arbre admet plusieurs e e e e reprsentations, ce qui doit ^tre pris en compte lors des tests dgalit entre are e e e bres. Une feuille est un nud dont la liste des branches est vide. Lexpression arithmtique sin(x yz) peut ^tre mise en arbre par la dclaration : e e e
let expr = G_noeud( "sin", [G_noeud( "-", [G_noeud( "x", []); G_noeud( "*", [G_noeud("y", []); G_noeud("z",[])]) ]) ]) ;;

Le constructeur G_noeud est en principe inutile puisquil ny a quune forme possible pour un arbre : (racine, branches). On la introduit pour insister sur le fait quon manipule un arbre et non un couple quelconque. Cette coquetterie ne co^te rien car le compilateur caml actuel rserve toujours une place pour le code u e du constructeur, quil y en ait un explicite ou non. En pratique cette dnition est trop gnrale, et on prfre souvent dnir e e e ee e un type particulier mieux adapt aux arbres que lon doit manipuler. Par exemple e pour les expressions arithmtiques, on peut dnir plusieurs types de feuilles (ene e tiers, rels, variables, .. . ) et plusieurs types de nuds internes (oprateurs unaires, e e binaires, .. . ) ce qui permet de mieux reter la structure dune expression : e
type a expression = | Const of a | Variable of string | Op1 of (a -> a) * (a expression) | Op2 of (a -> a -> a) * (a expression) * (a expression) ;;

(cf. ltude des expressions boolennes, section 5-4). Lavantage dune descripe e tion spcialise est une meilleure lisibilit du code, linconvnient est que les ale e e e gorithmes gnraux de manipulation et parcours darbres doivent ^tre rcrits a e e e ee

7-2 Reprsentation en mmoire e e

93

chaque nouvelle dnition de type, et que la longueur du code augmente avec la e multiplication des cas a tester. On pourrait dailleurs spcialiser encore plus la e description dune expression en listant tous les oprateurs possibles (+, , , .. . ). e Quoi quil en soit, la reprsentation interne dun nud est semblable a celle vue e pour les nuds darbres binaires, mais les direntes branches issues dun nud e sont cha^ ees entre elles et le temps daccs a une branche particulire dpend de n e e e son rang (cf. gure 16). On pourrait utiliser un vecteur au lieu dune liste cha^ ee n pour stocker les pointeurs vers les branches, une branche quelconque et le degr e dun nud seraient alors accessibles en un temps constant.
G noeud

e
Liste Liste

ls1

ls2

gure 16 : reprsentation dun nud dans un arbre gnral e e e Reprsentation ascendante e La reprsentation (racine,branches) permet un accs facile aux nuds de e e larbre en partant de la racine, ce qui correspond au mode daccs le plus frquent. e e Il ny a aucun moyen avec cette reprsentation de conna^ e tre le pre dun nud e a partir du nud lui m^me. Dans certains cas pourtant, on peut avoir besoin e de remonter vers la racine, par exemple a partir du nom dune ville retrouver son dpartement, sa rgion, son pays, .. . Les arbres binaires parfaits rangs e e e dans un vecteur permettent cette remonte. Dans le cas gnral on adopte une e e e reprsentation inverse : e
type a a_noeud = A_vide | A_noeud of a * (a a_noeud);; let etiquette(n) = match n with | A_vide -> failwith "noeud vide" | A_noeud(e,_) -> e and p`re(n) = match n with e | A_vide -> failwith "noeud vide" | A_noeud(_,p) -> p ;;

Larbre gographique de la France est dclar par : e e e


let let let let let let france ilefr paris bourg dijon auxr = = = = = = A_noeud("France", A_vide);; A_noeud("^le de France", france);; I A_noeud("Paris", ilefr);; A_noeud("Bourgogne", france);; A_noeud("Dijon", bourg);; A_noeud("Auxerre", bourg);;

France

Ile de France

Bourgogne

Paris

Dijon

Auxerre

94

Arbres

La racine de larbre est reconnue comme telle par son pre particulier : e
A_vide. Dans cette reprsentation il nest pas garanti que deux nuds appare

tiennent bien au m^me arbre, il faut remonter jusquaux racines pour le constater. e On reprsente donc en fait une for^t non ordonne plut^t quun unique arbre. e e e o Enn, dans le cas o lon a besoin de pouvoir monter et descendre dans un arbre, u on peut utiliser une reprsentation mixte o chaque nud contient un lien vers e u son pre et un lien vers ses ls. e Reprsentation e e ( ls gauche - fr`re droit ) ( )

Dans cette reprsentation chaque nud contient un lien vers son premier ls e et un lien vers son frre suivant appel ( frre droit ) (cf. gure 17). Chaque e e ( e ) nud na plus que deux liens, ventuellement vides, ce qui transforme un arbre e ordonn quelconque en un arbre binaire dont la racine na pas de ls droit et une e for^t darbres ordonns en un arbre binaire quelconque. Cette reprsentation nest e e e pas fondamentalement dirente de celle o tous les ls sont rangs dans une liste e u e cha^ ee, mais elle est plus conomique en termes de mmoire. n e e

a b c d e
ef g hi j kl m

a b c f g h i j k l m d

Figure 17 : reprsentation ls gauche - frre droit e e

7-3

Parcours dun arbre

Pour appliquer un m^me traitement a tous les nuds de cet arbre, par exeme ple les compter, les imprimer ou comparer leur tiquette a une valeur donne, il e e faut parcourir larbre. On distingue deux mthodes de parcours. e

Figure 18 : parcours en profondeur et en largeur

7-3 Parcours dun arbre

95

{ Le parcours en profondeur dabord : partant de la racine, on descend le plus bas possible en suivant la branche la plus a gauche de chaque nud, puis on remonte pour explorer les autres branches en commenant par la c plus basse parmi celles non encore parcourues. { Le parcours en largeur dabord : partant de la racine, on explore tous les nuds dun niveau avant de passer au niveau suivant. La complexit temporelle dun parcours darbre est au minimum proportione nelle au nombre de nuds visits, donc a la taille de larbre si le parcours nest pas e interrompu prmaturment. Il y a proportionnalit lorsque le temps de traitement e e e dun nud, non compris le temps de traitement de sa descendance, est constant. La complexit spatiale dpend du type de parcours : pour un parcours en proe e fondeur il faut conserver la liste des branches non encore explores, ce qui requiert e un nombre xe de mots mmoire par anc^tre strict du nud visit (un pointeur e e e vers lanc^tre et le numro de la premire branche non explore par exemple), donc e e e e la complexit spatiale est proportionnelle a la hauteur de larbre. Pour un pare cours en largeur il faut conserver une liste de pointeurs vers les branches du niveau en cours, et la complexit spatiale est proportionnelle a la largeur de larbre (le e plus grand nombre de nuds de m^me niveau). e Ces estimations de complexit peuvent ^tre modies par une reprsentation e e e e particulire de larbre, par exemple un arbre binaire parfait stock dans un vecteur e e permet un parcours en largeur ou en profondeur a mmoire constante. e Parcours en profondeur dun arbre binaire
let rec parcours(a) = match a with | B_vide -> () | B_noeud(e,g,d) -> traitement prfixe; e parcours(g); traitement infixe; parcours(d); traitement postfixe ;;

traitement prxe, traitement inxe et traitement poste xe dsignent des actions ou calculs ventuels a eectuer. e e Lordre dapplication de ces traitements est : prxe : nud, descendants droits, descendants gauches. e inxe : descendants droits, nud, descendants gauches. postxe : descendants droits, descendants gauches, nud.
prfixe Noeud infixe postfixe

Lordre prxe, lordre inxe et lordre postxe constituent des relations e dordre total sur les nuds dun arbre binaire. Lordre inxe est aussi appel ordre e symtrique (cf. exercice 7-8). Le numro prxe inxe ou postxe dun nud e e e est son rang dans lordre correspondant. Par exemple le code suivant imprime les tiquettes dun arbre avec les numros postxe : e e

96 (* a = arbre, n = numro postfixe e *) (* retourne le prochain numro postfixe *) e let rec imprime a n = match a with | B_vide -> n | B_noeud(e,g,d) -> let n = imprime g n in let n= imprime d n in print_int(n); print_char(:); print_string(e); print_newline(); n+1 ;; let a = B_noeud("France", B_noeud("Ile de France", B_noeud("Paris", B_vide, B_noeud("5`me arr.", B_vide,B_vide)), e B_noeud("Versailles",B_vide,B_vide)), B_noeud("Bourgogne", B_noeud("Dijon",B_vide,B_vide), B_noeud("Auxerre",B_vide,B_vide))) in imprime a 1;; 1:5`me arr. e 2:Paris 3:Versailles 4:Ile de France 5:Dijon 6:Auxerre 7:Bourgogne 8:France - : int = 9

Arbres

France Ile de France Paris Versailles Bourgogne Dijon Auxerre

5me arr. e

Remarque : larbre dappels de la fonction parcours est un arbre binaire isomorphe a larbre parcouru. Parcours en profondeur dun arbre gnral e e La mthode est la m^me : eectuer un traitement prxe sur la racine, e e e parcourir chaque branche en eectuant ventuellement un traitement entre deux e branches, puis eectuer un traitement postxe avant de quitter la racine. Si larbre est ordonn, cest--dire si lordre de succession des branches est dni, alors on e a e peut dnir lordre et la numrotation prxe et postxe des nuds. Il ny a pas e e e dordre inxe. Par exemple lvaluation dune expression arithmtique mise sous e e forme darbre consiste a parcourir larbre en valuant les branches puis en valuant e e les oprations une fois que tous les oprandes sont connus. Lordre de traitement e e des nuds est donc un ordre postxe (le nud est trait aprs sa descendance, e e mais celle-ci peut l^tre dans nimporte quel ordre) et lalgorithme dvaluation e e

7-3 Parcours dun arbre

97

est la transcription en termes darbres de lvaluation dune formule postxe, la e pile de rcursion de caml remplaant la pile de valeurs. e c
type a formule = | Valeur of a | Op1 of (a -> a) * (a formule) | Op2 of (a -> a -> a) * (a formule) * (a formule) | Opn of (a -> a -> a) * a * (a formule list) (* Opn = oprateur binaire associatif : +,*,... *) e ;; (* le 2`me champ est llment neutre associ *) e e e e let rec evalue(f) = match f with | Valeur(v) -> v | Op1(op,g) -> op (value g) e | Op2(op,g,h) -> op (value g) (value h) e e | Opn(op,neutre,l) -> evalue_liste(op, neutre, l) and evalue_liste(op,accu,liste) = match liste with | [] -> accu | f::suite -> evalue_liste(op, op accu (value f), suite) e ;;

Une formule est reprsente par un arbre dont les feuilles sont tiquetes e e e e par des valeurs et les nuds internes sont tiquets par des oprateurs unaires ou e e e binaires. Le constructeur Opn correspond a la rptition dun oprateur binaire e e e associatif pour lequel on spcie llment neutre qui est retourn en guise de e ee e valeur dans le cas dune liste vide. Le caractre postxe du traitement eectu e e nappara^ pas clairement dans le code de evalue, mais rsulte de la convention t e caml comme quoi les arguments dune fonction sont calculs avant que le code de e la fonction soit excut. Par exemple la ligne : e e
| Op2(op,g,h) -> op (value g) (value h) e e

est traduite par le compilateur caml en lquivalent machine de : e


Si f est de la forme Op2(op,g,h) alors : calculer x = evalue(g) calculer y = evalue(h) retourner op x y.

De m^me, la fonction evalue_liste eectue lvaluation rcursive des brane e e ches dune opration multiple et un traitement inxe entre chaque branche, a e savoir le calcul et stockage des rsultats partiels dans accu. Exemple : e
let f = Opn(add_int, 0, [Op2(mult_int, Valeur 1, Valeur 2); Op2(div_int, Valeur 9, Valeur 3); Valeur 5; Opn(mult_int, 1, [Valeur 2; Valeur 3; Valeur 4])]) in evalue(f);; - : int = 34

98

Arbres

Parcours en largeur dabord Le parcours en largeur dabord est surtout utilis dans les situations de e recherche dans un arbre o lon ne peut pas dterminer quelle est la branche u e a explorer, et o lon ne veut pas explorer larbre en entier. Par exemple la u recherche des feuilles de profondeur minimum dans un arbre de jeu de grande hauteur (quel est le moyen le plus rapide de ( mater ) aux checs a partir dune e ( ) position donne ?) conduit a un parcours en largeur. Ce type de parcours est e mal adapt a la reprsentation hirarchique dun arbre, mais peut-^tre eectu en e e e e e tenant a jour la liste des branches restant a visiter :
(* constitue la liste des branches dune liste de noeuds *) let rec liste_fils lnoeuds = match lnoeuds with | [] -> [] | G_noeud(_,f)::suite -> f @ liste_fils(suite) ;; (* parcours en largeur dune for^t *) e let rec parcours traitement for^t = match for^t with e e | [] -> () | _ -> do_list traitement for^t; e parcours traitement (liste_fils for^t) e ;; (* parcours en largeur dun arbre *) parcours traitement [arbre];;

On utilise ici la reprsentation (tiquette, liste des ls) dun arbre gnral. e e e e
do_list est une fonction prdnie en caml qui parcourt une liste et applique la e e fonction traitement a chaque lment. Par rcurrence sur sa hauteur, parcours ee e applique traitement a chaque nud de for^t, par ordre de niveau et dans un m^me e e

niveau ( de gauche a droite ) . Si lon veut eectuer une recherche ou un calcul ( ) sur les nuds de la for^t alors il sut de modier en consquence linstruction : e e do_list traitement for^t. e Complexit : on suppose que traitement a un temps dexcution constant et donc e e que litration de traitement sur une liste a un temps dexcution proportionnel e e a la longueur de cette liste. Le temps dexcution dun appel a liste_fils, sans e compter les appels rcursifs qui en dcoulent, est de la forme T = ad + b o a e e u et b sont des constantes et d le degr du nud considr. Le temps dexcution e ee e de parcours pour une for^t de k nuds ayant ensemble k ls, non compris le e parcours de la for^t des ls, est de la forme : T = ak + ck. Dans le parcours e complet dun arbre, chaque nud co^te donc a + c units de temps (c seulement u e pour la racine) et le temps total de parcours est linaire par rapport a la taille de e larbre.

7-4 Dnombrements sur les arbres binaires e

99

7-4

Dnombrements sur les arbres binaires e

Calculs lmentaires ee Thor`me : e e 1. Un arbre binaire a n nuds possde n + 1 branches vides. e 2. Dans un arbre binaire a n nuds, le nombre de nuds sans ls est infrieur ou gal a (n + 1)/2. Il y a galit si et seulement si tous les e e e e nuds ont zro ou deux ls. e 3. La hauteur dun arbre binaire non vide a n nuds est comprise entre log2 n et n 1. Dmonstration : e 1. Par rcurrence sur n. e 2. Soient p le nombre de nuds ayant un seul ls et q le nombre de nuds sans ls. p + 2q = n + 1 (nombre de branches vides) donc q = (n + 1 p)/2. 3. Dans un arbre de taille n la profondeur dun nud est son nombre dascendants stricts donc est infrieure ou gale a n 1. La hauteur dun arbre est e e la plus grande profondeur donc est aussi majore par n 1. e Un arbre binaire non vide de hauteur h a au plus 1 + .. . + 2h = 2h+1 1 nuds. Soit a un arbre binaire de taille n et h = log 2 n : tout arbre binaire non vide de hauteur infrieure ou gale a h 1 a au plus 2h 1 < n nuds e e donc la hauteur de a est au moins gale a h. e Application aux calculs de complexit e Considrons un arbre de dcision binaire (chaque test na que deux issues) e e ayant N sorties. Une sortie est une branche vide (il ny a plus de test a faire) donc cet arbre possde N 1 nuds et a une hauteur au moins gale a log2 (N 1) . e e Ceci signie que le nombre de tests a eectuer dans le pire des cas est au moins gal e a 1 + log2(N 1) = log 2 N . On obtient ainsi une minoration de la complexit e intrinsque dun problme. e e Par exemple le tri comparaisons de n lments distincts a une complexit ee e dans le pire des cas au moins gale a log2(n!) , complexit compte en nombre e e e de comparaisons, puisquune issue du tri est une permutation des lments les ee remettant dans lordre, permutation bien dnie si les lments sont distincts, et e ee toutes les permutations sont possibles (voir lexercice 7-19 pour une construction formelle de larbre de dcision associ a un algorithme de tri par comparaisons). e e Cela prouve que la complexit intrinsque dans le pire des cas du tri par compae e raisons est (n ln n). Le minorant obtenu par cette mthode nest pas toujours aussi pertinent. e La recherche du plus grand lment dans une liste de taille n produit un arbre ee

100

Arbres

de dcision a n issues (une issue est la la position de ce plus grand lment), elle e ee ncessite donc au moins log2 n comparaisons. Mais en ralit il est impossible de e e e conna^ le plus grand lment sans les avoir tous examins, donc la complexit tre ee e e intrinsque de ce problme est (n). e e Dans le m^me ordre dides, un calcul dpendant de n variables et ralis e e e e e par des oprations binaires ne peut ^tre conduit en moins de log2 (n) units de e e e temps dans le pire des cas m^me si lon eectue autant doprations binaires e e en parallle que lon veut. Larbre exprimant le calcul a eectuer, dont les nuds e sont les oprateurs binaires et les feuilles sont les variables, possde n feuilles donc e e a une hauteur au moins gale a log2 n . Ainsi il est impossible de dterminer par e e comparaisons le plus grand lment dune liste de taille n sur une machine parallle ee e en moins de log2 n units de temps, et le minorant est cette fois pertinent (cf. e multiplication en parallle, section 6-1). e Arbres quilibrs e e Un arbre binaire est dit quilibr en hauteur sil est vide ou si pour tout e e nud x, les branches gauche et droite issues de x ont m^me hauteur a une unit e e prs. e
dsquilibre 4 2 1 0 0 0 0 2 1 3 1 0 1 0 0 2 0 0 1 0 4 3 2 0

Figure 19 : arbres quilibr et dsquilibr e e e e e Remarquons que la proprit dquilibre est une proprit globale valable pour ee e ee larbre entier et pour tous ses sous-arbres. Thor`me : Soit h la hauteur dun arbre quilibr en hauteur a n nuds e e e e 1+ 5 et = 2 . Alors log2 (n + 1) h + 1 < log (n + 2). Dmonstration : e Pour h N soient m(h) et M(h) le plus petit et le plus grand nombre de nuds dun arbre quilibr de hauteur h. On a pour h 2 : e e m(h) = 1 + m(h 1) + min(m(h 1), m(h 2)),

M(h) = 1 + M(h 1) + max(M(h 1), M(h 2)). Par consquent les fonctions m et M sont croissantes sur N et m(0) = M(0) = 1, e m(1) = 2, M(1) = 3, donc elles sont croissantes sur N. On en dduit : e m(h) + 1 = (m(h 1) + 1) + (m(h 2) + 1),

M(h) + 1 = 2(M(h 1) + 1),

7-4 Dnombrements sur les arbres binaires e

101

et donc : M(h) + 1 = c2h ,

m(h) + 1 = ah + b ,

o a, b, c sont des constantes indpendantes de h, = 1+2 5 et = 12 5 (voir u e ltude de la suite de Fibonacci dans le cours de mathmatiques). Compte tenu e e des conditions initiales, on obtient : h+3 )/ 5, m(h) + 1 = (h+3 M(h) + 1 = 2h+1 . La deuxime galit donne h + 1 = log2 (M(h) + 1) e e e log2 (n + 1). La premire e h+3 h+3 h+3 implique = (m(h) + 1) 5 + < (m(h) + 2) 5 car < 1 < 5 donc : h + 1 < log (m(h) + 2) + log ( 5) 2 < log (m(h) + 2) log(n + 2).

En consquence, la hauteur dun arbre quilibr en hauteur est (ln n) ce qui e e e signie que les algorithmes de recherche en profondeur dans un tel type darbre ont une complexit logarithmique. e Dnombrement des arbres binaires a n nuds e ` Soit Cn le nombre darbres binaires non tiquets a n nuds. On a C0 = 1, e e C1 = 1, C2 = 2, C3 = 5 et C4 = 14. De manire gnrale, un arbre binaire a e e e n nuds sobtient en choisissant deux arbres binaires a k et n k 1 nuds indpendamment, et en les reliant a une racine, larbre a k nuds tant a gauche. e e On a donc la relation de rcurrence : e
n1

Cn =
k=0

Ck Cnk1

(n

1).

Notons C(z) = n=0 Cnzn la srie gnratrice associe. En multipliant la e e e e relation prcdente par zn1 et en sommant de n = 1 a , on obtient : e e 1 1 4z C(z) C0 2 2 = C(z) zC(z) C(z) + 1 = 0 C(z) = z 2z et C tant de classe C au voisinage de 0, le est en fait un . Il est e ainsi prouv e que, si la srie C a un rayon de convergence non nul alors, C(z) = (1 1 4z)/2z. e Considrons alors la fonction dnie par : e e 1 1 4z f(z) = . 2z f est dveloppable en srie entire, e e e 1 1/2 Cn n 2n z = an z n f(z) = (4)n+1 zn = 2 n+1 n+1 n=0 n=0 n=0

pour |z| < 1,

102

Arbres

et les coecients (an ) vrient la relation : e


n1

an =
k=0

ak ank1

pour n 1 car les deux membres sont les coecients des dveloppements en srie e e entire de (f(z) a0 )/z et f(z)2 , et ces fonctions sont gales par construction de f. e e Enn, comme a0 = 1 = C0, on peut conclure : n N, Cn = an = Cn 2n . n+1

Le nombre Cn est appel n-me nombre de Catalan, et lon a daprs la e e e formule de Wallis : 4n Cn 3/2 (n ). n Profondeur moyenne dun nud La mthode ( srie gnratrice ) prcdente peut aussi ^tre utilise pour e e e e e ( e ) ee dterminer la profondeur moyenne dun nud dans un arbre binaire de taille n. e Notons Pn la somme des profondeurs de tous les nuds de tous les arbres binaires n a n lments et P(z) = ee e n=0 Pn z . En dcomposant un arbre a n nuds en son sous-arbre gauche a k nuds et son sous-arbre droit a n k 1 nuds, et en observant que la profondeur dun nud augmente de 1 quand on passe du sous-arbre a larbre complet, on obtient :
n1

Pn =
k=0

(Cnk1(Pk + kCk ) + Ck(Pnk1 + (n k 1)Cnk1) )


n1 n1

= (n 1)Cn +

Cnk1Pk +
k=0 k=0

Ck Pnk1,

ce qui se traduit en termes de sries gnratrices par : e e e C(z) C0 P(z) P0 = C (z) + 2P(z)C(z) z z avec P0 = 0, do : u 1 1 1 zC (z) C(z) + 1 1 = + + . 1 2zC(z) 1 4z z 1 4z 1 4z z Comme prcdemment, la fonction dnie par lexpression ci-dessus est dvelope e e e pable en srie entire et ses coecients vrient par construction la m^me quation e e e e e de rcurrence que les Pn , donc on peut les identier, ce qui donne : e P(z) = Pn = 4n (n + 2)Cn+1 + (n + 1)Cn (n 1). La profondeur moyenne dun nud dans un arbre binaire quelconque a n lments est donc : ee Pn pn = n (n ). nCn

7-4 Dnombrements sur les arbres binaires e

103

Arbres binaires construits alatoirement e Le rsultat prcdent a t tabli en supposant que tous les arbres binaires a e e e eee n nuds sont quiprobables. Un autre modle de probabilit consiste a considrer e e e e quun arbre binaire donn a t construit par adjonction un a un de nuds dans un e ee ordre alatoire. Plus prcisment, on suppose quun arbre a de taille n sobtient e e e a partir dun arbre a de taille n 1 par transformation dune branche vide en une branche a un nud, et que les n branches vides de a sont choisies avec la m^me probabilit 1/n. Cette hypothse est vrie dans le cas des arbres binaires e e e e e de recherche si lon procde a linsertion ( aux feuilles ) des entiers 1, 2, . .., n e ( ) dans un ordre alatoire (cf. section 8-2). Dans ce modle de probabilit, il y a n! e e e arbres binaires a n nuds (non tous distincts puisque Cn < n!) et la profondeur moyenne dun nud est la somme des profondeurs des tous les nuds de ces n! arbres, divise par n n!. e Pour un arbre binaire a on note Li (a) la somme des profondeurs des n nuds (longueur du chemin interne de a) et Le (a) la somme des profondeurs des n + 1 branches vides (longueur du chemin externe de a), en convenant que la profondeur dune branche vide est gale a la profondeur du nud dont elle e est issue augmente dune unit. On note aussi Li (n) et Le (n) les sommes des e e quantits Li (a) et Le (a) pour les n! arbres binaires a n nuds. e Si a est un arbre binaire a n 1 nuds et si a se dduit de a par transfor e mation dune branche de profondeur p en un nud alors on a : Li (a) = Li (a ) + p, On en dduit : e Li (n) = nLi(n 1) + Le (n 1), Le (n) = (n + 1)Le (n 1) + 2 n! Le (a) = Le (a ) + p + 2.

avec les conditions initiales : Li (1) = 0, Le (1) = 2. On obtient alors successivement : Li (n 1) Le (n 1) Li (n) = + , n! (n 1)! n! Le (n) Le (n 1) 2 = + , (n + 1)! n! n+1 Li (n) =2 n!
n

1 1 Le (n) =2 + . .. + , (n + 1)! 2 n+1

k=2

1 1 + . .. + . 2 k

Comme 1/2 + . . . + 1/k ln(k) lorsque k , on peut appliquer le lemme de Csaro : e n Li(n) ln(k) = 2 ln(n!) 2n ln(n). 2 n!
k=2

Ainsi, la profondeur moyenne dun nud dans un arbre binaire de n lments construit alatoirement est : ee e Li (n) 2 ln(n). n n!

104

Arbres

7-5

Exercices

Exercice 7-1 : relation entre les nombres de nuds Si un arbre a contient n0 nuds de degr 0 (feuilles), n1 nuds de degr 1, .. . , e e np nuds de degr p, quelle relation y a-t-il entre n0, n1, . .. , np ? e Exercice 7-2 : nombre moyen de ls On suppose ici que tous les arbres binaires a n nuds sont quiprobables. Dans e un arbre binaire de taille n, combien un nud a-t-il de ls en moyenne ? Combien a-t-il de ls droits en moyenne ? Exercice 7-3 : ordre des feuilles Montrer que lordre prxe et lordre postxe induisent la m^me relation dordre e e sur les feuilles dun arbre. Exercice 7-4 : reconstitution dun arbre a partir des ordres prxe et ` e postxe Soient x, y deux nuds dun arbre a. Montrer que x est un ascendant de y si et seulement si x prcde y en ordre prxe et succde a y en ordre postxe. e e e e Exercice 7-5 : reprsentation ls gauche, fr`re droit e e Ecrire une fonction caml transformant une for^t darbres gnraux en un arbre e e e binaire suivant la convention ( ls gauche - frre droit ) et une fonction eectuant e ( ) la transformation inverse. Exercice 7-6 : reprsentation ls gauche, fr`re droit e e Soient a un arbre gnral ordonn et a larbre binaire associ a a dans la repre e e e e sentation ls gauche, frre droit. Quel rapport y a-t-il entre les ordres prxe et e e postxe des nuds de a et les ordres prxe, postxe et inxe des nuds de a ? e Exercice 7-7 : arbres binaires parfaits Soit a un arbre binaire parfait a n nuds rang dans un vecteur v. Peut-on e calculer en mmoire constante les indices des successeurs dun nud dindice i e pour les ordres prxe, inxe, postxe ? e Exercice 7-8 : ordres de parcours inverses Le parcours prxe inverse dun arbre consiste a traiter un nud dabord puis e ensuite a parcourir les branches issues de ce nud en commenant par la dernire c e branche. On dnit de m^me lordre postxe inverse et, pour un arbre binaire, e e lordre inxe inverse. Comparer ces ordres aux ordres de parcours directs. Exercice 7-9 : fonctions de parcours Etudier les fonctions de parcours suivantes (quel est lordre de parcours, quelle est la complexit asymptotique du parcours ralis en supposant que traitement a un e e e temps dexcution constant) : e
let rec parcours traitement for^t = match for^t with e e | [] -> () | G_noeud(e,f)::suite -> traitement(e); parcours traitement (f @ suite) ;;

7-5 Exercices let rec courspar traitement for^t = match for^t with e e | [] -> () | G_noeud(e,f)::suite -> traitement(e); courspar traitement (suite @ f) ;;

105

Exercice 7-10 : transformation dun arbre binaire en liste Ecrire une fonction liste_prfixe qui constitue la liste des tiquettes des nuds e e dun arbre binaire suivant lordre prxe. Analyser sa complexit temporelle (il e e existe une solution de complexit linaire par rapport a la taille de larbre). e e Exercice 7-11 : impression textuelle dun arbre Ecrire une fonction imprime_arbre_binaire qui prend en argument une fonction de conversion a -> string et un arbre binaire a tiquettes de type a et limprime e sous forme semi graphique. Par exemple, on devra avoir :
imprime_arbre_binaire string_of_int (B_noeud(1, B_noeud(2, ...)));; ______1______ / \ __2__ __9__ / \ / \ 3 6 10 13 / \ / \ / \ / \ 4 5 7 8 11 12 14 15

Exercice 7-12 : reconnaissance de sous-arbres On donne deux arbres binaires a et b. 1. Ecrire une fonction est_sous_arbre qui dit si a est un sous-arbre de b (un sous-arbre est lensemble des descendants dun nud). 2. Ecrire une fonction est_inclus qui dit si a est inclus dans b (cest--dire si a a sobtient en supprimant certaines branches dun certain sous-arbre de b). Exercice 7-13 : arbre dynastique La gure page suivante prsente un extrait de larbre dynastique de la maison de e Bourbon. Ecrire une fonction liste_rois qui, a partir dun tel arbre, donne la liste des personnes ayant rgn. e e Exercice 7-14 : reprsentation dun arbre par une liste parenthse e e e On reprsente un arbre a par une expression parenthse : e ee
1

a (racine (ls-1) (ls-2) ... (ls-n)) o racine est ltiquette de la racine et (ls-i) est la reprsentation u e e de la i-me branche. Par exemple larbre ci-contre est reprsent e e e par : (1 (2 (3) (4)) (5)).
3

2 4

106

Arbres

Henri IV 1553{1610 Louis XIII 1601{1643 Louis XIV 1638{1715 Louis le Grand Dauphin 1661{1711 Louis 1682{1712 Louis XV 1710{1774 Louis 1729{1765 Louis 1751{1761 Louis XVI 1754{1793 Philippe 1683-1746 Philippe 1748{1765 Charles 1686{1714

Philippe 1730{1733 Charles X 1757-1836 Charles-Ferdinand 1778-1820 Henri 1820-1883

Louis XVIII 1755{1824

Louis-Joseph 1781{1789

Louis XVII 1785{1795

Louis-Antoine 1775-1844

arbre dynastique des Bourbons


source : Initiation lhistoire de la France, Pierre Goubert a

7-5 Exercices

107

On demande : 1. Une fonction caml qui calcule lexpression parenthse dun arbre. ee 2. Une fonction caml qui calcule larbre associ a une expression parenthse. e ee Les expressions parenthses seront reprsentes par des listes selon la dclaration : ee e e e
type a terme = Pargauche | Pardroite | Etiquette of a;; type a expression_parenthse == a terme list;; e e

Exercice 7-15 : impression dune formule avec le minimum de parenth`ses e On reprsente les expressions arithmtiques par le type suivant : e e
type formule = | Valeur of string (* valeur *) | Op1 of string * formule (* oprateur unaire, argument *) e | Op2 of string * int * formule * formule ;; (* op. binaire, priorit, arguments *) e

o les champs de type string contiennent la reprsentation en cha^ de caractres u e ne e de llment considr et le champ de type int code la priorit dun oprateur ee ee e e binaire. Ecrire une fonction dimpression pour ce type de formules en imprimant le minimum de parenthses ncessaires pour respecter la priorit des oprateurs e e e e binaires. Largument dun oprateur unaire sera systmatiquement mis entre pae e renthses. e Exercice 7-16 : arbre binaire quilibr en poids e e 1 < 1. On note |A| la taille dun arbre binaire A et on dit quun arbre Soit 2 A est -quilibr en poids si pour tout sous-arbre B de branches G, D, on a : e e |G| |B| et |D| |B|. Montrer quun arbre -quilibr de taille n a une e e hauteur (ln n). Exercice 7-17 : arbre binaire quilibr en hauteur e e Un arbre binaire est dit quilibr en hauteur a k prs si pour tout nud x les e e e branches gauche et droite de x ont m^me hauteur a k prs (k 1). Montrer que e e la hauteur dun tel arbre a n nuds est (ln n). Exercice 7-18 : dnombrement des arbres a n nuds e ` Soient Gn le nombre darbres gnraux ordonns non tiquets de taille n et Bn e e e e e le nombre darbres binaires non tiquets de taille n. e e 1. Quelle relation y a-t-il entre ces quantits ? e 2. A un arbre gnral A on associe lexpression parenthse, u = [u0, . .., u2n1] e e ee o ui est une parenthse ouvrante ou fermante (cf. exercice 7-14). Montrer u e quune suite de 2n parenthses reprsente eectivement un arbre de taille n e e si et seulement si elle contient autant de parenthses ouvrantes que de fere mantes et si toute sous-suite [u0, . . ., ui] avec i < 2n 1 contient strictement plus de parenthses ouvrantes que de fermantes. Une telle suite sera dite e ( admissible ) . ( )

108

Arbres

3. Soit u = [u0, . .., u2n1] une suite de parenthses contenant autant douvrane tes que de fermantes avec u0 = (. On dnit la suite : e T (u) = [u0, u2, u3, .. ., u2n1, u1] (on fait tourner toutes les parenthses sauf la premire). Montrer quune e e et une seule des suites u, T (u), T 2(u), .. ., T 2n2(u) est admissible (faire un dessin reprsentant la dirence entre le nombre douvrantes et de fermantes e e dans [u0, .. ., ui1] en fonction de i et interprter gomtriquement loprae e e e tion T ). 4. Retrouver ainsi lexpression de Bn en fonction de n. Exercice 7-19 : Complexit en moyenne du tri par comparaisons e 1. Soit a un arbre binaire non vide a n nuds. Montrer que la longueur du chemin externe de a est minimale ( n x) si et seulement si tous les niveaux a e de a sauf peut-^tre le dernier sont complets. En dduire que, dans le cas e e gnral, on a Le (a) (n + 1) log2 n . e e 2. On considre un algorithme de tri par comparaisons A oprant sur des listes e e de n entiers avec n 2. Si est une permutation de [[1, n]], on note T le nombre de comparaisons eectues par A pour trier la liste ((1), . .., (n)). e Le nombre moyen de comparaisons eectues par A est : e Tn = 1 n! T

o la somme porte sur toutes les permutations de [[1, n]]. En modlisant A u e par un arbre de dcision, montrer que Tn e log2 (n! 1) .

Chapitre 8 Arbres binaires de recherche

8-1

Recherche dans un arbre binaire

Un arbre binaire non vide tiquet est appel arbre binaire de recherche si e e e les tiquettes appartiennent a un ensemble totalement ordonn et sil vrie lune e e e des deux conditions quivalentes suivantes : e 1. la liste des tiquettes en ordre inxe est croissante au sens large ; e 2. pour tout nud x dtiquette e, les tiquettes des lments de la branche e e ee gauche de x sont infrieures ou gales a e et les tiquettes des lments e e e ee de la branche droite de x sont suprieures ou gales a e. e e Remarques : { La condition 2 implique que ltiquette dun nud est comprise entre celles e des ses ls gauche et droit quand ils existent, mais il ny a pas quivalence. e { Par dnition m^me, tout sous-arbre non vide dun arbre binaire de recherche e e est encore un arbre binaire de recherche. { Pour un ensemble donn dtiquettes il existe plusieurs arbres binaires de e e recherche contenant ces tiquettes, en particulier deux arbres linaires assie e milables a des listes ordonnes et des arbres ( mieux quilibrs ) (cf. gu e e e ) ( re 21).
6 5 4 3 2 1 1 2 3 4 5 6 1 2 3 4 5 6

Figure 21 : arbres binaires de recherche ayant m^mes tiquettes e e

110

Arbres binaires de recherche

On utilise les arbres binaires de recherche pour reprsenter des ensembles e nis ou des tables dassociation. Leur intr^t vient de la proprit 2 : pour ee ee dterminer si une tiquette x donne gure dans un arbre binaire de recherche, il e e e sut de la comparer a ltiquette r de la racine de larbre, puis si x = r de chercher e rcursivement x dans le sous-arbre gauche ou droit selon le sens de la comparaison e entre x et r. On limine ainsi une branche a chaque comparaison, ce qui limine e e environ la moiti des nuds si larbre est quilibr. e e e
(* dtermine si ltiquette x appartient a larbre donn *) e e ` e (* compare est la relation dordre entre etiquettes *) let rec recherche compare x arbre = match arbre with | B_vide -> false | B_noeud(e,g,d) -> match compare x e with | EQUIV -> true (* EQUIV = egal *) | PLUSGRAND -> recherche compare x d | PLUSPETIT -> recherche compare x g ;;

La correction et la terminaison de recherche stablissent par rcurrence sur e e la hauteur de larbre considr. Le temps dexcution est proportionnel au nombre ee e de sous-arbres examins, soit O(h) pour un arbre de hauteur h. Lorsque larbre est e quilibr on a h = O(ln n) et le temps de recherche est logarithmique par rapport e e a la taille de larbre, mais si larbre est liforme alors h = O(n) et la complexit e de recherche est linaire par rapport a la taille de larbre. La complexit spatiale e e est en principe constante car la fonction recherche est rcursive terminale, ceste a-dire quil ny a rien a faire aprs lappel rcursif. e e
4 2 1 a b c 3 d e f 5 6
x=1? x=2? 2 b c x=3? 3 d x=4? 4 e x=5? 5 f x=6? 6 g

g
a 1

Figure 22 : arbre de recherche et arbre de dcision e Un arbre binaire de recherche peut ^tre vu comme un arbre de dcision, e e les nuds correspondant aux comparaisons a eectuer avec trois branches par nud : continuer la recherche a droite, a gauche, ou conclure a la prsence de x. e Les feuilles de cet arbre de dcision sont les nuds de larbre de recherche et les e branches vides reprsentant les intervalles dlimits par les tiquettes de larbre e e e e (cf. gure 22). Remarquer par ailleurs la similitude entre la recherche dans un arbre binaire de recherche et la recherche par dichotomie dans un vecteur tri. e Dans ce dernier cas larbre correspondant est quilibr en hauteur puisque les e e branches issues dun pivot ont m^me taille a une unit prs. e e e A la dirence dun vecteur, un arbre binaire ne permet pas daccder en e e temps constant a un lment par son rang. Toutefois on peut trouver le plus ee grand ou le plus petit lment en O(h) tapes : il sut de ( descendre ) le plus ee e ( )

8-2 Insertion

111

a gauche possible (recherche du minimum) ou le plus a droite possible (recherche du maximum) :


let rec minimum(a) = match a with | B_vide -> failwith "arbre vide" | B_noeud(e,B_vide,_) -> e | B_noeud(_,g,_) -> minimum(g) ;;

8-2

Insertion

Etant donns un arbre binaire de recherche a et une tiquette x, on veut e e construire un nouvel arbre binaire de recherche b contenant les tiquettes des e nuds de a et x. Noter que b nest pas entirement spci dans ce problme e e e e car plusieurs arbres peuvent correspondre au m^me ensemble dtiquettes. La e e mthode la plus simple consiste a dterminer dans quelle branche issue de la e e racine de a on peut insrer x, et a raliser cette insertion rcursivement. e e e
let rec ins`re compare x a = match a with e | B_vide -> B_noeud(x,B_vide,B_vide) | B_noeud(e,g,d) -> match compare x e with | PLUSGRAND -> B_noeud(e,g,ins`re compare x d) e | PLUSPETIT -> B_noeud(e,ins`re compare x g,d) e | EQUIV -> a ;;

La correction de ins`re est immdiate par rcurrence sur la hauteur de a. e e e En pratique, ins`re suit le m^me chemin dans larbre que la fonction recherche e e jusqu trouver une branche vide, et remplace cette branche par un nud dtia e quette x. Le nouvel arbre est alors reconstruit de proche en proche depuis cette branche vers la racine, sans modier les branches non explores. Le retour vers la e racine est eectu par le jeu normal de dpilement des appels imbriqus sans quil e e e soit ncessaire de le coder explicitement. e La complexit temporelle de ins`re est O(h) pour un arbre de hauteur h et e e la complexit spatiale galement pour deux raisons : il faut une pile de rcursion e e e de hauteur O(h) pour atteindre le point dinsertion car la rcursivit nest pas e e terminale, et il y a cration de O(h) nouveaux nuds. e La mthode dinsertion ci-dessus est appele insertion aux feuilles car elle e e place le nouvel lment sur une branche vide de lancien arbre (certains auteurs ee appellent ( feuilles ) les branches vides dun arbre binaire) en modiant ( aussi peu ( ) ( que possible ) la structure de ce dernier. En particulier la racine est conserve sauf e ) dans le cas dun arbre vide. Le modle probabiliste darbre construit alatoirement e e correspond a ce type dinsertion : si est une permutation alatoire des entiers e 1, 2, . .., n et si lon cre un arbre binaire de recherche en insrant successivement e e les tiquettes (1), . .., (n) dans un arbre initialement vide, alors (n) est insr e ee

112

Arbres binaires de recherche

14 4 2 6 8
ins`re 9 e

9 16 4
ins`re racine 9 e

14 6 8 10 12 16

10 12

14 4 2 6 8 9 10 12 16
supprime 10

14 4 2 6 8 9 12 16

Figure 23 : insertion et suppression dans un arbre binaire sur la k-me branche vide en ordre inxe si et seulement (n) = k, ce qui se e produit avec une probabilit 1/n indpendante de k. e e Une autre mthode dinsertion, appele insertion a la racine, consiste a e e placer ltiquette a insrer a la racine du nouvel arbre. Pour cela on dcoupe e e e larbre initial en deux arbres dont les tiquettes sont respectivement infrieures e e a x et suprieures ou gales a x, puis on rassemble ces arbres sous une nouvelle e e racine :
(* dcoupe larbre a en deux arbres spars par ltiquette x *) e e e e let rec dcoupe compare x a = match a with e | B_vide -> (B_vide,B_vide) | B_noeud(e,g,d) -> if (compare x e) = PLUSGRAND then let (b,c) = dcoupe compare x d in (B_noeud(e,g,b),c) e else let (b,c) = dcoupe compare x g in (b,B_noeud(e,c,d)) e ;; (* ins`re ltiquette x dans a a la racine *) e e ` let ins`re_racine compare x a = e let (b,c) = dcoupe compare x a in B_noeud(x,b,c);; e

8-3 Suppression

113

Comme pour linsertion aux feuilles, les complexits temporelle et spatiale e sont O(h).

8-3

Suppression

Soit a un arbre binaire de recherche et x un nud de a que lon veut supprimer. Si x na pas de ls on le remplace par une branche vide, et sil na quun ls, y, on remplace la branche de racine x par celle de racine y. Dans les deux cas on obtient encore un arbre binaire de recherche car aucun nud ne change de position par rapport a ses ascendants. Lorsque x a un ls gauche y et un ls droit z, soient y le prdcesseur et z le successeur de x dans lordre de parcours e e inxe. y est le plus a droite des descendants de y et z est le plus a gauche des descendants de z. On peut alors au choix : retirer y de la descendance de y ou retirer z de la descendance de z et mettre ltiquette du nud retir a la place de e e celle de x. Dans les deux cas la proprit dun arbre de recherche est conserve : ee e toutes les tiquettes a gauche sont infrieures a celle de la racine qui est infrieure e e e a toutes les tiquettes a droite. e
(* supprime llment le plus a droite dun arbre e e ` *) (* renvoie ltiquette supprime et le nouvel arbre *) e e let rec suppmax(a) = match a with | B_vide -> failwith "suppression impossible" | B_noeud(e,g,B_vide) -> (e,g) | B_noeud(e,g,d) -> let (e,d) = suppmax(d) in (e,B_noeud(e,g,d)) ;; (* recherche si ltiquette x figure dans a et la supprime *) e let rec supprime compare x a = match a with | B_vide -> failwith "x nest pas dans a" | B_noeud(e,g,d) -> match compare x e with | PLUSGRAND -> B_noeud(e,g,supprime compare x d) | PLUSPETIT -> B_noeud(e,supprime compare x g,d) | EQUIV -> if g = B_vide then d else if d = B_vide then g else let (e,g) = suppmax(g) in B_noeud(e,g,d) ;;

Compte tenu de ce qui prcde, la correction de supprime est quivalente e e e a celle de suppmax et celle-ci stablit par rcurrence sur la hauteur de larbre e e considr. La complexit temporelle dans le pire des cas de suppmax est proporee e tionnelle a la hauteur de larbre dont on supprime le maximum, et la complexit e temporelle dans le pire des cas de supprime est proportionnelle a la hauteur h de larbre initial. Il y a cration de O(h) nouveaux nuds et rcursion non terminale, e e donc la complexit spatiale est aussi O(h). e Si lon part dun arbre vide et si lon insre des tiquettes distinctes dans e e un ordre alatoire, alors la profondeur moyenne dun nud est O(ln n) et donc e

114

Arbres binaires de recherche

lopration de recherche, insertion ou suppression suivante a une complexit teme e porelle et spatiale moyenne O(ln n). Mais cette proprit nest pas rcurrente : ee e aprs une suite dinsertions et de suppressions alatoires la distribution de probae e bilit des arbres obtenus nest pas celle des arbres ( construits alatoirement ) , e e ( ) et nest pas connue thoriquement. Exprimentalement il semble que les are e bres bien quilibrs sont plus frquents que dans le modle ( arbres construits e e e e ( alatoirement ) et que la profondeur moyenne reste O(ln n) ([Knuth] vol. 3, ch. 6). e )

8-4

Exercices

Exercice 8-1 : contrle dun arbre de recherche o Ecrire une fonction testant si un arbre binaire est bien un arbre de recherche. Exercice 8-2 : complexit de la cration dun arbre de recherche e e Soit Tn le temps maximal de cration dun arbre binaire de recherche a partir dune e liste quelconque de n lments en procdant uniquement a des comparaisons entre ee e ces lments pour dcider des positions dans larbre o les placer. Montrer que ee e u n ln n = O(Tn ). Exercice 8-3 : transformation dun vecteur tri en arbre de recherche e On dispose dun vecteur tri de n lments. Ecrire une fonction caml construisant e ee un arbre binaire de recherche quilibr contenant ces lments. e e ee Exercice 8-4 : comparaison entre linsertion aux feuilles et a la racine ` On constitue un arbre binaire de recherche par insertion de n lments dans un ee arbre initialement vide. Quel rapport y a-t-il entre les arbres obtenus par les deux mthodes dinsertion ? e Exercice 8-5 : fusion de deux arbres de recherche Ecrire une fonction ralisant la fusion de deux arbres binaires de recherche. Anae lyser sa complexit temporelle. e Exercice 8-6 : analyse du tri rapide Soit une permutation des entiers de [[1, n]]. Montrer que le nombre de comparaisons eectues lors du tri rapide de la liste ((1), . . ., (n)) est gal au nombre e e de comparaisons eectues lors de linsertion aux feuilles de (1), .. . , (n) dans e cet ordre dans un arbre binaire de recherche initialement vide. En dduire que le e nombre moyen de comparaisons eectues pour trier rapidement une permutation e alatoire de [[1, n]] est (n ln n). Le code du tri rapide est : e
let rec dcoupe a liste = match liste with e | [] -> [],[] | x::suite -> let (u,v) = dcoupe a suite in e if x < a then (x::u,v) else (u,x::v) ;; let rec quicksort liste = match liste with | [] -> [] | a::suite -> let (u,v) = dcoupe a suite in e (quicksort u) @ (a :: (quicksort v)) ;;

Chapitre 9 Manipulation dexpressions formelles

9-1

Introduction

On sintresse ici a la manipulation dexpressions arithmtiques contenant e e des constantes, des variables, des fonctions et les oprateurs binaires usuels +, -, e *, / et ventuellement ^ (puissance). Un systme de calcul formel est dni par e e e deux caractristiques : e { la reprsentation interne des expressions ; e { les manipulations que lon veut eectuer. La reprsentation interne, gnralement sous forme darbre, nest importante e e e que par son inuence sur la complexit temporelle et spatiale des manipulations e que lon veut eectuer, elle doit donc ^tre choisie une fois que ces manipulations e sont spcies. Parmi les manipulations courantes on peut citer : e e { Lvaluation dune formule quand certaines variables sont connues. Lorsque e toutes les variables sont connues, lvaluation peut produire une constante, e mais aussi formule sans variables. Par exemple lvaluation de la formule une e x + 1 + y 1 avec les conditions x = 1, y = 2 peut produire la constante 2.4142136 ou la formule 1 + 2. { Les transformations lmentaires : dveloppement dun produit, factorisaee e tion, substitution. Le dveloppement est relativement simple a eectuer e mais produit gnralement une formule de grande taille : (1 + x)100 est e e transform en une somme de 101 termes. La factorisation est nettement e plus dlicate : on peut facilement factoriser une somme autour dun facteur e commun prsent dans chaque terme, mais factoriser un polyn^me tel que e o

116

Manipulation dexpressions formelles

x4 + x2 + 1 en (x2 + x + 1)(x2 x + 1) est bien plus dlicat. De m^me que le e e dveloppement, la factorisation peut produire une formule plus grande que e celle dont on est parti, par exemple : x20 1 = (x 1)(x + 1)(x2 + 1)(x4 + x3 + x2 + x + 1)

(x4 x3 + x2 x + 1)(x8 x6 + x4 x2 + 1).

{ La simplication : transformer une formule donne en une formule quivae e lente mais plus simple, par exemple : x1 1 ; 2 x+1 x 1 ln(x +

x2 + 1) + ln(x +

x2 + 1) 0.

Comme la factorisation, la simplication est une opration dicile, et ceci e dautant plus que le rsultat attendu est dni de manire ambigue. On peut e e e dailleurs objecter que (x 1)/(x2 1) et 1/(x + 1) ne sont pas rellement e quivalentes, la deuxime expression est dnie pour x = 1 mais pas la e e e premire. e { La drivation par rapport a une variable : l le calcul est facile a conduire e a en appliquant les rgles de drivation. Le problme essentiel de la drivation e e e e est la simplication du rsultat. Lopration inverse, la primitivation, est e e trs dicile a conduire car on ne dispose pas dalgorithme pour cela (mais e il existe des cas particuliers importants dans lesquels la primitivation peut ^tre automatise, notamment pour les fractions rationnelles et pour les exe e pressions dites ( lmentaires ) constitues uniquement dexponentielles, de e (ee ) logarithmes et de racines dquations polynomiales (algorithme de Risch)). e Lvaluation a dj t tudie lors du parcours dun arbre gnral (cf. sece eaeee e e e tion 7-3). On se limitera dans ce chapitre a la drivation formelle et aux simpli e cations lmentaires : regrouper les termes identiques dans une somme ou dans ee un produit, regrouper les constantes, liminer les oprations inutiles (0 + x x, e e x0 1, .. . ).

9-2

Reprsentation des formules e

On pourrait reprendre la description des formules vue en 7-3, mais pour automatiser les simplications algbriques il est prfrable de dnir de manire e ee e e symbolique les oprateurs binaires : e
type a | Const | Var | Fct | Plus expression = of a of string of string * (a expression) of (a expression) * (a expression)

(* (* (* (*

constante variable fonction somme

*) *) *) *)

9-2 Reprsentation des formules e | Moins | Mult | Div | Puiss ;; of of of of (a (a (a (a expression) expression) expression) expression) * * * * (a (a (a (a expression) expression) expression) expression) (* (* (* (* diffrence e produit quotient puissance *) *) *) *)

117

Une fonction est identie par son nom. On supposera quil existe des fonctions e caml feval et fder renvoyant le code dvaluation et la drive dune fonction de e e e nom donn. e Le type des constantes nest pas spci (a) ce qui permet thoriquement e e e dcrire des algorithmes indpendants de la reprsentation eective des constantes, e e e mais il faudra bien coder les oprations binaires (Plus, Moins, Mult, Div et Puiss) e entre constantes. Une possibilit est de transmettre en argument aux fonctions de e manipulation les oprateurs associs ainsi que les constantes lmentaires 0, 1 et e e ee 1, mais elle alourdirait le code de ces fonctions. On supposera pour simplier que les constantes sont de type float. Il sagit certainement dun mauvais choix car les calculs sur les ( rels machine ) sont approchs et les erreurs darrondi peuvent e ( e ) g^ner la simplication. En pratique, il vaudrait mieux prendre des constantes e de type entier et accepter des expressions constantes comme 3 2, mais cela conduirait a dvelopper une bibliothque de calcul sur les entiers de longueur e e arbitraire et les nombres algbriques sortant largement du cadre de ce cours. e Le problme principal de la reprsentation prcdente est la complication e e e e quelle entra^ pour les simplications lmentaires : (x+y)(y+x) est reprsent ne ee e e par larbre : + +

x y y x et il nest pas immdiat de constater sur larbre que les x et les y sen vont. De e m^me, 2 (x/2) est reprsent par : e e e 2 / x 2 et les 2 qui se simplient sont relativement loin lun de lautre. Ce problme e est d^ au fait que lon ne prend pas en compte dans la reprsentation interne la u e commutativit et lassociativit de + et , ni les caractres ( rciproques ) de + e e e ( e ) et ou et /. Une meilleure solution consiste a dnir deux oprateurs n-aires, e e la combinaison linaire et le produit avec exposants dune liste dexpressions : e

118 type a | Const | Var | Fct | CL | PG ;;

Manipulation dexpressions formelles expression = of a of string of string * (a expression) of (a * a expression) list of (a * a expression) list

(* (* (* (* (*

constante *) variable *) fonction, argument *) comb. linaire e *) produit gnralis *) e e e

CL [(a1 , e1); .. .; (an en)] reprsente lexpression a1 e1 +. ..+an en o les ai sont des e u constantes et les ei des expressions. De m^me, PG [(a1, e1); . ..; (an en)] reprsente e e le produit gnralis ea1 .. . ean . La notation est alourdie, f + g est code e e e 1 e n par CL [(1, f); (1, g)], mais en contrepartie il ny a plus que deux oprateurs au e lieu de cinq. Remarquons quon a ainsi perdu llvation a une puissance non ee constante, mais on peut la retrouver par la forme exponentielle. Lassociativit et e la commutativit de + et ne sont pas directement prises en compte, il faut pour e cela des conventions de reprsentation : e { aucun terme dune combinaison linaire nest lui-m^me une combinaison e e linaire ; e { aucun facteur dun produit gnralis nest lui-m^me un produit gnralis ; e e e e e e e { il est dni une relation dordre total sur les expressions, et les termes dune e combinaison linaire ou dun produit gnralis sont tris suivant cet ordre, e e e e e deux termes successifs tant distincts. e La condition de tri des termes permet de garantir une sorte dunicit de la e reprsentation mmoire dune formule ce qui est indispensable pour tester si deux e e formules sont gales et aussi pour les classer, mais elle ne sut pas. La principale e cause de non unicit est la prsence des constantes, et on ajoute les conventions e e suivantes : { dans une combinaison linaire aucun coecient nest nul et toutes les constane tes sont regroupes en une seule avec coecient 1 si elle est non nulle, en e aucune sinon ; { dans un produit gnralis aucun exposant nest nul et il ny a pas de facteur e e e constant ; { un produit gnralis comporte au moins deux facteurs ou un seul facteur e e e avec un exposant dirent de 1. e En eet, les facteurs constants dans un produit gnralis peuvent ^tre ( sortis ) du e e e e ( ) produit et placs en coecient dune combinaison linaire, donc cette interdiction e e de facteurs constants dans un produit ne porte pas a consquence (mais elle ne e serait pas dfendable si lon voulait grer des constantes symboliques comme 2 1/2 e e sans les convertir en approximation numrique). e Les conventions prcdentes font partie de la reprsentation interne des exe e e pressions, m^me si elles napparaissent pas en tant que telles dans la dclaration e e caml du type expression. Il est donc possible de construire des expressions ( non (

9-2 Reprsentation des formules e

119

normalises ) , mais il faut sengager a les mettre sous forme normale a la n des e ) calculs. Remarquons enn que les simplications du type : x1 1 , 2 x+1 x 1

ln(x + x2 + 1) + ln(x + x2 + 1) 0, ne sont pas prises en compte : la premire relve dalgorithmes de factorisation et e e la deuxime de rgles de simplication fonctionnelles. e e Relation dordre

Une manire simple de comparer deux expressions consiste a les parcourir e simultanment en profondeur dabord jusqu ce que lon trouve une dirence. e a e On dclare la premire expression plus grande ou plus petite que lautre en fonction e e de cette premire dirence si lon en trouve une, gale a lautre si lon nen trouve e e e pas :
let rec compare e e = match (e,e) with | (Const(a),Const(b)) -> else | (Const(_),_) -> | (_,Const(_)) -> | (Var(a),Var(b)) | (Var(_),_) | (_,Var(_)) -> else -> -> if a < b then PLUSPETIT if a > b then PLUSGRAND else EQUIV PLUSPETIT PLUSGRAND if a < b then PLUSPETIT if a > b then PLUSGRAND else EQUIV PLUSPETIT PLUSGRAND if f < g then PLUSPETIT if f > g then PLUSGRAND else compare u v PLUSPETIT PLUSGRAND

| (Fct(f,u),Fct(g,v)) -> else | (Fct(_),_) -> | (_,Fct(_)) -> | (CL(l),CL(l)) | (CL(_),_) | (_,CL(_)) | (PG(l),PG(l))

-> compare_listes l l -> PLUSPETIT -> PLUSGRAND -> compare_listes l l

and compare_listes l l = match (l,l) with | ([],[]) -> EQUIV | ([],_) -> PLUSPETIT | (_,[]) -> PLUSGRAND | ((a,x)::b,(a,x)::b) -> if a < a then PLUSPETIT else if a > a then PLUSGRAND else match compare x x with | EQUIV -> compare_listes b b | c -> c ;;

120

Manipulation dexpressions formelles

< dsigne a la fois loprateur de comparaison entre rels et celui entre cha^ e e e nes de caractres. La fonction compare ci-dessus compare successivement tous les e nuds des expressions e et e dans lordre prxe, et termine ds quune dirence e e e est dtecte, soit dans un constructeur soit dans une tiquette (valeur dune e e e constante ou dun coecient, nom dune variable ou dune fonction). Lordre parmi les constructeurs est dni arbitrairement par : e

Const < Var < Fct < CL < PG. Par rcurrence sur la taille de e, compare e e termine et renvoie un rsultat e e PLUSPETIT, PLUSGRAND ou EQUIV, ce dernier si et seulement si e = e . La relation ainsi dnie est bien une relation dordre total : total puisquun appel a compare e termine ; rexive, transitive et antisymtrique par rcurrence sur la plus grande e e e taille des formules a comparer. Il sagit en fait dun cas particulier de relation dordre sur un produit cartsien appele ordre lexicographique parce que cest e e lordre utilis pour classer les mots dans un dictionnaire. Dans le langage caml e la relation < est en fait une relation polymorphe classant deux objets de m^me e type quel que soit ce type pourvu quil ne contienne pas de valeurs fonctionnelles. Elle est grosso modo implmente comme la fonction compare ci-dessus, mais les e e comparaisons ( lmentaires ) portent sur les reprsentations binaires des objets e (ee ) a comparer ce qui lui confre son caractre polymorphe. En pratique on pourra e e donc utiliser < a la place de compare, le rsultat dune comparaison tant alors un e e boolen. e On peut donc comparer deux expressions. Le temps de comparaison dans le pire des cas est proportionnel a la plus petite des tailles des expressions compares, e mais si lon compare deux expressions alatoires alors on peut considrer que le e e temps moyen de comparaison est constant (cf. exercice 6-3).

9-3

Drivation e

Soit e une expression et x une variable (une cha^ de caractres). Lobjectif ne e est de calculer une expression e quivalente a e/x. Notons quil ny a pas unicit e e du rsultat, m^me si lon impose a e de respecter les conventions de reprsentation e e e des expressions normales. Par exemple lexpression : e = x cos(x) sin(x) admet pour drives par rapport a x les deux expressions suivantes (entre autres) : e e e1 = cos(x) sin(x) + x cos(x)2 x sin(x)2 , e2 = cos(x) sin(x) + x(cos(x)2 sin(x)2 ). Par ailleurs, bien quil soit souhaitable de retourner une expression sous forme normale, on se limitera dans un premier temps au calcul dune expression de e/x non simplie, quitte a la simplier aprs coup (voir cependant lexercice 9-7 a ce e e sujet).

9-3 Drivation e

121

Le calcul de e seectue rcursivement en appliquant les rgles usuelles de e e drivation : e


c = 0 pour toute constante c ; x x x = 1 ; y = 0 si y est une variable dirente de x ; e x f(u) = f (u) u pour une fonction f et une expression u ; x x (a e + . . .+a e ) = a e1 + . . . +a en pour des expressions e , . . ., e n n 1 n 1 n x 1 1 x x et des constantes a1 , . .., an ; (ea1 . ..ean ) = a e1 ea11 ea2 . ..ean +. ..+a en ea1 .. .ean1 ean1 pour 1 n n n 2 n1 n x 1 x 1 x 1 des expressions e1, . . ., en et des constantes a1 , .. ., an.
let rec drive e | Const(_) -> | Var(v) -> | Fct(f,u) -> | CL(liste) -> | PG(liste) -> x e = match e with Const(0.0) if v = x then Const(1.0) else Const(0.0) PG [(1.0,drive x u); (1.0,fder f u)] e CL(map (driveCL x) liste) e CL(map (drivePG liste x) liste) e

and driveCL x (a,e) = (a,drive x e) e e and drivePG liste x (a,e) = e (a, PG( (1.0,drive x e) :: (-1.0,e) :: liste )) e ;; map applique la fonction passe en premier argument a la liste passe en deuxime e e e argument. La fonction drivePG accole a liste (reprsentant ea1 . . . ean ) e e n 1

les facteurs ei/x et e1 et place le coecient ai , en accord avec la formule i de drivation logarithmique dun produit. Lexpression nest certainement pas e e simplie puisque eai gure dans liste, la fonction de simplication dcrite a la e i section 9-4 rectiera ceci. La drivation des fonctions dune variable fait appel a une fonction fder e charge de constituer la drive dune fonction spcie par son nom et applique e e e e e e a une expression u. Le code de fder est de la forme :
let fder f | "exp" -> | "ln" -> | "cos" -> | "sin" -> ...... | _ -> ;; u = match f with Fct("exp",u) (* PG [(-1.0,u)] (* CL [(-1.0,Fct("sin",u))] (* Fct("cos",u) (* (* autres Fct(f^"",u) (*

exp(u) = exp(u) ln(u) = u^-1 cos(u) = -sin(u) sin(u) = cos(u) drives usuelles e e f(u) = f(u)

*) *) *) *) *) *)

122

Manipulation dexpressions formelles

La dernire ligne constitue la drive dune fonction inconnue en accolant une e e e prime a son nom. On peut ainsi driver des fonctions formelles. e Correction et complexit e La correction de drive stablit par rcurrence sur la taille ou la hauteur e e e dune expression. Il sut de constater que lon a eectivement cod les rgles e e de drivation des fonctions usuelles et des oprations (combinaison linaire et e e e produit). La complexit est plus dlicate a valuer : drive x e sexcute en e e e e e temps constant lorsque e est une constante ou une variable. En admettant que map a une complexit linaire, le temps de drivation dune combinaison linaire, e e e e non compte tenu des appels rcursifs, est proportionnel au nombre de termes. La e drivation de f(u) produit larbre : e u f u donc il faut compter le temps de construction du sous-arbre : f u qui est a priori au moins gal a la taille de u. Lorsque f est complique, u e e peut appara^ tre plusieurs fois. Par exemple si lon dispose dans la batterie des fonctions usuelles de la fonction scante (sec x = 1/ cos x) alors la drivation de e e sec (u) produit larbre : u sec u tan u

car sec (x) = sec(x) tan(x) (ou sin(x)/ cos 2(x)). En fait, dans limplmentation de e caml, les sous-arbres ne sont pas recopis et toutes les donnes complexes sont e e rfrences par des pointeurs, donc larbre prcdent est en ralit un graphe : ee e e e e e u sec u tan

9-3 Drivation e

123

let e = expression "x^2 + cos(2*x+t)";; e : float expression = _____CL_____ / \ _*_ ___*____ / \ / \ 1.0 PG 1.0 cos | | ^ _CL__ / \ / \ x 2.0 * * / \ / \ 2.0 x 1.0 t #let e = drive "x" e;; e e : float expression = ____________________CL_____________________ / \ ____*_____ _____________*__________... / \ / 1.0 CL 1.0 ______... | / ______*______ ____^_____ / \ / \ 2.0 ______PG_______ __CL___ 1.0 / | \ / \ ^_ ^_ ^ *_ *_ / \ / \ / \ / \ / \ 1.0 1.0 x -1.0 x 2.0 2.0 1.0 1.0 0.0

#simplifie(e);; - : float expression = ___CL____ / \ * ___*____ / \ / \ 2.0 x -2.0 sin | _CL__ / \ * * / \ / \ 1.0 t 2.0 x

Figure 24 : drivation et simplication e

124

Manipulation dexpressions formelles

Pour cette implmentation, la drivation de f(u) prend un temps constant e e une fois que lon conna^ u , avec des fonctions usuelles raisonnables et en nomt bre dtermin a lavance, la drivation dune fonction formelle prenant un temps e e e proportionnel a la longueur du nom de cette fonction (car il y a recopie du nom pour accoler une prime). De m^me, la drivation dun produit gnralis produit e e e e e un arbre dans lequel le produit complet est partag entre les dirents termes de e e la drive : e e CL a1 e1 e1 1 a2 e2 e1 2 a3 e3 e1 3

e a1 e a2 e a3 1 2 3 Le temps de construction de cet ( arbre ) est proportionnel au nombre de ( ) facteurs. La complexit temporelle de la drivation dune expression e est donc e e proportionnelle au nombre de nuds de e sil ny a pas de fonction formelle. Sous la m^me hypothse, la complexit spatiale est galement linaire par rapport au e e e e e nombre de nuds puisquil nest cr quun nombre born de nouveaux nuds a ee e chaque tape ou aussi parce que la complexit spatiale sur une machine squentielle e e e est majore par la complexit temporelle. Notons que la taille mmoire de e peut e e e ^tre bien plus faible que son nombre de nuds sil y a dj partage de sous-arbres e ea dans e, dans ce cas on calcule plusieurs fois la drive dune m^me sous-expression. e e e

9-4

Simplication

Lexemple gure 24 illustre le caractre catastrophique de la drivation fore e melle sans simplication. Etant donne une expression e obtenue par drivation, e e substitution, valuation partielle ou toute autre manipulation formelle, il est e ncessaire de transformer e en une expression e quivalente a e et normalise e e e selon les conventions de la section 9-2. On considre ici que deux formules e sont quivalentes si lon peut passer de lune a lautre par application des rgles e e usuelles de commutativit, associativit, distributivit de sur + et de ^ sur , et e e e valuation dexpressions constantes. Le schma gnral de simplication est : e e e e parcourir e en profondeur dabord ; pour chaque nud n simplier rcursivement les branches de n puis simplier n lui-m^me. e e Lordre de simplication est donc postxe. On peut aussi procder a une e simplication prxe, par exemple transformer un produit contenant zro en zro e e e

9-4 Simplification

125

sans avoir besoin de simplier les autres facteurs, mais il nest pas garanti que cela suse, il se peut quun facteur savre nul aprs simplication seulement. La e e validit de la simplication postxe est justie ci-aprs. e e e Algorithme de simplication { Une constante et une variable sont dj simplies. ea e { Soit e = f(u) o f est une fonction et u une expression : simplier u u en u puis, si u est une constante et f est valuable, remplacer e par la e constante f[u ] sinon par lexpression f(u ). { Soit e = a1 e1 + ... + an en o les ai sont des coecients et les ei des u expressions : simplier chaque ei en ei. Si ei est une combinaison linaire, distribuer le coecient ai . On obtient ainsi une combinaison e linaire b1 f1 + ... + bp fp o les bj sont des coecients et les fj des e u expressions simplies et ne sont pas des combinaisons linaires. Trier e e la liste et regrouper les termes correspondant a la m^me sous-expression, e supprimer les termes ayant un coecient nul, regrouper les constantes en une seule avec coecient 1 si elle est non nulle, aucune sinon. Si la liste obtenue est vide, remplacer e par zro ; sil ne reste plus quun e terme, f, avec un coecient 1, remplacer e par f sinon remplacer e par la combinaison linaire obtenue. e u { Soit e = ea1 ... ean o les ai sont des exposants et les ei des expresn 1 sions : simplier chaque ei en ei . Si ei est un produit gnralis, dise e e tribuer lexposant ai . Si ei est une combinaison linaire a un seul terme, e ei = af, la transformer en produit af puis distribuer lexposant ai (il est possible ici que f soit aussi un produit, distribuer lexposant sur chaque facteur dans ce cas). Trier la liste des facteurs obtenue en regroupant les facteurs gaux et en supprimant les facteurs ayant un exposant nul. e Regrouper toutes les constantes en une seule, c, et soit f la liste des facteurs restants. Si f est vide, remplacer e par la constante c ; si c = 0 remplacer e par zro ; si c = 1 et f ne contient quun terme g avec e un exposant aussi gal a 1, remplacer e par g ; si c = 1 et f contient e plusieurs facteurs ou un facteur avec un exposant dirent de 1, reme placer e par PG(f) ; si c = 1 et f ne contient quun terme, g, qui est une combinaison linaire avec un exposant 1, distribuer c et remplacer e par e la combinaison linaire obtenue ; dans tous les autres cas remplacer e e par la combinaison linaire cPG(f). e Il sagit presque dun algorithme, il sut de prciser certains dtails comme la e e manire de reconna^ si les expressions intermdiaires sont de la forme attendue, e tre e la manire deectuer les oprations entre constantes, la manire de distribuer un e e e coecient ou un exposant et la relation de comparaison utilise pour les tris. Le e codage de cet ( algorithme ) en caml est fastidieux mais ne pose pas de problme e ( ) particulier, il fait lobjet de lexercice 9-6.

126

Manipulation dexpressions formelles

Terminaison Montrons par rcurrence sur la hauteur h de e que la simplication de e e termine : pour h = 0, e est une feuille, donc une constante ou une variable et la terminaison est vidente. Si la simplication termine pour toute expression de e hauteur h1 et si e est de hauteur h alors e est de la forme f(u) ou a1e1 +. . .+an en ou ea1 . ..ean : la branche u ou les branches ei sont simplies par hypothse en e e n 1 un temps ni, et il reste a vrier quon eectue un nombre ni doprations aprs e e e simplication des branches. Cest immdiat si e = f(u). e Si e = a1 e1 + . .. +an en il faut vrier quon nappliquera pas une innit de e e fois la rgle de distributivit : on constate ici que lalgorithme est incompltement e e e spci puisquil nest pas dit si lon doit distribuer rcursivement le coecient e e e ai dans le cas o ei contient des combinaisons linaires imbriques. On peut reu e e marquer que ceci ne peut pas se produire si lalgorithme est correct puisque ei est suppose simplie, mais la correction de lalgorithme nest pas prouve . . . e e e Cette situation peut se rgler de plusieurs manires : dmontrer dabord la correce e e tion ou la dmontrer ensuite mais en vriant quon nutilise pas lhypothse de e e e terminaison, dmontrer en m^me temps la correction et la terminaison puisquici e e on a besoin de lhypothse de correction au rang h 1 et non h, revoir la dese cription de lalgorithme en prcisant quon ne distribue pas rcursivement (cette e e prcision ne changeant rien si lalgorithme est correct) ou remarquer que, m^me si e e lon distribue rcursivement, il y a un nombre ni de ei chacun ayant un nombre e ni de descendants, donc on ne pourra pas appliquer une innit de fois cette e rgle de distributivit. Une fois la distribution des coecients eectue, le tri e e e des termes, leur regroupement et llimination des constantes prennent un temps e manifestement ni donc la simplication dune combinaison linaire de hauteur h e termine. Si e est un produit gnralis de hauteur h, on constate comme dans le cas e e e prcdent quon obtient en un temps ni une liste de facteurs isols, la transformae e e tion des combinaisons linaires a un seul terme en produit ne pouvant ^tre eectue e e e une innit de fois m^me si elle est applique rcursivement. Llimination des e e e e e facteurs constants et les simplications nales ont aussi un temps dexcution ni e donc par rcurrence, lalgorithme de simplication termine ! e Correction Dj, on montre par une rcurrence immdiate que lexpression e dduite ea e e e de e par simplication est quivalente a e sous lhypothse que les calculs sur e e les constantes sont exacts. Avec des constantes de type float il ny a aucune garantie dquivalence et e est seulement une approximation de e ce qui ne veut e rien dire dans labsolu. En supposant les calculs exacts, il reste a prouver que e satisfait aux conventions de normalisation dnies en 9-2, ce qui se fait encore e par rcurrence sur la hauteur h de e : e { Aucun terme dune combinaison linaire nest lui-m^me une combinaie e son linaire : si e est une combinaison linaire, les termes simplis ei e e e ne contiennent pas de combinaisons linaires imbriques par hypothse de e e e

9-4 Simplification

127

rcurrence et si ei est une combinaison linaire elle est clate par distribue e e e tivit donc e ne contient pas de combinaison linaire imbrique. Si e est e e e un produit gnralis, les facteurs ei ne contiennent pas de combinaisons e e e linaires imbriques et e est soit un produit de certains de ces termes (ou de e e leurs descendants), soit une combinaison linaire de produit avec plusieurs e facteurs ou un seul si son exposant est dirent de 1, soit lun des ei ou un e descendant. En aucun cas, e ne contient de combinaison linaire imbrique. e e Lorsque e est une constante, une variable, ou de la forme f(u) il ny a pas cration de nouvelle combinaison linaire donc l encore e ne contient pas e e a de combinaison linaire imbrique. e e { Aucun facteur dun produit gnralis nest lui-m^me un produit gne e e e e e ralis : par un raisonnement analogue. e { Les sous-expressions dune combinaison linaire ou dun produit gne e e ralis sont tries, deux expressions successives tant distinctes ; e e e { dans une combinaison linaire, aucun coecient nest nul et toutes les e constantes sont regroupes en une seule (avec coecient 1) si elle est e non nulle, en aucune sinon ; { dans un produit gnralis, aucun exposant nest nul et il ny a pas de e e e facteur constant ; { un produit gnralis comporte au moins deux facteurs ou un seul face e e teur avec un exposant dirent de 1 : e par construction. Complexit e Soit e une expression de taille n que lon simplie en e . Chacune des rgles de e simplication rduit le nombre de nuds de lexpression manipule, sauf peut-^tre e e e la rgle stipulant de remplacer un produit ayant un coecient multiplicatif c = 1 e par une combinaison linaire a un terme de coecient c. Mais il est impossible e dobtenir un coecient c = 1 sil ny a pas de facteur constant dans le produit aprs simplication des facteurs et clatement des produits imbriqus. On cre e e e e un nud supplmentaire (la combinaison linaire) en ayant supprim au moins un e e e facteur (constant) donc cette dernire rgle naugmente pas le nombre de nuds e e de lexpression a simplier. Ainsi, il est garanti que e a moins de nuds que e et que, au moins en ce sens, e est plus simple que e. Soit T (e) le temps de simplication de e. On a les relations de rcurrence : e T (e) T (f(u)) T (a1 e1 + . .. + ap ep )
a T (ea1 . ..epp ) 1

lorsque e est une constante ou une variable,

+ T (u), T (e1 ) + . .. + T (ep ) + n ln n, T (e1 ) + . .. + T (ep ) + n ln n,

en supposant que le temps dvaluation dune fonction f est constant et que le e temps du tri dune liste de longueur infrieure ou gale a n est O(n ln n). Cette e e

128

Manipulation dexpressions formelles

deuxime hypothse ne va pas de soi car il faut tenir compte du temps de compae e raison de deux expressions de tailles arbitraires, ce temps est considr ici comme ee constant en moyenne. Si Tn dsigne le temps de simplication dune expression e de taille n dans le pire des cas, on a donc : T1 Tn , max( + Tn1, Tn1 + .. . + Tnp + n ln n, p pour n 2. 1, ni 1, n1 + . .. + np = n 1), 2.

Soit (Xn) la suite dnie par X1 = et Xn = Xn1 + + n ln n pour n e n On a Xn = n + k=2 k ln k, et si n1 + .. . + np = n 1 alors : Xn1 + .. . + Xnp + n ln n
n1 np

= (n1 + .. . + np ) +
k=2

k ln k + . .. +
k=2 np1 termes

k ln k +n ln n

Xn . Ceci permet de prouver par rcurrence que Tn Xn et lon a Xn = (n2 ln n) par e comparaison srie-intgrale, donc Tn = O(n2 ln n). Cette borne est atteinte par e e exemple lorsque e reprsente une addition en cha^ (cf. gure 25). e ne

+ e1 e2 e3 e4 e5 + + + + e6

Figure 25 : cas extr^me de simplication e Le temps de simplication dune expression a n nuds dans le pire des cas est donc (n2 ln n), si les comparaisons entre sous-expressions lors des tris prennent un temps moyen constant.

9-5 Exercices

129

9-5

Exercices

Exercice 9-1 : compatibilit de la relation de comparaison avec les transe formations dexpressions Soient e, e et f trois expressions et x une variable. On note subst(x = f, e) lexpression obtenue en remplaant chaque occurrence de la variable x dans e par c lexpression f. On suppose e < e o < dsigne la relation dordre entre expressions u e dnie dans le cours. A-t-on, avant simplication, e + f < e + f ? ef < e f ? e subst(x = f, e) < subst(x = f, e ) ? Et aprs simplication ? e Exercice 9-2 : substitution de sous-expressions Soient e et f deux expressions. On dit que f gure dans e si f est une sousexpression de e ou si f est une combinaison linaire ou un produit gnralis e e e e inclus dans une combinaison linaire ou un produit gnralis de e. Par exemple e e e e f = x + z gure dans sin(x + y + z) mais pas dans sin(2x + y + z). 1. Ecrire une fonction figure qui dit si f gure dans e. e et f seront supposes e sous forme normale. 2. Ecrire une fonction substitue qui remplace dans e chaque occurrence de f par une autre expression g. Il nest pas demand de simplier le rsultat. e e Exercice 9-3 : complexit de la drivation e e Montrer que les complexits temporelle et spatiale de drive sont O(n2) pour une e e expression de taille n sil y a recopie des sous-arbres lors de la drivation de f(u) e a ou de ea1 . ..epp . 1 Exercice 9-4 : drivation optimise e e Si une expression e comporte des sous-arbres partags, peut-on viter de calculer e e plusieurs fois la drive dun sous-arbre ? e e Exercice 9-5 : taille dun arbre avec partage Si lon admet le partage des sous-arbres et si lon considre quun nud a p ls e occupe p + 1 mots mmoire, quel est le plus gros arbre que lon peut stocker dans e n mots mmoire ? e Exercice 9-6 : simplication Transcrire en caml lalgorithme de simplication du cours. Exercice 9-7 : drivation et simplication e Quelle est la meilleure stratgie : driver puis simplier, driver et simplier en e e e m^me temps ? e

Chapitre 10 Langages rguliers e

La notion de langage est lie au problme de codage des informations : la e e langue franaise permet de coder des ides par des phrases ou des textes (suites de c e mots). Les mots eux-m^mes sont cods par des suites de lettres ou des suites de e e phonmes pour la langue parle. Un langage de programmation permet de coder e e un algorithme par une suite de dclarations, ces dclarations tant elles-m^mes e e e e codes par des suites de caractres alphanumriques. Lidentit gntique dun e e e e e e individu est code par une suite de molcules constituant une cha^ dADN. Une e e ne image lme par une camra est code par une suite de nombres reprsentant la e e e e luminosit et la couleur de chaque point du capteur de la camra. e e De manire informelle, un langage dnit quels sont les symboles de base e e (lettres), quelles suites de lettres constituent des mots valides (lexmes) et quelles e suites de lexmes constituent des phrases valides. Il sagit ici dune description e grammaticale : quelles sont les phrases bien formes, ou comment former une e phrase correcte. A un niveau suprieur, on peut aussi dnir une interprtation e e e pour chaque phrase correcte, cest le dcodage de linformation transporte par la e e phrase. Considrons par exemple les phrases : e 1. 2. 3. 4. Il fait beau kzw30 xxx tfgrd la maison mange le chat
x=3

Vues comme suites de caractres, chacune de ces phrases est bien forme ; e e vues comme suites de mots franais, les phrases 1 et 3 sont bien formes, la phrase c e 2 ne lest pas car elle contient au moins un mot non franais. Dun point de vue c grammatical, les phrases 1 et 3 sont aussi bien formes : sujet, verbe, complment e e dobjet ; mais dun point de vue smantique la phrase 3 na pas dinterprtation e e valide. La phrase 4 est bien forme selon les rgles du langage caml, et admet une e e interprtation valide (expression boolenne disant si x vaut 3), elle est aussi bien e e forme pour le langage c et admet une interprtation dirente (placer la valeur e e e 3 dans la variable x). Les problmes lis aux langages sont : e e

9-5 Exercices

131

{ Dnir un langage du point de vue lexical (lettres autorises, rgles dasseme e e blage des lettres en lexmes), syntaxique (rgles dassemblage des lexmes e e e en phrases) et smantique (interprtation dune phrase valide). Lorsque le e e langage nautorise quun nombre ni de suites, il sut de les lister toutes et de donner leur interprtation, cest ce que fait un dictionnaire pour la e description lexicale du franais. Par contre lorsque le langage est inni, il c sagit de donner une description nie et non ambigue de toutes les suites autorises, et de leur interprtation. e e { Dcomposer une suite de lettres en lexmes (analyse lexicale), reconna^ e e tre si une suite de lexmes est valide (analyse syntaxique) et dterminer son e e interprtation (analyse smantique). e e { Traduire une phrase valide pour un langage en une phrase valide pour un autre langage en respectant au mieux le sens de la phrase. La division de la description dun langage en une description lexicale et une description syntaxique permet de simplier la description globale du langage. Par exemple pour le franais il est plus simple de donner la liste des mots, chaque mot c tant quali par un attribut (nom, adjectif, verbe transitif,. .. ) et les rgles de e e e formation des phrases : sujet, verbe, complment dobjet, "." e verbe, sujet, complment dobjet, "?" e verbe, complment dobjet, "!" e ... plut^t que de donner toutes les phrases possibles (qui sont en nombre inni dans o le cas du franais compte tenu des propositions subordonnes). c e En ce qui concerne les langages informatiques, lanalyse lexicale et syntaxique dun texte est eectue par un compilateur ou un interprteur. Le come e pilateur reconna^ un programme source valide et le traduit en un programme t excutable (liste dinstructions machine). Linterprteur reconna^ une phrase e e t valide, la traduit en instructions machine et excute ces instructions avant de e passer a la phrase suivante. Il ny a pas danalyse smantique, aucun logiciel e (connu de lauteur a ce jour) nest en mesure de dire que le programme :
let rec myst`re(a,b) = if b = 0 then a else myst`re(b,a mod b);; e e

calcule le plus grand diviseur commun aux entiers strictement positifs a et b, ni m^me que ce programme est quivalent en termes de rsultat produit a : e e e
let rec enigme(a,b) = if b = 0 then a else enigme(b,abs(a-b));;

Lun des objectifs de la thorie des langages est de faciliter la ralisation de e e description sous une forme adquate dun langage de programmation et produisant e en sortie un compilateur pour ce langage. Dans ce cours, on se limitera a ltude e a e ( compilateurs de compilateurs ) , cest--dire de programmes prenant en entre la ( )

132

Langages rguliers e

des langages admettant une description simple et a la ralisation danalyseurs e lexicaux pour ces langages.

10-1

Dnitions e

Un alphabet est un ensemble ni non vide dont les lments sont appels ee e lettres. Un mot sur lalphabet A est une suite nie, ventuellement vide, de e lettres. On crit u = a1a2 .. .an pour dsigner la suite (a1 , .. ., an). Le mot vide e e est not . La longueur dun mot u est note |u|. Si u est un mot sur A et x e e une lettre de A, on note |u|x le nombre doccurrences de x dans u. Lensemble de tous les mots sur A est not A . Un langage sur A est un ensemble de mots, e cest--dire un sous-ensemble de A . Il peut ^tre ni ou inni. a e Exemples : { A = {0, 1} (chires binaires). A est lensemble de toutes les suites nies constitues de 0 et de 1. Lensemble L des suites de 0 et de 1 commenant par e c un 1 constitue un langage sur A. L peut ^tre interprt comme lensemble e ee des reprsentations en base 2 des entiers naturels non nuls, ceci constitue e une interprtation de L. On peut aussi interprter un mot de L comme la e e reprsentation binaire dun entier impair en lisant les chires de droite a e gauche, ou comme une suite de tirages a pile ou face commenant par pile. c { A = {a, b, c, .. ., z}, L = {mots franais non accentus et sans trait dunion}. c e Ici L est un langage ni. { A = {0, 1, .. ., 9, +, , , /, (, )}, L est lensemble des expressions arithmtiques e correctement parenthses (ceci constitue une description ambigue quil fauee drait prciser). Un mot de L peut en gnral ^tre interprt de plusieurs e e e e ee manires : 3 + 4 5 peut ^tre interprt comme 3 + (4 5) ou (3 + 4) 5, il faut e e ee xer des rgles de priorit pour dcider quelle est la ( bonne ) interprtation. e e e e ( ) Oprations sur les mots e Deux mots u = a1 .. .an et v = b1 . . .bp sur un m^me alphabet A peuvent e ^tre juxtaposs pour former le mot uv = a1 . . .an b1 . ..bp appel concatnation e e e e de u et v. En identiant les lettres de A et les mots a une lettre, lcriture a1 . . .an e peut ^tre interprte comme le mot constitu des lettres indiques ou comme le e ee e e produit de concatnation des mots a une lettre indiqus. Ces deux interprtations e e e dnissent clairement le m^me mot. On a les proprits : e e ee |uv| = |u| + |v| ;

est lment neutre a droite et a gauche pour la concatnation ; ee e la concatnation est associative mais non commutative, sauf si A ne contient e quune lettre ; (uv = uw = v = w) et (vu = wu = v = w).

10-2 Oprations sur les langages e

133

Pour u A et n N , on note u0 = et un = u u . . . u.
n facteurs

Si u et v sont des mots sur A, on dit que u est un facteur de v sil existe deux mots v , v , ventuellement vides, tels que v = v uv . Lorsque v = on dit e que u est un prxe de v, et lorsque v = on dit que u est un suxe de v. e Si u = a1 . ..an o les ai sont des lettres, limage miroir de u est u = an .. .a1 . u ~

10-2

Oprations sur les langages e

Soient L, L deux langages sur un alphabet A. On dnit les langages suivants : e L + L : union ensembliste de L et L . L L : intersection de L et L . LL = {uv tq u L et v L } : LL est lensemble de tous les produits de concatnation dun mot de L avec un mot de L . LL est vide si et seulement e si lun des langages L ou L est vide. L = {} + L + LL + LLL + . .. = nN Ln . L est lensemble des produits dun nombre ni de mots de L. Il est toujours non vide, m^me si L est vide e ( = {}). La notation A pour lensemble de tous les mots sur A est compatible avec cette notation si lon considre A comme un ensemble de e mots a une lettre. L+ =
n 1L n

L = {u A tq u L}. /

. L+ = L si et seulement si L contient le mot vide.

~ L = {~ tq u L}. u Les proprits suivantes sont immdiates : ee e L+ = LL = L L ; L = L+ + {} ; (L ) = L ; L(M + N) = LM + LN ; (M + N)L = ML + NL ; (L + M) = (L M) L = L (ML ) (rgle de Lazard). e Lintersection et le complmentaire nont par contre pas de ( bonne ) proe ( ) prit vis--vis de la concatnation : L = L ( appartient au premier et pas ee a e au second) et L(M N) = (LM) (LN) (par exemple L = A , M et N les sousensembles des mots de longueur paire, de longueur impaire).

134

Langages rguliers e

Expressions rguli`res e e Une expression rgulire sur lalphabet A est une formule de longueur nie e e correctement parenthse utilisant uniquement les oprations somme, concatnaee e e tion et toile, le langage vide et les langages rduits a un mot : {u} o u est un e e u mot quelconque sur A. Pour allger les notations, on crira u pour le langage {u}. e e Un langage L est dit rgulier sil peut ^tre dcrit par une expression rgulire. e e e e e Un langage rgulier est aussi dit rationnel pour des raisons lies a la thorie des e e e sries formelles. e Exemples : { Sur un alphabet A, le langage L constitu des mots de longueur paire : e L = {u tq |u| 2N} est rgulier car il est dcrit par lexpression L = (AA) e e (ici A est une abrviation pour la somme de toutes les lettres, ce qui constitue e une expression rgulire puisque A est ni). e e { Sur lalphabet A = {0, 1} le langage L des mots commenant par 1 est dcrit c e par lexpression rgulire L = 1(0 + 1) , il est donc rgulier. Sur le m^me e e e e alphabet, le langage L constitu des mots contenant exactement trois fois la e lettre 1 est dcrit par lexpression rgulire L = 0 1010 10. e e e { Sur lalphabet A = {a, . .., z} le langage des mots contenant comme facteur lun des mots : facteur ou factrice est dni par lexpression rgulire : e e e L = A fact(eur + rice)A. Les expressions rgulires : e e (A facteurA) + (A factriceA) A (facteur)(facteur + factrice)(factrice)A dnissent le m^me langage, ce qui montre quil ny a pas unicit dune e e e expression rgulire dnissant un langage rgulier donn. e e e e e { Le langage des parenthses embo^ ees est dni par L = {an bn tq n N} e t e o A = {a, b}, a dsignant une parenthse ouvrante et b une parenthse u e e e fermante. Ce langage nest pas rgulier, voir une dmonstration a la sece e tion 11-6 et une autre dmonstration dans lexercice 10-8. e Par dnition m^me, la somme, le produit de deux langages rguliers et e e e ltoile dun langage rgulier sont encore rguliers, mais il nest pas vident que e e e e lintersection de deux langages rguliers ou le complmentaire dun langage rgulier e e e le soient. On verra au chapitre suivant que cest cependant le cas. Par ailleurs, tout langage ni est rgulier puisquil est la somme des mots quil contient. Enn, si L e ~ est un langage rgulier, alors L lest aussi : on obtient une expression rgulire pour e e e ~ L en permutant rcursivement les oprandes des concatnations et en remplaant e e e c les mots par leurs images miroir dans une expression rgulire pour L e e

10-3 Appartenance dun mot a un langage rgulier e

135

10-3

Appartenance dun mot ` un langage rgulier a e

Soit L un langage rgulier sur un alphabet A et u A . On veut dterminer e e par programme si u L. On suppose que L est dni par une expression rgulire e e e reprsente par un arbre dont les nuds internes sont tiquets par les oprateurs e e e e e somme, concatnation et toile, et dont les feuilles sont tiquetes par le langage e e e e vide ou par un mot sur A, un mot tant reprsent par un vecteur de lettres. e e e
type a exp | Vide | Mot of | Somme of | Concat of | Etoile of ;; = (* a est le (* (a vect) (* (a exp) * (a (a exp) * (a (a exp) type des lettres *) langage *) langage a un mot *) ` exp) exp)

(* dit si le mot u appartient au langage rgulier dfini par exp *) e e let rec appartient(exp,u) = match exp with | Vide -> false | Mot(m) -> u = m | Somme(e1,e2) -> appartient(e1,u) or appartient(e2,u) | Concat(e1,e2) -> dcoupe(e1,e2,u,0) e | Etoile(e) -> u = [||] or dcoupe(e,exp,u,1) e (* dit si lon peut dcouper le mot u apr`s la position i de e e *) (* sorte que la partie gauche est dans e1 et la droite dans e2 *) and dcoupe(e1,e2,u,i) = e if i > vect_length(u) then false else let v = sub_vect u 0 i and w = sub_vect u i (vect_length(u) - i) in (appartient(e1,v) & appartient(e2,w)) or dcoupe(e1,e2,u,i+1) e ;; dcoupe essaie rcursivement tous les dcoupages possibles de u en deux face e e teurs jusqu trouver un dcoupage lment de E1 E2 o Ei est le langage dni a e ee u e par ei. Remarquer que lexpression boolenne : e (appartient(e1,v) & appartient(e2,w)) or dcoupe(e1,e2,u,i+1) e

est un raccourci pour :


if appartient(e1,v) then if appartient(e2,w) then true else dcoupe(e1,e2,u,i+1) e else dcoupe(e1,e2,u,i+1) e

cest--dire que appartient(e2,w) nest pas valu si appartient(e1,v) retourne a e e false, et dcoupe(e1,e2,u,i+1) nest valu que si lun des deux appels a appare e e tient a retourn false. On remarque que chaque appel rcursif a appartient e e porte sur une expression plus petite (en nombre de nuds) et un mot plus petit,

136

Langages rguliers e

lune des deux ingalits tant toujours stricte car on traite a part lappartenance e e e du mot vide a une expression E . Donc appartient termine et on dmontre par e rcurrence sur max(|exp|, |u|) que le boolen retourn est correct. e e e Il ne sagit certainement pas dun algorithme ecace : par exemple pour constater que le mot aab nappartient pas au langage dni par lexpression (a + b) c, e on essaie successivement : (a + b) et aab c ? a (a + b) et (a + b) et ab c ? a (a + b) et a (a + b) et (a + b) et b c ? a (a + b) et a (a + b) et b (a + b) et (a + b) et c ? Il y a donc rptition des m^mes tests, rptition due aux ( points de e e e e e ( dcoupage ) multiples pour reconna^ e tre une concatnation et pour reconna^ e tre ) une toile. Plus prcisment, si lexpression rgulire est la concatnation de k e e e e e e expressions simples (mots ou sommes de mots), alors on teste dans le pire des cas toutes les possibilits de placer k points de dcoupage entre les lettres de u, soit e e pour un mot de longueur n, Ck essais. Compte tenu des court-circuits boolens e n+1 eectus par le compilateur caml, il nest pas vident que tous ces essais soient e e eectus, mais cela se produit certainement si chaque essai choue lors du dernier e e test compil. A k x la complexit dans le pire des cas de la reconnaissance pour e e e un mot de longueur n a un langage de la forme L1 . . .Lk cro^ au moins aussi vite t que nk . Si lexpression rgulire est de la forme L , alors on teste dans le pire des e e cas tous les dcoupages de u en facteurs de longueur suprieure ou gale a 1, e e e donc tous les sous-ensembles de positions distinctes entre les lettres de u et il y a 2n tels sous-ensembles. Dans le cas gnral, la complexit de appartient pour e e e une expression rgulire donne comportant au moins une toile et pour un mot e e e e arbitraire de longueur n est au moins exponentielle.

10-4

Exercices

Exercice 10-1 : mots commutants 1. Lemme de Levi : soient u, v, x, y A tels que uv = xy. Montrer quil existe z A tel que (u = xz et y = zv) ou (x = uz et v = zy). 2. Soient x, y A . Montrer que x et y commutent si et seulement sils sont puissance dun m^me mot. e Exercice 10-2 : expression rguli`re e e Dnir par une expression rgulire le langage des mots sur {a, . . ., z} contenant e e e les lettres a, v, i, o, n dans cet ordre (non ncessairement conscutives). Dnir par e e e une expression rgulire le langage des mots ne contenant pas les lettres a,v,i,o,n e e dans cet ordre.

10-4 Exercices

137

Exercice 10-3 : expression rguli`re e e Dnir par une expression rgulire le langage des mots sur {0, .. ., 9} ne contenant e e e pas le facteur 13. On prouvera que cette expression est correcte. Exercice 10-4 : expression rguli`re e e 1. Donner une expression rgulire dnissant le langage des suites croissantes e e e sur lalphabet {0, . .., 9}. 2. Donner une expression rgulire dnissant le langage des suites arithmtie e e e ques sur lalphabet {0, . .., 9}. Exercice 10-5 : expression rguli`re e e En Turbo-Pascal, un commentaire est un texte plac entre les caractres (* et e e *) ou un texte plac entre les caractres { et }. Donner une expression rgulire e e e e dnissant le langage de ces commentaires. e Exercice 10-6 : langage dni par un syst`me dquations. e e e Soient K, L deux langages sur un alphabet A tels que K ne contient pas le mot vide. 1. Montrer quil existe un unique langage X sur A solution de lquation : e X = KX + L, et dcrire explicitement X. e 2. De m^me, si K, K , L, L , M, M sont des langages sur A tels que K, K , L, L ne e contiennent pas le mot vide, montrer que le systme : e X = KX + LY + M Y =KX+LY +M admet une solution unique (que lon ne demande pas dexpliciter), et que si K, K , L, L , M, M sont rguliers, alors X et Y sont aussi rguliers. e e Exercice 10-7 : expression sans ni Soit L un langage rgulier non vide et ne contenant pas le mot vide. Montrer quil e existe une expression rgulire dnissant L ne faisant intervenir ni ni . e e e Exercice 10-8 : langage non rgulier e Soient L = {an bn tq n N} le langage des parenthses embo^ ees et pour p N, e t Lp = Lbp et Lp = ap L. Montrer que tout langage rgulier inclus dans un Lp e (p Z) est ni. Ceci dmontre que L nest pas rgulier. e e

Chapitre 11 Automates nis

11-1

Dnitions e

Un automate ni est un dispositif physique ou abstrait pouvant se trouver dans un nombre ni dtats et susceptible de changer dtat en raction a un e e e vnement extrieur. Mathmatiquement, un automate est dni par la donne : e e e e e e { de lensemble des vnements susceptibles dinuer sur lautomate. Cet ene e semble est suppos ni non vide, donc constitue un alphabet appel alphabet e e dentre. e { de lensemble des tats de lautomate. Cest galement un ensemble ni non e e vide. { dune fonction de transition qui, pour chaque tat et chaque lettre de e lalphabet dentre indique les tats possibles vers lesquels lautomate peut e e voluer. Cette fonction peut aussi spcier des transitions ( spontanes ) e e e ) ( (lautomate volue sans vnement extrieur) appeles transitions vides ou e e e e e -transitions. la fonction de transition est aussi appele programme de e lautomate. On reprsente gnralement un automate par un graphe de e e e transition dont les nuds sont les tats de lautomate et les ches e e sont les transitions autorises, tiquetes par la ou les lettres correse e e pondant a ces transitions. Par exemple la gure ci-contre prsente e un automate dascenseur simpli dont les tats sont les tages e e e o peut se trouver la cabine et lalphabet dentre est constitu u e e des lettres M (monte) et D (descente) correspondant aux boutons e dappel de la cabine. Un automate est quali de complet si pour chaque tat il e e est dni au moins une transition par lettre dentre, et de dtere e e ministe sil na pas de -transitions et si pour chaque tat il est e dni au plus une transition par lettre dentre. Si un automate e e incomplet reoit une lettre pour laquelle il ny a pas de transition a c partir de ltat courant alors il se bloque et cesse de fonctionner. Si e
M 3 M 2 M 1 M 0 D D D D

automate dascenseur

11-1 Dfinitions e

139

a 0 b 1 a b a b 3 2 a,b

gure 26 : automate non dterministe e un automate non dterministe se trouve dans un tat do part une -transition e e u alors il peut changer dtat selon cette transition sans attendre larrive dune e e lettre dentre. Sil reoit une lettre pour laquelle plusieurs transitions sont dnies e c e alors il peut suivre nimporte laquelle de ces transitions. La gure 26 prsente un e automate incomplet et non dterministe. Si cet automate est plac dans ltat 0 e e e et reoit les lettres a, b, a, a dans cet ordre, alors il peut suivre lun des chemins : c 0 0 0 0 0 a a a a
a

0 0 1 1 1

b b b b

2 2 0 0 0

a a a a

3 3 0 0 1

bloqu e a 2 3 a 0 a 1 a 2

Au contraire, lautomate dascenseur est complet et dterministe, donc il ne peut e jamais se bloquer et partant dun tat donn il ne peut suivre quun seul chemin e e pour une suite de lettres donne. e Dans la vie quotidienne, on utilise des automates pour piloter des appareils physiques ou de manire gnrale eectuer des t^ches automatiques, lautomate e e e a dascenseur relve de ce type dutilisation (dans les ascenseurs modernes il nest pas e ncessaire dappuyer sur un bouton a chaque tage, lexercice 11-4 propose ltude e e e dun modle plus raliste). Un ordinateur peut ^tre considr comme un automate e e e ee ayant un nombre ni dtats, toutes les congurations possibles de sa mmoire, et e e changeant dtat lorsque lon frappe une touche sur un clavier. Les ordinateurs e rels disposent de plusieurs organes dentre que lon peut assimiler a un ensemble e e de claviers, mais aussi dune horloge permettant de dater les vnements reus. e e c Cette notion de temps nest pas prise en compte dans le modle mathmatique, e e elle pourrait l^tre en considrant les tops de lhorloge comme des frappes sur une e e touche particulire. e Soit A un automate dalphabet dentre A, u = a1 .. .an A et x, y deux e tats de A. On dit que u fait passer A de ltat x a ltat y si x et y sont relis par e e e e une cha^ de transitions correspondant aux lettres a1 , .. ., an et au mot vide , les ne lettres gurant dans le m^me ordre que dans u. On dit quil existe une transition e u gnralise, note x y, dtiquette u menant de x a y. Remarquer que si e e e e e A est un automate complet et dterministe alors pour x et u donns il existe un e e u unique tat y tel que x y. Le langage menant de x a y est lensemble des e mots u faisant passer A de x a y, il est not LA(x, y). e Un automate reconnaisseur est un automate dans lequel on choisit un tat e q0 appel tat initial et un ensemble F dtats appels tats nals ou tats e e e e e e

140

Automates finis
u

acceptants : A reconna^ un mot u sil existe un tat nal f F tel que q0 f. t e Le langage reconnu par A est le langage menant de ltat initial a un tat nal e e quelconque. Dans le cas dun automate non dterministe, un mot est reconnu e sil existe au moins une transition gnralise indexe par u de q0 vers F, m^me e e e e e si dautres transitions gnralises peuvent conduire de q0 vers un tat non nal e e e e ou bloquer lautomate. Deux automates reconnaissant le m^me langage sont dits e quivalents. Dans la reprsentation graphique dun automate reconnaisseur, on e e indique par une che entrante ltat initial et par une che sortante ou un e e e cercle double chaque tat nal. Par exemple les deux automates de la gure e 27 sur lalphabet {a, b, c} reconnaissent le langage L = a bc ; le premier est dterministe, le deuxime non. e e
c a 0 b c 1 a 0 a 2 a b 1 b

gure 27 : automates reconnaissant le langage a bc Lintr^t des automates reconnaisseurs, et surtout des automates reconnaisee seurs dterministes, est quils permettent de savoir facilement si un mot donn e e appartient au langage de lautomate : on place lautomate dans ltat initial et on e lui transmet une a une les lettres de u. Si lautomate arrive dans un tat nal alors e le mot appartient au langage ; sinon, et si toutes les possibilits de transition ont e t essayes dans le cas dun automate non dterministe, alors le mot nappartient ee e e pas au langage. Une autre application des automates reconnaisseurs est de permettre le dcoupage dun mot en facteurs appartenant au langage de lautomate : e a chaque fois que lautomate atteint un tat nal, il met le sous-mot reconnu et e e est replac dans ltat initial pour analyser la suite du mot dentre. Les analye e e seurs lexicaux procdent gnralement de cette manire. Par exemple lautomate e e e e de la gure 28 reconna^ les expressions arithmtiques non parenthses conformes t e ee a la syntaxe de caml. Ltat nal 1 correspond aux constantes entires, les tats e e e nals 4 et 8 correspondent aux constantes ottantes, ltat nal 2 aux oprations e e entires, ltat nal 5 aux oprations ottantes et ltat nal 3 aux identicateurs e e e e crits en minuscules. Bien que cet automate soit dterministe, il y a ambigut e e e sur la manire de dcouper un mot en lexmes, par exemple le mot 12.3E+07 e e e peut ^tre dcoup en 1, 2.3E+0, 7. Ce dcoupage ne correspond pas a la syntaxe e e e e usuelle des expressions arithmtiques, mais cette syntaxe ne gure pas dans la dese cription de lautomate. Gnralement les analyseurs lexicaux choisissent en cas e e dambigut le sous-mot le plus long reconnaissable, et dans le cas dun automate e non dterministe, sil y a plusieurs tats nals correspondant a ce sous-mot, ils e e choisissent entre ces tats selon une rgle de priorit inscrite dans lanalyseur. e e e Enn un automate peut aussi servir a chercher un mot dans un texte. Lau tomate de la gure 29 reconna^ les textes contenant le mot ennemi. Si on lui t

11-2 Simulation dun automate fini

141

0..9 1 0..9 0 +*/ a..z 3 a..z,0..9 2 . .

0..9 4 5 E 6 + 7 0..9 0..9

0..9 8

gure 28 : automate reconnaissant les expressions arithmtiques simplies e e soumet un tel texte alors il aboutit a ltat nal n 6 sur la premire occurrence e e du mot ennemi et reste dans cet tat pour lire le reste du texte. A partir dun e tat, les transitions tiquetes correspondent a toutes les lettres autres que celles e e e explicitement indiques comme partant de ltat considr. e e ee

e 0 _ e 1 _ n 2

e n _

n 3 _ e 4

e m _ 5

e i _

_ 6

gure 29 : automate reconnaissant la premire occurrence de ennemi e

11-2

Simulation dun automate ni.

On peut simuler le fonctionnement dun automate sur un ordinateur, il sut de conserver en mmoire les tats et transitions de lautomate et de suivre ces e e transitions en parcourant un mot a analyser. Les problmes algorithmiques lis a e e cette simulation sont de choisir sous quelle forme on mmorise les transitions, et e de quelle manire on gre le non-dterminisme. e e e Simulation dun automate dterministe e Dans le cas dun automate dterministe il sut pour conna^ e tre lautomate de spcier ltat initial, les tats nals et la fonction de transition qui indique a e e e partir dun tat et dune lettre vers quel tat lautomate doit voluer. En pratique, e e e si les tats et les lettres sont des nombres entiers alors on peut dnir la fonction de e e transition par une matrice de transition M telle M.(e).(l) contient ltat accessible e a partir de ltat e et de la lettre l, et un entier particulier, par exemple 1, pour e les transitions non dnies. On peut gnralement se ramener facilement a ce cas e e e puisque lensemble des tats et lalphabet dentre sont nis, donc numrotables. e e e

142

Automates finis

Par exemple lautomate de transition :

e e ( ennemi ) de la gure 29 est reprsent par la matrice ( ) e 1 1 1 4 1 1 1 n m 0 0 2 0 3 0 0 0 2 5 0 0 1 1 i 0 0 0 0 0 0 0 0 0 0 6 0 1 1

0 1 2 3 4 5 6

On a comprim la matrice en notant une lettre quelconque autre que e e,n,m,i. Sans cette compression ou pour un automate ( surveillant ) un plus ( ) grand nombre de lettres, on obtiendrait une matrice norme contenant essentiellee ment des transitions indnies (1) ou menant a ltat initial (0). Une mthode e e e de stockage plus lgante qui nimpose pas le codage des tats et des lettres par ee e des entiers consiste a crire une fonction de transition directement en caml. La e fonction de transition de ( ennemi ) peut ^tre code de la manire suivante : e e e ( )
(* e = etat, l = lettre *) let transition(e,l) = match | (0,e) -> 1 | (0,_) -> | (1,e) -> 1 | (1,n) -> | (2,e) -> 1 | (2,n) -> | (3,e) -> 4 | (3,_) -> | (4,e) -> 1 | (4,n) -> | (5,e) -> 1 | (5,i) -> | (6,_) -> 6 | _ -> failwith "tat e ;; (e,l) with 0 2 | (1,_) 3 | (2,_) 0 2 | (4,m) 6 | (5,_) inconnu"

-> 0 -> 0 -> 5 | (4,_) -> 0 -> 0

De cette manire on nindique que les transitions existantes, et on peut e ventuellement regrouper plusieurs cas identiques a laide de tests appropris. e e Linconvnient de la mthode ( fonction ) par rapport a la mthode ( matrice ) e e e ( ) ( ) est que le temps de calcul dune transition est plus long puisquil faut examiner tous les cas successivement avant de trouver celui qui sapplique. On peut aussi mlanger les deux mthodes en crivant une fonction qui limine rapidement les e e e e cas simples et consulte une ou plusieurs tables dans les autres cas. On utilisera ici la mthode ( fonction ) pour stocker lautomate. e ( )
(* a est le type des etats, b est celui des lettres *) type (a,b) automate = { dpart : a; e (* etat initial *) final : a -> bool; (* dit si un etat est final *) transition : (a * b) -> a (* fonction de transition *) };;

11-2 Simulation dun automate fini

143

(* a est un automate dterministe, u un mot a analyser *) e ` (* dit si u appartient au langage de a. *) let analyse(a,u) = try let e = ref(a.dpart) in e for i = 0 to vect_length(u)-1 do e := a.transition(!e,u.(i)) done; a.final(!e) with Failure "transition indfinie" -> false e ;;

La correction de analyse est immdiate, et sa complexit pour un autoe e mate a donn est proportionnelle a la longueur de u sous rserve que la fonction e e a.transition sexcute en un temps constant. e On peut aussi reprsenter un automate par un ensemble de fonctions mue tuellement rcursives o chaque appel rcursif correspond a une transition : e u e
let rec etat_0(u) = match u with | e :: v -> etat_1(v) | _ :: v -> etat_0(v) | _ -> false and etat_1(u) | e :: v -> | n :: v -> | _ :: v -> | _ -> and etat_2(u) | e :: v -> | n :: v -> | _ :: v -> | _ -> and etat_3(u) | e :: v -> | _ :: v -> | _ -> = match u with etat_1(v) etat_2(v) etat_0(v) false = match u with etat_1(v) etat_3(v) etat_0(v) false = match u with etat_4(v) etat_0(v) false and etat_4(u) | e :: v -> | n :: v -> | m :: v -> | _ :: v -> | _ -> and etat_5(u) | e :: v -> | i :: v -> | _ :: v -> | _ -> = match u with etat_1(v) etat_2(v) etat_5(v) etat_0(v) false = match u with etat_1(v) etat_6(v) etat_0(v) false

and etat_6(u) = true ;;

Un mot u (reprsent ici par une liste cha^ ee de lettres) est reconnu si et e e n seulement si lappel etat_0(u) retourne true. Ce codage est moins compact que la fonction de transition dnie plus haut, mais chaque fonction de transition e sexcute plus rapidement puisquelle na a examiner que la premire lettre du e e mot propos et non le couple (tat, lettre). Tous les appels rcursifs sont tere e e minaux, donc lanalyse dun mot peut ^tre compile de manire a sexcuter en e e e e mmoire constante. Le logiciel camllex est un gnrateur de programmes : a partir e e e

144

Automates finis

dune expression rgulire fournie en entre, il construit un automate dterministe e e e e reconnaissant le langage associ et rdige un programme caml simulant cet aue e tomate par la technique des fonctions mutuellement rcursives. e Simulation dun automate non dterministe e Un automate non dterministe peut ^tre reprsent par une fonction de trane e e e sition retournant pour un tat et une lettre donns la liste des tats accessibles, e e e et une deuxime fonction retournant la liste des tats accessibles a partir dun e e tat donn par une -transition. Dans la mesure o lautomate est constant on e e u peut calculer, lors de la construction de lautomate, pour chaque tat la liste de e tous les tats accessibles par un nombre quelconque de -transitions et adapter e en consquence la fonction de transition sur lettre. Il est alors plus commode de e considrer que lautomate dispose de plusieurs tats initiaux, exactement tous les e e tats accessibles a partir de ltat initial ( ociel ) par des -transitions. On est e e ( ) donc ramen au problme suivant : e e tant donns un automate non dterministe sans -transitions, un ene e e semble I dtats initiaux, un ensemble F dtats nals et un mot u, e e dterminer si lon peut passer dun tat de I a un tat de F en suivant e e e les transitions correspondant aux lettres de u. Ce problme sapparente a un parcours de graphe o lon cherche un chemin e u menant dune source a un but dans un graphe orient a priori quelconque. Il existe e essentiellement deux solutions a ce problme, le parcours en profondeur dabord e du graphe : on suit un chemin aussi loin que possible, puis on revient rcursivement e sur les choix eectus en cas dimpasse ; et le parcours en largeur dabord : e on explore en parallle tous les chemins possibles. La mthode du parcours en e e profondeur dabord sapparente a lalgorithme prsent a la section 10-3 pour la e e reconnaissance dune expression rgulire. Lalgorithme de parcours en largeur est e e simple : dterminer tous les successeurs autoriss de tous les tats de I compte e e e tenu de la premire lettre de u, et appliquer rcursivement lalgorithme avec cet e e ensemble de successeurs et la suite de u.
(* a est le type des etats, b est type (a,b) automate_nd = { dpart : a list; e final : a -> bool; transition : (a * b) -> a list };; celui des lettres *) (* etats initiaux *) (* etat final ? *) (* fct. de transition *)

(* cherche tous les successeurs dune liste dtats *) e let rec successeurs(a,liste,lettre) = match liste with | [] -> [] | x::suite -> union (a.transition(x,lettre)) (successeurs(a,suite,lettre)) ;;

11-2 Simulation dun automate fini (* a est un automate non dterministe, u un mot a analyser *) e ` (* dit si u appartient au langage de a. *) let analyse_nd(a,u) = let l = ref(a.dpart) in e for i = 0 to vect_length(u)-1 do l := successeurs(a,!l,u.(i)) done; exists a.final !l ;;

145

union et exists sont des fonctions de la bibliothque standard de caml e ralisant lunion sans rptition de deux listes et cherchant si une liste contient un e e e lment satisfaisant une proprit. La fonction de transition de lautomate doit ee ee renvoyer une liste de successeurs dans tous les cas, ventuellement une liste vide e pour une transition indnie, car si lautomate se bloque sur un tat il faut pouvoir e e continuer lanalyse avec les autres tats stocks dans !l. Par exemple lautomate e e de la gure 27 est dni par : e let a = { dpart = [0]; e final = (fun x -> x = transition = (function | | | | | };;

1); (0,a) (0,b) (1,c) (2,a) (2,b) _

-> -> -> -> -> ->

[0;2] [1] [1] [2] [1] [])

Complexit : chaque lettre de u donne lieu a un appel a la fonction successeurs sur e la liste des tats atteints, et cette liste est de taille borne puisque lautomate est e e ni et la fonction union ralise une union sans rptition. La complexit temporelle e e e e de analyse_nd est donc linaire par rapport a la taille de u, et il en est de m^me e e de la complexit spatiale puisquon cre pour chaque lettre de u une nouvelle liste e e !l de taille borne par le nombre dtats de lautomate. Comme lancienne liste e e nest plus utilise, la mmoire quelle occupe peut ^tre ( recycle ) et dans ce cas e e e e ) ( la complexit spatiale de analyse_nd est constante. e Ainsi, aussi bien avec un automate dterministe quavec un automate non e dterministe, on peut reconna^ lappartenance dun mot de longueur n a un lane tre gage donn en O(n) oprations, ce qui amliore nettement la complexit obtenue e e e e par parcours dune expression rgulire (cf. section 10-3). A priori les langages e e reconnus ne sont pas de m^me type, lalgorithme de la section 10-3 ne reconna^ e t que lappartenance a un langage rgulier tandis que les deux versions de analyse e traitent de langages dits reconnaissables, cest--dire reconnaissables par un aua tomate ni. On verra quen fait un langage est rgulier si et seulement sil est e reconnaissable (thorme de Kleene) donc la comparaison des algorithmes de e e reconnaissance est pertinente.

146

Automates finis

11-3

Dterminisation dun automate e

Les fonctions analyse et analyse_nd vues a la section prcdente sont trs e e e semblables : on part dun tat initial et on applique la fonction de transition a e cet tat pour chaque lettre du mot u a analyser, ou on part dune liste dtats e e initiaux et on applique la fonction successeurs a cette liste pour chaque lettre de u. Cette similitude suggre quun automate ni non dterministe A est formellement e e quivalent a un automate dterministe A construit de la manire suivante : e e e { les tats de A sont les sous-ensembles dtats de A (si A a n tats alors A e e e a 2n tats) ; e { pour un ensemble E dtats de A et une lettre a, A dnit une unique e e transition partant de E tiquete par a, arrivant sur lensemble E constitu e e e de tous les tats de A accessibles a partir dun tat lment de E par une e e ee transition gnralise dtiquette a ; e e e e { ltat initial de A est lensemble de tous les tats de A accessibles a partir e e des tats initiaux de A par des -transitions ; e { un tat E de A est nal si et seulement sil contient un tat nal de A. e e Toutes ces rgles peuvent ^tre appliques de manire automatique puisque A a un e e e e nombre ni dtats, cest--dire quil est possible de ( construire ) lautomate A e a ( ) a partir dune description convenable de A. Les dtails de cette construction font e lobjet de lexercice 11-5. Complexit : partant dun automate A a n tats, . .. e e { On construit les 2n tats de A ce qui ncessite O(n2n) oprations (en supe e e posant quun tat de A est reprsent par une liste dtats de A ou un vecteur e e e e de boolens, il faut O(n) oprations pour crer cette liste ou ce vecteur). e e e { On cherche ensuite pour chaque tat de A tous les tats accessibles par e e -transitions, ce qui peut ^tre fait en O(n3 ) oprations (algorithme de Ware e shall, cf. exercice 11-5 et [Froid] ch. 19). { Puis, pour chaque tat et chaque lettre de lalphabet dentre, on dtermine e e e les tats accessibles depuis cet tat en suivant cette lettre et les -transitions. e e Il y a pour un tat et une lettre donns au maximum n transitions sur lettre e e a considrer et donc n sous-ensembles de taille infrieure ou gale a n a e e e runir ; au total, lalphabet dentre tant de taille xe, il faut eectuer e e e e O(n3) oprations. e { Enn on dtermine les transitions des tats de A par runion des ensembles e e e prcdents, ce qui ncessite O(n22n ) oprations. e e e e La complexit totale de lalgorithme de dterminisation est donc O(n2 2n) e e pour un automate non dterministe a n tats. e e Lorsque n est petit cet algorithme peut ^tre excut en un temps raisonnable, e e e mais si n dpasse quelques dizaines il est impraticable. Il y a deux solutions a ce e problme : e

11-4 Le thorme de Kleene e e

147

1. Conserver lautomate non dterministe : lalgorithme de reconnaissance nest e plus lent que dun facteur constant entre un automate non dterministe et e un automate dterministe quivalent ; si lon a peu de mots a tester alors le e e gain a attendre de la dterminisation ne vaut pas leort quil faut fournir. e 2. Appliquer lalgorithme de dterminisation en ne gnrant que les tats utiles, e e e e cest--dire les sous-ensembles dtats de A eectivement obtenus a partir de a e ltat initial en suivant toutes les -transitions et les transitions sur lettre e possibles. Si lautomate nest pas trop compliqu, on peut esprer obtenir un e e automate dterministe nayant pas trop dtats en O(n3 + n2 N) oprations e e e o N est le nombre dtats de lautomate dterministe eectivement construit u e e (cf. exercice 11-5). Il existe cependant des cas pathologiques o tout autou mate dterministe quivalent a A a au moins 2n1 tats (cf. section 11-6). e e e Exemple
0 a 4 b 3 a a a 2 a a 1 b

dpart e {0} {0} {1, 4} {1, 4} {0, 2, 3} {0, 2, 3} {1, 2, 3, 4} {1, 2, 3, 4}


a 023 b

lettre a b a b a b a b

arrive e {1, 4} {0, 2, 3} {1, 2, 3, 4} {1, 2, 3, 4} {0, 2, 3}

automate non dterministe e


0 a 14 b

table de transition
1234 a

automate dterministe quivalent e e

11-4

Le thor`me de Kleene e e

Thor`me : soit L un langage sur un alphabet A. Il y a quivalence entre : e e e 1. L est dni par une expression rgulire. e e e 2. L est reconnu par un automate ni. Dmonstration de 1 = 2 (construction de Thompson) e L est reprsent par une expression rgulire E que lon assimile a un are e e e bre comme a la section 10-3. On construit rcursivement un automate non e dterministe E qui simule le parcours de E : a chaque nud n de E on assoe cie deux tats dans E , un tat dentre et un tat de sortie (un seul tat pour un e e e e e nud de type Etoile). On place des -transitions entre ces tats et ceux des ls e de n comme indiqu gure 30, et des transitions sur lettre entre les lettres dune e feuille de type Mot (ou une -transition dans le cas du mot vide). Les feuilles correspondant au langage vide nont pas de transition dnie. Il est clair, par e rcurrence sur la taille de E, que E reconna^ exactement le langage dcrit par e t e lexpression rgulire E. e e

148
Somme
+

Automates finis
Concatnation
.

Etoile
*

Mot
mot

Vide
vide

uvxyz M N M N M

u v x

z y

M (L+M)

M (LM)

M (M*)

(uvxyz)

gure 30 : transformation dune expression rgulire en automate e e La gure 31 illustre la transformation de lexpression rgulire (a+b) (a+c) e e en automate reconnaisseur. Dans un premier temps on obtient un automate a 16 tats, mais on peut supprimer des tats ( inutiles ) et raccourcir les transitions e e ( b ) a associes : 2 4 5 3 et 2 6 7 3 sont rassembles en une e e a,b seule transition 2 3 et de m^me pour la branche (a + c), ce qui limine 8 e e tats. On peut aussi dplacer les points dentre et de sortie de lautomate vers e e e le point dentre de (a + b) et le point de sortie de (a + c) et enn raccourcir e les boucles reconnaissant (a + b) et (a + c) ce qui fournit un automate non dterministe a deux tats. Cet automate peut ^tre transform selon lalgorithme e e e e de dterminisation en un automate dterministe a trois tats. e e e

15

10


5 6

7 11

12


13

14

gure 31 : automate reconnaissant lexpression (a + b) (a + c)

11-4 Le thorme de Kleene e e

149

a,c
1

18

c b

10

a,b,c

a,b

a,c

a,b

a,b

a,c

gure 32 : automates simplis e Automate index par des expressions rguli`res e e e Pour dmontrer la rciproque (un automate reconna^ un langage rgulier), e e t e on gnralise la notion dautomate en considrant des automates indexs par des e e e e expressions rgulires sur lalphabet A. Un tel automate A est dni par un ene e e semble dtats ni non vide, et une fonction de transition qui associe a tout couple e x,y dtats (x, y) une expression rgulire Ex,y sur A, ce que lon note : x E y avec e e e linterprtation suivante : partant de ltat p, lautomate peut passer dans ltat e e e q en lisant un mot u si et seulement sil existe une suite dtats (x0 , . . ., xn) telle e que x0 = p, xn = q, et u appartient au langage dcrit par lexpression rgulire : e e e Ex0 ,x1 . ..Exn1 ,xn . On note LA(p, q) le langage des mots faisant passer A de ltat e p a ltat q. Remarquons quun automate ( ordinaire ) est un cas particulier e ( ) dautomate index par des expressions rgulires o les expressions E x,y sont e e e u ou des sommes nies de lettres et de . Dmonstration de 2 = 1 (mthode par suppression dtats) e e e Soit A un automate ordinaire ni. Comme le langage reconnu par A est une somme de langages LA(q0 , f) o q0 est un tat initial et f un tat nal quelconque, u e e il sut de prouver que pour tous tats x, y de A le langage LA (x, y) est rgulier. e e On xe donc deux tats x, y de A et on considre dsormais que A est index par e e e e des expressions rgulires. e e
v u w v + w u

gure 33 : suppression de ltat u e Considrons un tat u de A autre que x ou y. On construit un automate e e A , lui aussi index par des expressions rgulires, ayant pour tats tous les tats e e e e e de A sauf u, et tel que pour tous tats v, w de A on ait LA (v, w) = LA(v, w). e Soient v, w deux tats de A tels quil y a une transition v w et une cha^ de e ne transitions v u u w dans A. Alors on remplace la transition v w

150

Automates finis

par v + w (cf. gure 33). Ceci tant fait pour tous couples (v, w), on e e obtient un automate A qui vrie LA (v, w) = LA(v, w) pour tous tats v, w. Le e m^me procd peut ^tre appliqu a A et de proche en proche on aboutit a lun e e e e e des automates A ou A de la gure 34 selon que x = y ou x = y o , , , u et sont des expressions rgulires. e e

gure 34 : automates rduits e Donc LA(x, x) = LA (x, x) = ou LA (x, y) = LA (x, y) = (+ ) sont des langages rguliers et ceci achve la dmonstration du thorme de Kleene. e e e e e Exemple : considrons lautomate ordinaire non dterministe gure 35 ( gauche). e e a En supprimant dabord les tats 1 et 4 puis ltat 2 et enn ltat 3, on obtient e e e limposante expression : ab + ab(ab) ab + (ab + ab(ab) a(ab + a(ab) a) (ab + a(ab) ab)) pour le langage reconnu. En appliquant la m^me technique a lautomate dtermie e niste quivalent obtenu en 11-3, on obtient une expression plus simple : e + ab(aa b) . Cest un excellent exercice de patience que de montrer a la main lquivalence e de ces deux expressions. Ainsi, le langage reconnu par lautomate est form du e mot vide et de lensemble des mots constitus des lettres a et b, commenant par e c ab, se terminant par b et ne contenant pas deux b conscutifs. e

b a 4 a

0 a

b 1 a

ab

ab+ab(ab)*ab

ab ab ab a
b

ab

ab+ab(ab)*a ab+a(ab)*ab

b 3

a a 2

ab

ab

ab+a(ab)*a

gure 35 : recherche dune expression rgulire e e

11-5 Stabilit et algorithmes de dcision e e

151

11-5

Stabilit et algorithmes de dcision e e

Thor`me : soient L, L deux langages rguliers sur un alphabet A. Alors e e e les langages L, L L et L \ L sont rguliers. e Dmonstration : on a L L = L + L et L \ L = L + L donc il sut de prouver e e e que L est rgulier. Soit A un automate dterministe reconnaissant L. On peut supposer que A est complet car si ce nest pas le cas, on peut ajouter a A un tat rebut et diriger vers cet tat toutes les transitions indnies dans A, et faire e e e boucler ltat rebut sur lui-m^me pour toutes les lettres de A. On suppose donc e e que pour tout mot u A , il existe un unique tat xu de lautomate complt e ee u tel que q0 xu o q0 est ltat initial de A. Alors L est lensemble des mots u u e tels que xu F o F dsigne lensemble des tats nals de A, et L est lensemble u e e des mots u tels que xu F, cest--dire que L est reconnu par le m^me automate a e que L en changeant lensemble des tats nals en son complmentaire. e e Il est ainsi possible, a partir dune expression rgulire E dnissant un lan e e e gage L, de construire par programme une expression rgulire E dnissant le e e e langage L : on construit un automate reconnaissant L, on le transforme en automate dterministe et on le complte, on change les tats nals et non nals et on e e e e reconstruit une expression rgulire, probablement abominable, pour lautomate e e obtenu. De m^me on peut par programme trouver une expression rgulire recone e e naissant lintersection ou la dirence de deux langages dnis par des expressions e e rgulires. e e Compte tenu de la taille des expressions obtenues, les algorithmes prcdents e e sont pratiquement de peu dutilit. Cependant, dun point de vue thorique, il e e existe donc des algorithmes rpondant aux questions suivantes : e { Un langage dni par une expression rgulire est-il vide ? L = M + N est e e e vide si et seulement si M et N le sont ; L = MN est vide si et seulement si M ou N lest ; L = M nest jamais vide. On peut donc ramener le problme e de la vacuit au m^me problme pour des expressions rgulires plus courtes e e e e e et les cas de base, , , lettre ou mot sont vidents. En termes dautomates, e on peut dterminer si le langage reconnu par un automate ni est non vide e en cherchant sil existe un chemin menant dun tat initial de lautomate e a un tat nal, avec lalgorithme de Warshall (de complexit O(n3 ) o e e u n est la taille de lautomate). Donc la question de la vacuit est rsoluble e e algorithmiquement. { Un langage dni par une expression rgulire est-il ni ? L aussi, ce e e e a problme se ramne au m^me problme pour des expressions rgulires plus e e e e e e courtes. { Deux expressions rgulires dnissent-elles le m^me langage ? Si L et L e e e e sont les langages dnis par ces expressions rgulires, il sut de tester si e e e L \ L et L \ L sont vides, ce qui est dcidable puisque lon peut obtenir des e expressions rgulires pour ces deux langages. e e Ainsi, lgalit smantique de deux expressions rgulires est dcidable par e e e e e e programme.

152

Automates finis

11-6

Langages non rguliers e

Daprs le thorme de Kleene, un langage rgulier est reconnaissable par e e e e un automate ni, et cet automate ne peut ( mmoriser ) quun nombre born de e ( e ) lettres dun mot a analyser puisquil a un nombre ni dtats. En consquence, tout e e langage dni par une condition imposant de mmoriser un nombre arbitrairement e e grand de lettres est non reconnaissable par automate ni et donc non rgulier. Les e exemples les plus simples de langages non rguliers sont : e { le langage des parenthses embo^ ees : L = {an bn tq n N} ; e t { le langage des parenthses correctement imbriques : L est dni comme tant e e e e le plus petit langage sur {a, b} solution de l quation : L = + aLb + LL ; e { le langage des palindromes : L = {u(a + )~ tq a A et u A } o A est u u un alphabet ayant au moins deux lettres. Formellement, les dmonstrations dirrgularit utilisent la notion de langage re e e e siduel ou le lemme de ltoile. e Soit L un langage sur A et u A . Le langage rsiduel associ a u et L est e e le langage not u1L dni par : e e u1L = {v A tq uv L}. u1L est lensemble des mots pouvant complter u en un mot lment de L. Cest e ee un langage (sous-ensemble de A ) qui peut ^tre vide ou non selon les cas. e Thor`me : soit L un langage rgulier sur un alphabet A. Alors pour tout e e e mot u A le langage rsiduel u1L est rgulier et lensemble des langages e e rsiduels obtenus lorsque u dcrit A est ni. e e Dmonstration : soit A un automate ni dterministe complet reconnaissant L, e e q0 ltat initial et F lensemble des tats nals de A. Si u A , soit xu ltat e e e atteint a partir de q0 en lisant les lettres de u. Alors u1L est le langage faisant passer A de xu a lun des tats nals, donc est rgulier. Et il y a au plus autant e e de langages rsiduels distincts associs a L quil y a dtats dans A. e e e Remarque : la rciproque est vraie, cest--dire que si un langage admet un nombre e a ni de rsiduels, alors il est rgulier (cf. [Stern], ch. 1.4). e e Application : soit L le langage des parenthses embo^ ees. Pour n N on note e t Ln = (an )1 L. Alors les ensembles Ln sont deux a deux distincts car si n = p alors bn Ln et bn Lp . Ainsi, L admet une innit de langages rsiduels distincts, / e e ce qui prouve que L nest pas rgulier. Lirrgularit des autres langages cits e e e e ci-dessus se dmontre de la m^me manire en exhibant une innit de rsiduels e e e e e distincts. Autre application : soit Ln le langage sur {a, b} constitu des mots dont la ne me lettre avant la n est un a. Ln est rgulier : Ln = (a + b) a(a + b)n1 , et e e lautomate non dterministe de la gure 36 reconna^ Ln . Si u est un mot de n e t lettres sur {a, b}, alors la connaissance de u1Ln permet de reconstituer u car

11-7 Exercices

153

a,b 0 a 1 a,b a,b n

gure 36 : automate a n + 1 tats dont le dterminis a au moins 2n tats e e e e la i-me lettre de u est un a si et seulement si ai1 u1Ln . Cela signie que e Ln a au moins 2n langages rsiduels distincts, donc tout automate dterministe e e complet reconnaissant Ln a au moins 2n tats. Lautomate non dterministe de e e la gure 36 constitue un exemple sur lequel toute mthode de dterminisation a e e une complexit exponentielle. e Thor`me : (lemme de ltoile) soit L un langage rgulier. Alors il existe e e e e un entier n tel que tout mot u L de longueur suprieure ou gale a n se e e dcompose en trois parties : u = xyz avec |xy| n, |y| 1 et xykz L pour e tout k N. Autrement dit, dans un langage rgulier, pour tout mot u susamment long e on peut supprimer ou dupliquer la partie centrale de u un nombre arbitraire de fois sans quitter L. Contrairement au thorme sur les rsiduels en nombre ni, le e e e lemme de ltoile ne constitue pas une caractrisation des langages rguliers (cf. e e e exercice 11-13). Dmonstration : puisque L est rgulier, il admet un nombre n ni de langages e e rsiduels. Soit u L de longueur suprieure ou gale a n. u admet n + 1 prxes e e e e de longueur infrieure ou gale a n donc il existe deux prxes produisant le m^me e e e e langage rsiduel. Notons x et xy ces prxes, (donc |xy| n et |y| 1) et soit e e u = xyz. Alors (xy)1L = x1L cest--dire : a v A , xyv L xv L. En particulier, xyz L donc xz L mais aussi x(yz) L donc xy(yz) L et de proche en proche, pour tout k N, xyk z L. Exemple : le langage des parenthses embo^ ees nest pas rgulier (troisime e t e e dmonstration en comptant celle de lexercice 10-8). En eet, soit n N quele conque et u = an bn L que lon dcoupe en u = xyz avec |xy| n et |y| 1. e Le facteur y est de la forme y = ap avec p 1, donc xz = anp bn L . /

11-7

Exercices

Exercice 11-1 : multiples de 3 Soit A = {0, 1}. On interprte un mot sur A comme la reprsentation binaire e e dun entier naturel avec le bit de poids fort en t^te. Construire un automate e reconnaissant les multiples de 3.

154

Automates finis

Exercice 11-2 : automate squentiel e Un automate squentiel est un automate dterministe muni de deux alphabets : e e lalphabet dentre, A, et lalphabet de sortie, B. Chaque transition est tiquete e e e par un couple (a, w) o a A et w B . Lautomate peut utiliser cette transition u sil reoit la lettre a et dans ce cas, il met le mot w (penser a un ordinateur muni c e dun clavier et dune imprimante). Que fait lautomate squentiel suivant ? e
(0,0) 0 (0,1) (1,1) 1 (0,0) (1,0) 2 (1,1)

Exercice 11-3 : automate produit Soient A, B deux automates nis dterministes complets. Lautomate produit e A B a pour tats tous les couples (a, b) o a est un tat de A et b un tat de e u e e x x B et pour transitions : (a, b) (a , b ) si a a est une transition de A et x b b une transition de B. Si LA et LB sont les langages reconnus par A et B, comment peut-on reconna^ les langages LA LB , LA LB , LA \ LB a laide de tre AB ? Exercice 11-4 : ascenseur Dans un immeuble de trois tages (Rdc, 1er, 2me) on installe un ascenseur avec e e un bouton dappel a chaque tage et un bouton pour chaque tage dans la cabine. e e Concevoir lautomate rgissant cet ascenseur de sorte que : e { lascenseur se rend aux tages demands ; e e { lascenseur sarr^te aux tages intermdiaires sil est appel en cours de voyage e e e e a un tel tage. e On supposera quil ny a pas dappels simultans. e Exercice 11-5 : algorithme de dterminisation e Soit A un automate non dterministe sur lalphabet {0, . .., p 1} dont les tats e e sont numrots de 0 a n 1, donn par : e e e 1. 2. 3. 4. 5. le nombre n dtats et le nombre p de lettres ; e la liste des -transitions (liste de couples (dpart,arrive)) ; e e la liste des transitions sur lettre (liste de triplets (dpart, lettre, arrive)) ; e e la liste des tats initiaux ; e la liste des tats nals. e

Ecrire une fonction caml produisant un automate dterministe A quivalent a A. e e A sera dni par : e 1. 2. 3. 4. le nombre q dtats ; e la liste des transitions sur lettre (liste de triplets (dpart, lettre, arrive)) ; e e le numro de ltat initial ; e e la liste des tats nals. e

11-7 Exercices

155

Exercice 11-6 : simplication dun automate Soit A un automate et q un tat de A. On appelle langage dentre de q le e e langage faisant passer A dun tat initial a q et langage de sortie de q le langage e faisant passer A de q a un tat nal de A. On dit quun tat est accessible si son e e langage dentre est non vide et coaccessible si son langage de sortie est non vide. e Un tat non coaccessible est appel tat rebut. e ee 1. Montrer que lautomate A dduit de A en retirant tous les tats non accessie e bles ou non coaccessibles et les transitions issues de ces tats ou aboutissant e a ces tats est quivalent a A. e e 2. Donner un algorithme en franais permettant de construire A a partir de A. c 3. Caractriser la proprit ( A est dterministe ) en termes de langage dentre. e ee ( e e ) 4. Soit A quelconque. On construit successivement : B lautomate miroir de A (on retourne les ches et on intervertit les tats dentre et de sortie) ; e e e C le dterminis de B par la mthode des sous-ensembles sans tat rebut ; e e e e D lautomate miroir de C ; E le dterminis de D par la mthode des souse e e ensembles sans tat rebut. e Montrer que E est quivalent a A, que tous les tats de E sont coaccese e sibles, et que deux tats de E distincts ont des langages de sortie distincts. e 5. Dmontrer que tout automate dterministe quivalent a A a au moins autant e e e dtats que E (E est appel automate dterministe minimal quivalent a A). e e e e Exercice 11-7 : langage a une lettre ` Soit L un langage sur lalphabet a une lettre {a}. Montrer que L est rgulier e si et seulement sil existe deux langages nis F et G et un entier n tels que L = F + G(an ) . Exercice 11-8 : racine carre dun langage e Soit L un langage sur un alphabet A. On note L = {u A tq u2 L}. Montrer que si L est rgulier alors L lest aussi. e Exercice 11-9 : rsiduels dun langage rgulier e e Dmontrer quun langage rgulier na quun nombre ni de rsiduels en utilie e e sant uniquement la dnition des expressions rgulires (cest--dire sans utiliser e e e a dautomate reconnaisseur). Exercice 11-10 : langage des parenth`ses embo ees e t 1. Ecrire une fonction caml prenant un mot u (vecteur de lettres) et disant sil appartient au langage L = {an bn , n N} (langage des parenthses e embo^ ees). t 2. Un ordinateur excutant la fonction prcdente constitue un automate recone e e naissant le langage des parenthses embo^ ees, connu pour ^tre non rgulier. e t e e Comment est-ce possible ?

156

Automates finis

Exercice 11-11 : Congruences Montrer que L5 = {u {a, b} tq |u|a |u|b mod 5} est un langage rgulier. e Montrer que L = {u {a, b} tq |u|a = |u|b} ne lest pas. Exercice 11-12 : Un automate sait-il compter ? 1. On reprsente un triplet dentiers (m, n, p) par le mot am bn cp sur lalphabet e {a, b, c}. Montrer que le langage des additions exactes : L = {am bn cp tq m + n = p} nest pas reconnaissable par automate ni (un automate ne peut donc pas vrier une addition). e 2. On reprsente un triplet (m, n, p) par le mot m0 n0p0 m1 n1p1 .. .mq nqpq sur e lalphabet {0, 1} o mq .. .m0 , nq . . .n0 et pq . ..p0 sont les critures binaires u e de m, n et p prolonges par des zros pour avoir m^me longueur. Montrer que e e e le langage des additions exactes pour cette reprsentation est reconnaissable e par automate ni (un automate peut donc vrier une addition). e Exercice 11-13 : contre-exemple au lemme de ltoile e Soit A un alphabet ayant au moins deux lettres. Dmontrer que le langage e L = {p~q tq p A+ , q A } vrie le lemme de ltoile, mais nest pas rgulier. p e e e Exercice 11-14 : test de nitude pour un langage rgulier e Soit L un langage dni par une expression rgulire E sur un alphabet A. On e e e remplace dans E les symboles par des zros, les symboles par des 1, et chaque e lettre par un 2. Soit E lexpression obtenue. On interprte alors E comme une e formule ( algbrique ) sur lensemble X = {0, 1, 2, } avec les oprations : e ( e ) x + y = max(x, y) ; 0x = x0 = 0, 0 = 1,

1x = x1 = x, 2 = ,

22 = 2, = .

1 = 1,

2 = 2 = ;

Montrer que lvaluation de E retourne 0 si et seulement si L est vide. Caractriser e e les langages L pour lesquels lvaluation de E retourne 1, retourne 2, retourne . e

Probl`mes e

158

Problmes e

Tri par distribution

Question 1 Soit a un entier naturel. On sait que a admet une unique criture binaire : e a = a0 + 2a1 + 4a2 + .. . + 2n1an1, o ai {0, 1} et n est un entier naturel susamment grand. Le nombre ai est u appel i-me bit de a ou aussi bit i de a. e e a) Donner une expression simple calculant a0 en fonction de a. b) Quelle est lcriture binaire de a/2 en fonction de celle de a ( e partie entire) ? e dsigne la e

c) En dduire une fonction caml bit : int -> int -> int telle que bit p a e retourne le bit p de a si a et p sont des entiers naturels. On donnera deux versions : une version rcursive et une version itrative. e e Question 2 Soit v = [|v0; v1; . ..; vn1|] un vecteur a lments entiers naturels. On veut ee rordonner ce vecteur de sorte que tous les entiers vi pairs soient placs en t^te et e e e tous les vi impairs en queue, lordre relatif des lments tant conserv a lintrieur ee e e e de chaque groupe. Par exemple si : v = [|3; 1; 4; 1; 5; 9; 2; 6|] alors on souhaite obtenir aprs transformations : e v = [|4; 2; 6; 3; 1; 1; 5; 9|]. Il est autoris pour ce faire dutiliser un vecteur auxiliaire w de longueur n. e a) Donner un algorithme en franais eectuant la transformation demande. On c e dmontrera que cet algorithme rpond eectivement au problme pos. e e e e b) Ecrire une fonction caml permute : int vect -> unit implmentant cet algoe rithme. c) On appelle transfert une opration v.(i) <- qqch ou w.(j) <- qqch. Calculer e le nombre de transferts eectus par votre programme en fonction des nombres e a et b dentiers pairs et impairs dans v. d) On gnralise le problme en ajoutant a permute un paramtre p entier naturel e e e e de sorte que lappel permute p v place en t^te de v les lments dont le bit p e ee vaut 0 et en queue ceux dont le bit p vaut 1, lordre initial des entiers tant e conserv a lintrieur de chaque groupe. Indiquer quelles sont les modications e e a apporter a votre code donn en 2-b. e

Interpolation de Lagrange et multiplication rapide

159

Question 3 Soit v = [|v0; v1; .. .; vn1|] un vecteur a lments entiers naturels que lon veut ee trier par ordre croissant. On excute lalgorithme suivant : e . Calculer M = max(v0, v1, ..., vn1). . Dterminer un entier K tel que M < 2K. e . Pour p = 0, 1, ..., K 1 faire permute p v n pour a) Excuter cet algorithme sur le vecteur v = [|3; 1; 4; 1; 5; 9; 2; 6|]. On indiquera e les valeurs de M, K, et la valeur de v a la n de chaque itration de la boucle . e b) Traduire cet algorithme en caml. On rappelle que caml dispose dune fonction max : int -> int -> int qui retourne le plus grand de ses deux arguments. Il ny a pas dlvation a la puissance dans les entiers et il est interdit ee dutiliser celle des ottants. c) Montrer qu la n de chaque itration de la boucle la proprit suivante est a e ee vrie : e e la suite (v0 mod 2p+1 , v1 mod 2p+1 , ..., vn1 mod 2p+1 ) est croissante. En dduire que le vecteur v est tri par ordre croissant a la n de lalgorithme. e e d) On suppose que tous les entiers vi sont compris entre 0 et 230 1 (taille maximale dun entier caml sur une machine 32 bits). Quelle est la complexit e asymptotique de cet algorithme de tri compte en nombre de transferts efe fectus ? e

Interpolation de Lagrange et multiplication rapide


Soient n N , P(x) = a0 + a1 x + a2x2 + .. . + an1 xn1 un polyn^me a o coecients complexes de degr strictement infrieur a n et X = (x0 , x1, .. ., xn1) e e une suite de complexes deux a deux distincts. La liste des valeurs de P aux points xi est la suite note Y = P{X} = (P(x0 ), . .., P(xn1)). On tudie dans ce problme e e e des algorithmes permettant de calculer P{X} a partir de P et X, et des algorithmes permettant de calculer P a partir de X et P{X}. Les algorithmes pourront ^tre crits en franais ou en caml. On supposera e e c que le langage caml dispose dun type de donnes complexe reprsentant les nome e bres complexes et des oprations arithmtiques usuelles sur les complexes notes e e e +:, -:, *: et /:, ainsi que de fonctions de conversion :

160 complexe_of_floats : (a, b) a + ib floats_of_complexe : a + ib (a, b).

Problmes e

Les polyn^mes et les suites de valeurs seront reprsents par des vecteurs o e e caml a lments complexes : ee Le vecteur reprsentant P est p = [| a0 ; a1; . . .; an1 |] ; e Le vecteur reprsentant X est x = [| x0; x1; . ..; xn1 |] ; e Le vecteur reprsentant P{X} est y = [| P(x0 ); P(x1); . ..; P(xn1) |]. e Question 1 Ecrire un algorithme calculant la valeur P(z) pour un polyn^me P et un como plexe z donns. On prouvera la validit de cet algorithme et on donnera son e e temps dexcution mesur en nombre doprations complexes en fonction de la e e e longueur n de P. Question 2 Ecrire un algorithme calculant Y = P{X} en fonction du polyn^me P et de la suite o de points X. Il est suppos que P et X ont m^me longueur n. Donner la complexit e e e de cet algorithme en fonction de n (en nombre doprations complexes). e Question 3 Etant donn deux suites X = (x0 , .. ., xn1) et Y = (y0, . .., yn1) de n complexes, e les xi tant distincts, il existe un unique polyn^me P de degr infrieur ou gal a e o e e e n 1 tel que P{X} = Y. Ce polyn^me peut ^tre calcul par lune des relations : o e e
n1

a) Formule de Lagrange : P(x) =


i=0

yiLi (x) avec Li (x) =


0 j<n j=i

x xj xi x j .

b) Formule de Newton : P(x) = Q(x) +

yn1 Q(xn1) U(x) U(xn1)

o Q est le polyn^me dni par deg(Q) n2, Q{x0 , .. ., xn2} = (y0 , .. ., yn2) u o e et U(x) = (x x0)(x x1 ).. .(x xn2). c) Formule dAitken : P(x) = x x0 x xn1 P0,n2(x) + P1,n1(x) x0 xn1 xn1 x0

o Pa,b est le polyn^me de degr infrieur ou gal a b a tel que : u o e e e Pa,b {xa, . .., xb } = (ya , .. ., yb). Il nest pas demand la dmonstration de ces formules. Ecrire les algorithmes e e correspondant a ces formules et dterminer leur complexit asymptotique en fonc e e tion de n en nombre doprations complexes. On pourra utiliser si ncessaire des e e fonctions auxiliaires calculant la somme de deux polyn^mes et le produit dun o polyn^me par un polyn^me de degr 1, en indiquant a part le code de ces fonco o e tions et leur complexit. Aucun des algorithmes prsents ne doit conduire a e e e calculer plusieurs fois le m^me polyn^me. e o

Plus longue sous-squence commune e

161

Question 4 On suppose dans cette question que n est une puissance de 2 : n = 2 , et que X est la suite des racines n-mes de 1 dans C : xk = e2ik/n. Soient Y = (y0 , .. ., yn1) e une suite de n complexes quelconques et P le polyn^me de degr strictement o e infrieur a n dni par P{X} = Y. On note Y0 et Y1 les sous-suites paire et e e impaire associes a Y : Y0 = (y0, y2, y4, . .., yn2), Y1 = (y1, y3, y5, . . ., yn1), e X0 la sous-suite paire associe a X et P0, P1 les polyn^mes de degrs strictement e o e infrieurs a n/2 dnis par P0{X0} = Y0 et P1 {X0} = Y1 . e e a) Montrer que P(x) = 1 + xn/2 1 xn/2 P0 (x) + P1(xe2i/n). 2 2

b) En dduire un algorithme rcursif permettant de calculer P en fonction de Y. e e c) Montrer que le temps dexcution de cet algorithme (en nombre doprations e e complexes) est O(n ln(n)) (on rappelle que n est de la forme 2 ). d) Montrer de m^me que lon peut calculer la suite Y = P{X} a partir de P selon e la stratgie ( diviser pour rgner ) en O(n ln(n)) oprations. e e e ( ) Question 5 Soient P, Q deux polyn^mes a coecients complexes de degrs strictement info e e rieurs a n = 21 . En utilisant la question prcdente, montrer que lon peut e e calculer les coecients du polyn^me PQ en O(n ln(n)) oprations. Expliquer o e lintr^t de ce rsultat. ee e

Plus longue sous-squence commune e


Dnitions e { Soit A = (a0 , .. ., an1) une liste de n lments. On appelle : sous-squence ee e de A toute liste obtenue en retirant un nombre quelconque, ventuellement nul, e dlments a A et en conservant lordre relatif des lments restants. Par exemple, ee ee si A = (3, 1, 4, 1, 5, 9) alors les listes A, (1, 1, 5) et () (la liste vide) sont des soussquences de A, tandis que la liste (5, 1, 9) nen est pas une. e { Soient A = (a0 , . .., an1) et B = (b0 , .. ., bp1 ) deux listes. On appelle : soussquence commune a A et B toute liste C = (c0 , . .., cq1) qui est a la fois une e sous-squence de A et de B. Une plus longue sous-squence commune a A et e e B (en abrg plsc(A, B)) est une sous-squence commune de longueur maximale. e e e La longueur dune plsc(A, B) est note lc(A, B). Remarquer que A et B peuvent e avoir plusieurs plsc, mais quelles ont toutes m^me longueur. e

162

Problmes e

Lobjet du problme est ltude dalgorithmes permettant de calculer la e e longueur lc(A, B), et de trouver une plsc(A, B). Ce problme a des applicae tions pratiques entre autres dans les domaines suivants : { Biologie molculaire : dterminer si deux cha^ e e nes dADN dirent ( notablee ( ment ) , et sinon, identier les dirences. e ) { Correction orthographique : dceler les fautes dorthographe dans un mot ine correct par comparaison avec les mots ( voisins ) gurant dans un dictionnaire. ( ) { Mise a jour de chiers : A et B sont deux versions successives dun chier informatique ayant subi ( peu ) de modications. Soit C une plsc(A, B). Pour ( ) diuser B auprs des dtenteurs de A, il sut de transmettre les listes des lments e e ee de A et de B ne gurant pas dans C, ce qui est gnralement plus conomique que e e e de transmettre B en totalit. e Les algorithmes pourront ^tre crits en franais ou en caml. Les calculs e e c de complexit seront faits en supposant que les oprations lmentaires sur les e e ee lments dune liste (recopie dans une variable, comparaison de deux lments) ee ee ont un temps dexcution constant. Les rsultats seront donns sous forme asympe e e totique par rapport aux longueurs des listes traites. e Question 1 : reconnaissance dune sous-squence e On dispose de deux listes A = (a0 , .. ., an1) et C = (c0 , . .., cq1). a) Ecrire un algorithme permettant de savoir si C est ou non une sous-squence e de A. La validit de cet algorithme devra ^tre justie. e e e b) En supposant que C est bien une sous-squence de A, crire un algorithme e e calculant une liste I des indices des lments de A a supprimer pour obtenir C. ee Lorsquil existe plusieurs listes I solution, une seule doit ^tre retourne. e e c) Excuter les algorithmes prcdents sur lexemple : e e e A = (3, 1, 4, 1, 5, 9), C = (1, 5, 9).

Question 2 : calcul de lc(A, B) On dispose des listes A = (a0 , . .., an1) et B = (b0 , . .., bp1 ). Pour 0 i n et 0 j p on note Ai = (a0 , .. ., ai1), Bj = (b0 , .. ., bj1) et i,j = lc(Ai , Bj) avec la convention : A0 = B0 = (). a) Dmontrer pour i [[1, n]] et j [[1, p]] : e
i,j

1 + i1,j1 max( i1,j,

i,j1 )

si ai1 = bj1 ; sinon.

b) En dduire un algorithme ecace calculant la matrice L = ( i,j)0 i n, 0 j p. e On prouvera la validit de cet algorithme et on donnera sa complexit asympe e totique par rapport a n et p. Les listes A, B seront reprsentes au choix par e e des listes cha^ ees ou par des vecteurs. n

Arbres de priorit quilibrs ee e

163

c) Ecrire un algorithme permettant, a partir des listes A, B et de la matrice L de calculer une plsc(A, B). d) Excuter les algorithmes prcdents sur lexemple : e e e A = (p, i, o, l, e, t), B = (p, l, i, e, r).

Question 3 : pr-traitement de A et B e Pour acclrer le calcul dune plsc(A, B), on supprime de A tous les lments ee ee ne gurant pas dans B et on supprime de B tous ceux ne gurant pas dans A. En notant A , B les listes obtenues, toute plsc(A, B) est une plsc(A , B ) et rciproquement. e a) Ici on suppose que les lments de A et B appartiennent a un ensemble E de ee cardinal susamment petit pour quil soit envisageable de crer en mmoire e e des listes ou des vecteurs de longueur card(E). Ceci est le cas si A et B sont des listes de caractres ; E est alors lensemble de tous les caractres reprsentables e e e en machine, de cardinal 256 (sur les machines courantes). Ecrire un algorithme ecace calculant les listes A et B a partir de A et B. b) Ici on suppose que les lments de A et B appartiennent a un ensemble E trop ee gros pour tenir en mmoire, mais muni dune relation dordre total note . e e Ceci est le cas si A et B sont des listes dentiers avec E = [[109, 109]]. On suppose avoir tri A et B, cest--dire calcul des listes At = ((0), . .., (n 1)) e a e et Bt = ((0), .. ., (p 1)) o et sont des permutations de [[0, n 1]] et u [[0, p 1]] telles que les listes (a(0) , . .., a(n1)) et (b(0), . . ., b(p1)) sont croissantes. Ecrire un algorithme calculant A et B a partir de A, B, At, Bt . Question 4 Dterminer la complexit asymptotique du pr-traitement selon a ou b. Pour b, e e e la complexit du tri devra ^tre prise en compte : il nest pas demand dcrire un e e e e algorithme de tri, vous pouvez citer un algorithme vu en cours. Est-il raisonnable deectuer un pr-traitement (la rponse devra ^tre argumente) ? e e e e

Arbres de priorit quilibrs ee e

Etant donn un arbre binaire a, on note N(a) le nombre de nuds de a et e H(a) la hauteur de a. On pose par convention : N() = 0, H() = 1.

164

Problmes e

Soit a un arbre binaire dont les tiquettes appartiennent a un ensemble toe talement ordonn. On dit que a est un arbre de priorit quilibr (APE) sil e e e e vrie pour tout nud n a : e 1. ltiquette de n est suprieure ou gale a celles de ses ls sil en a ; e e e 2. si g et d dsignent les branches gauche et droite issues de n alors : e N(g) 1 N(d) N(g).

Par convention un arbre vide est un APE. Ce type darbre intervient dans les problmes de les dattente avec priorit o lon doit eectuer plusieurs t^ches e e u a selon un ordre de priorit. Si chaque t^che est reprsente par un nud dun e a e e APE tiquet par la priorit de la t^che, alors la t^che reprsente par la racine e e e a a e e de larbre est lune des t^ches les plus prioritaires. La condition 2. signie que a les autres t^ches sont rparties quitablement entre les branches gauche et droite, a e e la branche gauche tant ( plus lourde dun nud ) en cas dingalit. On tudie e e e e ( ) dans ce problme les oprations suivantes : e e 1. insertion dune nouvelle t^che ayant une certaine priorit ; a e 2. extraction dune t^che prioritaire (celle associe a la racine) et reconstitua e tion dun APE avec les t^ches restantes. a Les APE seront reprsents en caml par des arbres binaires ordinaires suivant e e la dclaration : e
type a arbre = B_vide | B_noeud of a * (a arbre) * (a arbre);;

o a est le type ordonn reprsentant les t^ches avec leur priorit. u e e a e


B_vide reprsente un APE vide ; e B_noeud(e, g, d) reprsente un APE dont la racine porte ltiquette e et dont e e

les branches gauche et droite sont g et d. On supposera que deux tiquettes peuvent ^tre compares par les oprateurs usuels e e e e
<, <=, > et >=.

Question 1 Soit a un APE non vide. Montrer que H(a) = log2 (N(a)) . Question 2 : insertion Ecrire une fonction insertion telle que si a dsigne un APE et e une tiquette e e alors insertion(a,e) renvoie un APE a contenant tous les nuds de a et un nud supplmentaire dtiquette e. On prouvera la correction de cette fonction, e e en particulier on prouvera que larbre a retourn est bien un APE, et on donnera e sa complexit temporelle. Excuter ( a la main ) votre fonction sur lexemple : e e ( )
5

a=
3

4 2 0

e = 2.

Arbres de priorit quilibrs ee e

165

Question 3 : modication de racine Soit a = B noeud(r, g, d) un APE non vide et e une tiquette. On souhaite e supprimer ltiquette r et insrer ltiquette e pour obtenir un nouvel APE, a . e e e Dans un premier temps on constitue larbre a1 = B noeud(e, g, d) qui nest pas en gnral un APE, et on transforme cet arbre en un APE a ayant les m^mes nuds. e e e Ecrire une fonction transforme qui constitue a a partir de a1 . On prouvera la correction de cette fonction et on donnera sa complexit temporelle en fonction e de N(a). Question 4 : extraction de la racine Soit a un APE dont on souhaite retirer la racine. On procde en deux temps : e 1. On supprime le nud le plus a gauche dans a et on permute les branches gauche et droite de chaque nud ascendant du nud supprim. Soient a e larbre obtenu et e ltiquette du nud supprim. e e 2. On remplace ltiquette r de la racine de a par e et on reconstitue un e APE, a , selon lalgorithme de la question prcdente. e e Exemple : a
5 4 3 2 0 1 0 1 2

a
5 4 0 1

a
4 3 2

a) Justier que larbre a obtenu en 1. est bien un APE. b) Ecrire le code de la fonction extraction qui retourne larbre a a partir de a. Donner la complexit temporelle de extraction en fonction de N(a). e Question 5 : utilisation des APE pour le tri Pour trier une liste [e0; e2; . . .; en1] dlments appartenant a un ensemble toee talement ordonn, on insre un a un ces lments dans un APE initialement vide e e ee puis on extrait par ordre de priorit dcroissante les lments de lAPE obtenu et e e ee on les insre dans une nouvelle liste initialement vide. Quelle est la complexit e e temporelle de cette mthode de tri ? e

166

Problmes e

Compilation dune expression


On considre une expression arithmtique constitue de constantes, de vae e e riables, doprateurs unaires (fonctions) et doprateurs binaires (addition, multie e plication, etc). La compilation dune telle formule consiste a transformer cette formule en une liste dinstructions, le code compil, dont lexcution par un proe e cesseur fournit la valeur de la formule. Les instructions a produire dpendent e du processeur excutant ; on supposera dans ce problme que ce processeur est e e constitu dune unit de calcul et dune pile oprationnelle dans laquelle sont e e e stocks les oprandes et les rsultats des calculs eectus par lunit de calcul. Les e e e e e instructions du processeur sont : { empiler une constante c, note empile_c c ; e { empiler la valeur dune variable v, note empile_v v ; e { eectuer une opration unaire op, note unaire op, loprande est le sommet e e e de la pile et lunit de calcul le remplace dans la pile par le rsultat de e e lopration ; e { eectuer une opration binaire op, note binaire op, les deux oprandes, e e e a et b sont pris au sommet de la pile (et retirs de la pile), b tant dpil le e e e e premier puis le rsultat, a op b, est plac au sommet de la pile restante. e e { eectuer une opration binaire op avec inversion des oprandes, note bie e e naire_inv op, identique a lopration prcdente a ceci prs que le rsultat e e e e e empil est b op a. e Par exemple la formule a/(b + c) peut ^tre compile de deux manires : e e e { empile_v a; empile_v b; empile_v c; binaire +; binaire /. { empile_v b; empile_v c; binaire +; empile_v a; binaire_inv /. Dans les deux cas la valeur de la formule est disponible a la n de lexcution e du programme au sommet de la pile. On remarque sur cet exemple que le deuxime e code nutilise que deux niveaux de pile pour valuer la formule tandis que le e premier en utilise trois. Le but de ce problme est de dterminer, pour une e e formule f quelconque, quel est le nombre N(f) minimal de niveaux de pile requis pour valuer cette formule, et de produire un code correspondant a cette utilisation e minimale de la pile. Question 1 Soit lexpression a + (b c) (d e). Combien y a-t-il de codes compils dirents e e correspondants ? Donner, en le justiant, un code utilisant le moins possible de niveaux de pile. Question 2 Dterminer une relation entre N(f) et N(g) o f et g sont deux formules telles que e u f = op1 (g), op1 dsignant un oprateur unaire. Dterminer de m^me une relation e e e e entre N(f), N(g) et N(h) lorsque f = g op2 h, op2 dsignant une opration e e binaire.

Recherche dune cha^ de caractres dans un texte ne e

167

Question 3 a) Dduire de la question prcdente un algorithme de compilation optimal dune e e e formule f. Cet algorithme sera donn en franais, puis cod en caml en e c e introduisant les dnitions de type adquates pour reprsenter les formules et e e e les codes compils. On ne cherchera pas a optimiser le temps de construction e du code, mais on vitera la rptition de calculs identiques. e e e b) Proposer une mthode permettant dviter les concatnations en queue de liste e e e dans la production du code. Le codage en caml de cette amlioration nest e pas demand. e Question 4 Si la pile oprationnelle dun processeur comporte 8 niveaux, quelle est la taille e minimale, compte en nombre de nuds, dune formule dont le calcul est impose sible ?

Recherche dune cha de ne caract`res dans un texte e


De nombreux problmes de traitement de texte ou de reconnaissance de e formes impliquent de dterminer si une cha^ de caractres gure dans un texte et e ne e si oui, de trouver la premire occurrence ou toutes les occurrences de la cha^ dans e ne le texte. Formellement, soit A un alphabet, m = a0 . ..a|m|1 et t = b0 . ..b|t|1 deux mots sur A ; on dit que m gure dans t sil existe un entier i tel que : a0 = b i , a1 = bi+1 , .. ., a|m|1 = bi+|m|1. ()

Un tel entier i est appel une position de m dans t. On tudie dans ce e e problme divers algorithmes de recherche de la premire position de m dans t e e quand elle existe. Dans les programmes, on pourra supposer que les lettres de A sont reprsentes par les entiers de [[0, |A|1]] o |A| est le cardinal de A. Les mots e e u m et t seront reprsents par des vecteurs. Les calculs de complexit seront faits e e e en supposant que |A| est constant et que |m| et |t| sont variables avec |m| = o(|t|). Enn, on supposera que |A| 2. Question 1 Le premier algorithme consiste a essayer successivement toutes les valeurs de i jusqu constater les galits () ou atteindre la n du texte t. a e e a) Ecrire une fonction caml implmentant cet algorithme. Donner sa complexit e e asymptotique dans le pire des cas en fonction de |m| et |t|.

168

Problmes e

b) On suppose dans cette question seulement que toutes les lettres de m sont direntes. Cette information permet-elle damliorer lalgorithme prcdent ? e e e e Si oui, donner la complexit de lalgorithme modi. e e c) Analyse en moyenne : on note (t, m) le nombre de comparaisons de lettres eectues par lalgorithme du 1-a pour tester () pour des valeurs donnes de e e t et m. En admettant que tous les mots m de longueur sont quiprobables, e le nombre moyen de comparaisons a t, xs est : e 1 (t, m) (t, ) = |A| |m|= o la somme porte sur tous les mots m de longueur . Montrer que lon a : u (t, ) |A| |t|. |A| 1

d) Majorer de m^me : ( , m) = e ~

1 (t, m) (nombre moyen de comparai|A| |t|= sons pour m x et t alatoire de longueur ). e e

Question 2 Le deuxime algorithme consiste a construire un automate dterministe complet e e Am reconnaissant le langage Lm = A m et a lui faire lire le texte t. Chaque passage par un tat nal de Am correspond a une occurrence de m dans t. e a) Exemple : A = {a, b, c} et m = aabaac. Construire un automate non dterministe reconnaissant Lm et en dduire un automate dterministe come e e plet reconnaissant le m^me langage. e b) Ecrire une fonction caml prenant en argument un automate Am (sous une forme a dnir) et le texte t et retournant la premire position de m dans t si e e elle existe et dclenchant une erreur dans le cas contraire. e Construction automatique de Am : Pour m, u A on note S(m, u) le plus long mot v qui soit a la fois un prxe e de m et un suxe de u (v = ventuellement). On construit Am de la manire e e suivante : { les tats de Am sont les prxes de m (il y a |m| + 1 prxes en comptant e e e et m) ; { si u est un prxe de m et a une lettre alors Am contient la transition e a u S(m, ua) ; { ltat initial de Am est et ltat nal m. e e c) Montrer que Am reconna^ eectivement Lm. t d) Soient u un prxe de m dirent de et u le mot obtenu en supprimant la e e premire lettre de u. Montrer que lon a pour toute lettre a : e S(m, ua) = ua S(m, S(m, u )a) si ua est un prxe de m, e sinon.

Recherche dune cha^ de caractres dans un texte ne e

169

e) On reprsente en machine un prxe a0 . ..ai1 de m par lentier i (0 reprsene e e tant ) et la fonction de transition de Am par une matrice M a |m| + 1 lignes et |A| colonnes telle que M.(i).(a) = j reprsente la transition : e a0 .. .ai1 a0 .. .aj1 (les lettres de A sont supposes ^tre reprsentes par des nombres entiers). e e e e Dduire de la question prcdente un algorithme ecace de calcul de M a e e e partir de m et A. Dterminer sa complexit asymptotique en fonction de |m|. e e Excuter votre algorithme sur le mot m = aabaac. e f ) Montrer que lautomate Am construit par la mthode prcdente est optimal, e e e cest--dire quil nexiste pas dautomate dterministe complet a moins de a e |m| + 1 tats reconnaissant Lm . e Question 3 Cet algorithme est une variante du premier algorithme : on teste les positions i ventuelles par valeurs croissantes, mais les tests de () sont eectus de droite a e e gauche, cest--dire quon eectue dans cet ordre les comparaisons : a a|m|1 = bi+|m|1, . . ., a1 = bi+1 , a0 = b i . ( )
a

En cas dchec, soit ak = bi+k la premire dirence constate et akp la e e e e dernire occurrence de la lettre bi+k dans m avant la position k (par convention, e k p = 1 si bi+k ne gure pas dans m avant la position k). On remplace alors i par i + p et on reprend les tests ( ). a) Excuter cet algorithme avec m = aabaac et t = abaabaababcbac. e b) Justier la validit de lalgorithme et donner sa complexit asymptotique dans e e le pire des cas en fonction de |m| et |t|. c) Programmer cet algorithme. On dnira les structures de donnes et fonctions e e auxiliaires ncessaires. e d) Peut-on exploiter simultanment les ides des algorithmes 2 et 3 ? e e

Travaux pratiques

Chemins dans Z2

171

Chemins dans Z2

On appelle ( chemin dans Z2 ) toute suite ` = (A0, . . ., An) de points du plan ( ) a coordonnes entires telle que lon passe de chaque point au suivant par une e e translation dont le vecteur appartient a lensemble : {N = (0, 1), S = (0, 1), E = (1, 0), W = (1, 0)} (Nord, Sud, Est et West).

Le mot de ` est la suite des vecteurs joignant deux points successifs : = (A0 A1, A1A2 , . .., An1An ). On dit que : { ` a des points multiples sil existe i, j distincts tels que Ai = Aj ; { ` est ferm si A0 = An ; e { ` est ferm simple si A0 = An et si les points A0, A1 ,.. . , An1 sont e distincts. Lobjet de ce TP est dtudier quelques algorithmes sur les chemins : dire e si un chemin comporte des points multiples, supprimer les boucles ventuelles en e conservant les extrmits dun chemin, remplir la surface du plan dlimite par un e e e e chemin ferm simple. Un chemin ` sera reprsent en caml soit par la liste des e e e points (couples dentiers) soit par le mot associ, le point initial tant pris par e e convention gal a (0, 0). On utilisera les fonctions de la bibliothque graphics et e e les fonctions random_chemins, dessine et noircit listes en annexe pour visualiser e les chemins tudis. e e 1. Conversion mot liste de points Ecrire une fonction points : (int*int) -> direction list -> (int*int) list qui calcule les points dun chemin dont lorigine et le mot sont passs en arguments. e Tirer des mots de chemins au hasard et les faire acher (eacer la fen^tre graphique e entre deux tracs). e 2. Dtection et limination des boucles e e a) Ecrire une fonction multiples : (int * int) list -> bool qui teste si un chemin contient des points multiples. On utilisera la fonction caml mem : a -> a list -> bool qui dit si une liste contient un lment donn en premier ee e argument. b) Pour supprimer les boucles dans le chemin ` = (A0 , . .., An) on utilise lalgorithme suivant :

172

Travaux pratiques

1. Constituer la liste de couples = ((A1 , A0), (A2, A1), ..., (An, An1)). Cette liste sera utilise comme ( table de prdcesseurs ) gr^ce a la fonce e e ( ) a tion standard assoc : assoc M renvoie pour un point M le premier point N tel que le couple (M, N) appartient a , cest--dire le premier a prdcesseur de M dans ` (si M na pas de prdcesseur, assoc dclenche e e e e e une erreur). 2. Constituer de proche en proche le chemin sans boucle ` = (A0 , ..., Ap) associ a ` a laide des relations : e Ap = A n , Ai = premier prdcesseur(Ai+1 ), e e A0 = A0 .

Programmer cet algorithme. On crira une fonction : e


sans_boucle : (int*int) list -> (int*int) list

qui calcule ` a partir de `. Remarque : la complexit asymptotique de sans_boucle est O(n2 ) car le e temps dune recherche eectue par assoc est linaire en la taille de la liste e e dassociation. On pourrait amliorer cette complexit en utilisant une struce e ture de donnes plus ecace quune liste dassociation, par exemple une table e de hachage ou un arbre binaire de recherche. La fonction suivante retourne un chemin ferm simple alatoire dau e e moins n segments :
let rec random_boucle(n) = let ch = random_chemin (n,n,n,n-1) in let pt = sans_boucle(points (0,0) ch) in if list_length(pt) >= n then pt @ [(0,0)] else random_boucle(n) ;;

On tire un chemin non ferm au hasard, on limine les boucles et on le ferme e e avec un segment supplmentaire. Si le chemin obtenu est trop court alors on e recommence (cela peut boucler indniment mais la thorie des probabilits e e e montre que cette ventualit a une probabilit nulle ; en pratique si n nest e e e pas trop grand on obtient un chemin convenable assez rapidement).

3. Remplissage Soit ` un chemin ferm simple ; on veut ( noircir ) la rgion borne dlimite par e e e e ( ) e ` (en fait la remplir avec la dernire couleur slectionne par set_color). Voici un e e e algorithme possible pour ce faire : 1. Dterminer les ordonnes minimale et maximale, y1 et y2, des points e e de `.

Chemins dans Z2

173

2. Pour y = y1, y1 + 1, ... , y2 1 faire : 2.1. Dterminer les abscisses (xi ) des segments verticaux de ` coupant e 1 la droite horizontale dordonne y+ 2 et classer ces abscisses par valeurs e croissantes. On obtient une liste (x0 , x1, ..., x2n1). 2.2 Noircir tous les rectangles [x2i, x2i+1] [y, y + 1]. n pour On se convaincra intuitivement que le nombre dabscisses trouves est force e ment pair et que les zones noircies sont les bonnes. Programmer cet algorithme. Le tri dune liste dentiers est obtenu par lexpression : sort__sort (prefix <=) . 4. Annexe : fonctions fournies. On entrera les dnitions suivantes : e
#open "graphics";; open_graph "";; type direction = N | S | E | W;; (* +--------------------+ | Chemin alatoire | e +--------------------+ *) (* chemin comportant n fois N, s fois S, e fois E et w fois W *) let rec random_chemin (n,s,e,w) = let t = n+s+e+w in if t = 0 then [] else begin let x = random__int(t) in if x < n then N :: random_chemin(n-1,s,e,w) else if x-n < s then S :: random_chemin(n,s-1,e,w) else if x-n-s < e then E :: random_chemin(n,s,e-1,w) else W :: random_chemin(n,s,e,w-1) end ;; (* +-------------+ | Affichage | +-------------+ *) let pas = 20 and rayon1 = 5 and rayon2 = 3;; let dessine points = (* origine = centre de la fen^tre *) e let x0 = size_x()/2 and y0 = size_y()/2 in let (a,b) = match points with | [] -> (x0,y0) | (x,y)::suite -> (x0 + x*pas, y0 + y*pas) in moveto a b; fill_circle a b rayon1;

174

Travaux pratiques (* trac des segments et des points *) e let rec trace = function | [] -> () | (x,y)::suite -> let r = if suite = [] then rayon1 else rayon2 in fill_circle (x0 + x*pas) (y0 + y*pas) r; lineto (x0 + x*pas) (y0 + y*pas); trace(suite) in trace(points) ;; (* noircit un rectangle de diagonale [(x1,y1),(x2,y2)] *) let noircit (x1,y1) (x2,y2) = let x0 = size_x()/2 and y0 = size_y()/2 in let x3 = min x1 x2 and y3 = min y1 y2 in let dx = (max x1 x2) - x3 and dy = (max y1 y2) - y3 in fill_rect (x0 + x3*pas) (y0 + y3*pas) (dx*pas) (dy*pas) ;;

Le r^le de #open "graphics" est de rendre accessibles les fonctions graphiques (elles o sont charges en mmoire lorsquon lance camlgraph mais leurs noms courts ne sont e e connus de linterprteur quaprs ce #open "graphics"). e e random_chemin tire au hasard un mot de chemin, , comportant n fois Nord, s fois Sud, e fois Est et w fois West. On obtient un mot de chemin ferm si (et e seulement si) n = s et e = w. dessine trace dans la fen^tre graphique un chemin ` (liste de points) pass en e e argument. Les quantits pas, rayon1 et rayon2 dterminent lunit dchelle et la e e e e taille des disques matrialisant les points du chemin. e noircit trace un rectangle dont on donne deux sommets opposs en tenant compte e du facteur dchelle pas. e

Files dattente et suite de Hamming

1. Implmentation des les dattente e Une le dattente est liste dont on limite lusage aux oprations suivantes : e { la liste est-elle vide ? { extraire la t^te de la liste ; e { ajouter un lment en queue de liste. ee On rencontre souvent des les dattente dans la vie courante, par exemple a la caisse dun supermarch ou a un feu rouge. En informatique une le dattente e

Files dattente et suite de Hamming

175

permet de stocker des informations qui ne peuvent ^tre traites de suite, mais qui e e devront l^tre en respectant leur ordre darrive dans la le (structure de donnes e e e FIFO : rst in, rst out). On peut raliser ces oprations avec le type liste cha^ ee fourni en standard e e n par caml, mais lopration ( insertion en queue ) a une mauvaise complexit sur e e ( ) ce type de listes, aussi utilise-t-on des structures de donnes mieux adaptes aux e e fonctionnalits des les dattente. Dans ce TP on implmentera une le dattente e e par un couple de listes cha^ ees : lavant de la le, classe par ordre darrive et n e e larrire, classe par ordre inverse darrive. e e e Les nouveaux arrivants seront placs en t^te de la liste arrire, les e e e premiers arrivs seront extraits en e t^te de la liste avant. Lorsque la e liste avant est puise on retourne e e la liste arrire, on la place a lavant e et on rinitialise la liste arrire a []. e e Cette opration de retournement a e une complexit linaire en la taille e e de la liste arrire, donc le temps dexe traction du premier lment dune ee le ainsi implmente nest pas conse e tant, mais comme un lment de la ee le nest retourn quune seule fois, e le temps cumul de n extractions en e t^te de la le est linaire en n. e e

arrire e

13 12 11 10 9 8 7 6

1 2 3 4 5

avant

type a file = { mutable avant : a list; mutable arri`re : a list e };;

Dans la dclaration ci-dessus les champs avant et arri`re sont dclars mutae e e e bles de faon a pouvoir ^tre modis sur place. Si f est une variable de type a file c e e alors on modie sa liste avant par une instruction de la forme : f.avant <- qqch. Recopier la dnition du type a file et programmer les fonctions suivantes : e
nouv_file: est_vide : longueur : ajoute : retire : unit -> a file a file a file a file a -> -> -> -> file bool int a -> unit a

premier : a file -> a

cre une le initialement vide ; e dit si une le est vide ; renvoie la longueur de la le ; ajoute un lment en queue de la le ; ee retire le premier lment de la le ee et le renvoie ; renvoie le premier lment de la le ee sans le retirer.

Les fonctions premier et retire dclencheront des erreurs appropries si la le e e passe en argument est vide. e 2. La suite de Hamming Un entier de Hamming est un entier naturel non nul dont les seuls facteurs premiers ventuels sont 2, 3, 5. Le problme de Hamming consiste a numrer les n e e e e premiers entiers de Hamming par ordre croissant. Pour cela on remarque que le

176

Travaux pratiques

premier entier de Hamming est 1 et que tout autre entier de Hamming est le double, le triple ou le quintuple dun entier de Hamming plus petit (ces cas ntant e pas exclusifs). Il sut donc dutiliser trois les dattente, h2, h3 et h5 contenant initialement le seul nombre 1 puis dappliquer lalgorithme : dterminer le plus petit des trois nombres en t^te des les dattente, e e soit x. Imprimer x, le retirer de chacune des les le contenant et insrer e en queue de h2, h3 et h5 respectivement 2x, 3x et 5x. a) Programmer cet algorithme et faire acher les n premiers entiers de Hamming. Observer lvolution des les dattente a chaque tape. e e b) Lalgorithme prcdent est trs dispendieux car il place la plupart des entiers e e e de Hamming dans les trois les alors quune seule surait. En eet, si x est un entier de Hamming divisible a la fois par 2, 3 et 5 alors x a t plac dans h 2 ee e au moment o lon extrayait x/2, dans h3 au moment o lon extrayait x/3 et u u dans h5 au moment o lon extrait x/5. Modier votre programme de sorte u quun m^me entier de Hamming ne soit insr que dans une seule des les e ee dattente. c) Les entiers caml sont limits a un milliard environ ce qui ne permet pas daller e trs loin dans la suite de Hamming. Pour pouvoir traiter des grands nombres e on convient de reprsenter un entier de Hamming x par le triplet (a, b, c) tel e que x = 2a 3b 5c. Reprendre votre programme avec cette convention et calculer le millionime entier de Hamming. Pour comparer deux entiers de Hamming e x et y connus par leurs exposants il sut de comparer les rels ln x et ln y e (ln est not log en caml). On admettra que la prcision des calculs sur les e e ottants est susante pour ne pas induire de comparaison errone. e d) Dterminer exprimentalement la complexit mmoire de lalgorithme de ree e e e cherche du n-me nombre de Hamming. Cette complexit sera mesure par e e e la somme des longueurs des trois les h2 , h3 et h5 . Pour cela on relvera les e valeurs de pour n = 1000, n = 2000, n = 4000 etc, et on conjecturera une relation simple entre et n.

Recherche de contradictions par la mthode des consensus e


1. Prsentation e Soient p1 , . . ., pn des variables boolennes. On appelle : e { littraux les propositions pi et leurs complmentaires pi ; e e { clause toute disjonction de littraux, par exemple p1 + p2 + p3 ; e { systme de clauses toute famille nie de clauses. e

Recherche de contradictions par la mthode des consensus e

177

La clause c est dite triviale sil existe une variable p telle que p et p apparaissent dans c. Dans ce cas la valeur de vrit de c est vraie quelles que soient les e e valeurs de vrit des pi . La clause Faux est la clause constitue daucun littral, e e e e sa valeur de vrit est fausse quelles que soient les valeurs des variables p i . Dans ce e e TP on ne considrera que des clauses non triviales. Ces clauses seront reprsentes e e e par un couple de deux listes : la liste des variables apparaissant positivement dans c (p1 et p2 dans lexemple prcdent) et la liste des variables apparaissant e e ngativement (p3 dans lexemple prcdent). Pour une clause non triviale ces e e e listes sont donc disjointes, et elles sont toutes deux vides pour la clause Faux et pour elle seulement. Un systme de clauses est dit contradictoire si la conjonction de toutes les e clauses du systme est gale a la clause Faux. Par exemple le systme : e e e {c + d, c + m, d + m, m} est contradictoire comme on peut sen rendre compte en dveloppant a la main le e produit : (c + d)(c + m)(d + m)m = c c d m + c c m m + c m d m + c m m m + d c d m + d c m m + d m d m + d m m m. Cette mthode de dveloppement complet nest pas praticable lorsque n est grand : e e la longueur dune clause non triviale peut atteindre n, et il y a 2n clauses de longueur n ; le produit de toutes ces clauses comporte donc dans sa forme dvelope n pe n2 termes. .. On peut aussi se rendre compte quun systme est contradictoire e e en calculant la table de vrit de la conjonction des clauses, mais pour n variables e e boolennes il y a quand m^me 2n valeurs de vrit a calculer. Lobjectif de ce e e e e TP est dtudier un autre algorithme de reconnaissance de contradictions, appel e e mthode des consensus, qui permet de dterminer si un systme est contradictoire e e e en gnral plus ecacement quen calculant le produit de toutes les clauses du e e systme ou en cherchant la table de vrit de leur conjonction. e e e Si c et c sont deux clauses, on dit que c implique c si tout littral ape paraissant dans c appara^ aussi dans c . Ceci correspond a la notion usuelle t dimplication : c = c si et seulement si tout choix des variables rendant c vraie rend aussi c vraie. Par convention la clause Faux implique toutes les autres. Dans un systme S, une clause c S est dite minimale sil nexiste pas de e clause c S \ {c} telle que c = c. Si c et c sont deux clauses telles quil existe une variable p apparaissant positivement dans une clause et ngativement dans lautre, par exemple c = p+c1 e et c = p + c1 (c1 et c1 ne contenant ni p ni p), on appelle consensus des clauses c et c la clause c = c1 + c1 . c a la proprit d^tre vraie chaque fois que c ee e et c le sont, et cest la plus petite clause pour lordre dimplication parmi les clauses indpendantes de p ayant cette proprit (cest--dire si d est une clause e ee a indpendante de p, on a cc = d si et seulement si c = d). Sil existe une autre e variable q apparaissant positivement dans lune des clauses c, c et ngativement e

178

Travaux pratiques

dans lautre alors c1 + c1 contient q + q donc est la clause triviale. Ceci montre quil existe trois cas possibles pour deux clauses c et c : { ou bien elle nont pas de consensus (aucune variable nappara^ positivement t dans une clause et ngativement dans lautre) ; e { ou bien elles ont un unique consensus ; { ou bien elles ont plusieurs consensus mais alors ils sont tous triviaux. Soit S un systme de clauses. On dtermine si S est contradictoire de la e e manire suivante : e 1. simplier S en retirant toutes les clauses non minimales ; 2. former tous les consensus non triviaux entre deux clauses de S et les ajouter a S ; 3. recommencer les tapes 1 et 2 tant que lon obtient en sortie de 2 un e systme dirent de celui en entre de 1 ; e e e 4. le systme dorigine est contradictoire si et seulement si le systme e e nal est rduit a {Faux }. e La terminaison de cet algorithme est immdiate (il ny a quun nombre ni de e systmes de clauses pour un ensemble de variables donn), sa correction lest e e moins, ce pourrait ^tre un trs bon sujet de problme. e e e Exemple : quand ils ont un devoir, les lves apprennent leur cours. Sils ont ee appris leur cours, ils nont pas de mauvaises notes. Sils nont pas de devoir, ils nont pas non plus de mauvaise notes. Montrer que les lves nont jamais ee de mauvaises notes. On modlise ce problme avec trois variables boolennes : d = ( avoir un e e e ( devoir ) ; m = ( avoir une mauvaise note ) ; c = ( apprendre son cours ) ; et on ) ( ) ( ) dispose des hypothses : e h1 (d = c c + d), h2 (c = m c + m), h3 (d = m d + m).

Il sagit de montrer que h1 h2 h3 = m cest--dire que le systme : a e S = {c + d, c + m, d + m, m} est contradictoire. En droulant a la main lalgorithme des consensus on obtient e successivement : 1. 2. 1. 2. 1. 2. 1. 2. S = {c + d, c + m, d + m, S = {c + d, c + m, d + m, S = {c + d, S = {c + d, S={ S={ S = {Faux} S = {Faux} m} m, d + m, c + m, c, d} m, d + m, c + m, c, d} m, d + m, c + m, c, d, d, c, m} m, c, d, d, c, m} m, c, d, d, c, m, Faux}

Recherche de contradictions par la mthode des consensus e

179

Dans cet exemple on aurait aussi pu partir du systme S = {c + d, c + m, d + m} e et le ( simplier ) par lalgorithme des consensus, on obtient en sortie un systme e ( ) contenant m ce qui sut a prouver h1 h2 h3 = m. 2. Types de donnes et fonctions fournies e Les variables boolennes seront reprsentes par des cha^ e e e nes de caractres, les e clauses par des couples de listes de cha^ nes de caractres et les systmes de clauses e e par des listes de tels couples :
(* v. positives, v. ngatives *) e type clause == (string list) * (string list);; type systeme == clause list;; (* affichage dune clause s *) let rec concat sep liste = match liste with | [] -> "" | [x] -> x | x::suite -> x^sep^(concat sep suite);; let string_of_clause(p,n) = (if n = [] then "" else (concat "." n)^" => ") ^ (if p = [] then "Faux" else concat "+" p);; let print_clause(c) = format__print_string(string_of_clause c);; install_printer "print_clause";; (* construction let prefix => and prefix =>~ and prefix ~=> and prefix ~=>~ ;; de clauses *) a b = ([b], [a]) a b = ([], [a;b]) a b = ([a;b],[]) a b = ([a], [b])

(* (* (* (*

a => b a => non b non a => b non a => non b

*) *) *) *)

La fonction print_clause ache une clause c sous la forme c1 = c2 o u c1 est la conjonction des variables ngatives de c et c2 la disjonction des vae riables positives de c (de fait, (p + q + r + s) (p.q = r + s)). Le r^le de o linstruction install_printer "print_clause" est dindiquer au systme quil doit e dornavant utiliser cette fonction a chaque fois quil doit acher une clause. Les e fonctions =>, ~=>, =>~ et ~=>~ permettent de saisir des clauses sous une forme presque mathmatique, on crira : e e
let s = ["d" => "c"; "c" =>~ "m"; "d" ~=>~ "m"];;

pour dsigner le systme S = {h1, h2, h3} prsent en exemple. En rponse, le e e e e e systme interactif ache : e
s : (string list * string list) list = [d => c; c.m => Faux; m => d]

180

Travaux pratiques

conformment au code de print_clause. On pourra par ailleurs utiliser les fonce tions a caractre ensembliste faisant partie de la bibliothque standard de caml : e e union, intersect, subtract, mem et except. 3. Programmation de ltape 1 e Ecrire les fonctions suivantes :
implique present ajoute simplifie : : : : clause clause clause clause -> -> -> -> clause systeme systeme systeme -> -> -> -> bool bool systeme systeme

{ implique c c dit si c = c . { present c s dit sil existe une clause c dans s telle que c = c. { ajoute c s retourne un systme s quivalent au systme s {c} en retirant de e e e s {c} toutes les clauses c = c telles que c = c . De la sorte, si lon part dun systme s ne contenant que des clauses minimales, le systme s retourn a aussi e e e cette proprit. ee { simplifie s retourne un systme s quivalent a s et ne contenant que des clauses e e minimales. Pour ce faire, on ajoutera une a une les clauses de s a un systme e initialement vide. 4. Programmation des tapes 2 et 3 e Ecrire les fonctions suivantes :
ajoute_cons : clause -> clause -> systeme -> systeme ajoute_consensus : clause -> systeme -> systeme -> systeme cloture : systeme -> systeme

{ ajoute_cons c c s calcule le consensus ventuel entre c et c et, sil est non e trivial, lajoute au systme s. e { ajoute_consensus c s s calcule tous les consensus non triviaux entre c et une des clauses de s et les ajoute au systme s . e { cloture s calcule la cl^ture par consensus du systme s, cest--dire le systme o e a e s que lon obtient en sortie de ltape 3. On utilisera la fonction subtract pour e dtecter si deux systmes sont gaux indpendamment de lordre dans lequel sont e e e e ranges les clauses dans chaque systme. e e 5. Applications a) Vrier avec votre programme que les lves ne peuvent jamais avoir de maue ee vaises notes (sous les hypothses de lexemple donn en introduction). e e b) Les rgles dadmission dans un club cossais sont les suivantes : e e Tout membre non cossais porte des chaussettes rouges. e Tout membre qui porte des chaussettes rouges porte un kilt. Les membres maris ne sortent pas le dimanche. e Un membre sort le dimanche si et seulement sil est cossais. e Tout membre qui porte un kilt est cossais et mari. e e Tout membre cossais porte un kilt. e (Lewis Carroll)

Recherche de contradictions par la mthode des consensus e

181

Montrer que les rgles de ce club sont si contraignantes que personne ne peut e en ^tre membre. e 6. Achage des tapes dune contradiction e Le programme prcdent dit que le club cossais ne peut pas avoir de membres, e e e mais on ne sait pas vraiment pourquoi : on sait seulement que la machine a trouv e une contradiction entre toutes les rgles. En fait il nest pas dicile dobtenir une e dmonstration en bonne et due forme de la contradiction trouve, il sut chaque e e fois quon produit un nouveau consensus de mmoriser a partir de quelles clauses e il a t obtenu. Lorsquon aboutit a la clause Faux , il ne reste plus qu acher ee a ces tapes dans le bon ordre. Modier le type clause de la manire suivante : e e
type clause == (string list) * (string list) * raison and raison = H | D of clause * clause;;

Une clause est a prsent constitue de la liste de ses variables positives, de la e e liste de ses variables ngatives, et dun composante de type raison indiquant son e origine : H pour une hypothse, D(c1,c2) pour une clause dduite par consensus e e des clauses c1 et c2 . Modier en consquence votre programme de recherche de contradiction et e crire une fonction dachage imprimant, lorsquune contradiction a t trouve, e ee e toutes les tapes ayant produit cette contradiction. Dans le cas du club cossais e e on obtiendra par exemple :
let syst = cloture ["e" ~=> "r"; "r" => "k"; "m" =>~ "d"; "d" => "e"; "e" => "d"; "k" => "e"; "k" => "m"; "e" => "k"] in explique (hd syst);; Jai lhypoth`se : k => e e Jai lhypoth`se : r => k e De r => k et k => e je dduis : r => e Jai lhypoth`se : e+r e De e+r et r => e je dduis : e e Jai lhypoth`se : e => d e Jai lhypoth`se : m.d => Faux e De m.d => Faux et e => d je dduis : e Jai lhypoth`se : e => k e Jai lhypoth`se : k => m e De k => m et e => k je dduis : e => e De m.e => Faux et e => m je dduis : e De e et e => Faux je dduis : Faux e - : unit = ()

m.e => Faux

m e => Faux

182

Travaux pratiques

Modlisation dun tableur e


Un tableur est un programme permettant de grer un tableau constitu dune e e matrice de valeurs et dune matrice de formules. Voici un exemple de tableau :
0 0 1 2 1 2 0 0 1 2 1 2

1 4 7

2 5 8
valeurs

3 6 9

2A20 A02

A22 A20 + A22 A11 + A01


formules

A00 A10 + A21

Chaque formule indique comment calculer llment de la matrice des valeurs ee ayant m^me position, par exemple la cellule ligne 1, colonne 2 contient la formule e A10 + A21 ce qui signie que la valeur ligne 1, colonne 2 doit ^tre gale a la somme e e des valeurs ligne 1, colonne 0 et ligne 2, colonne 1. Manifestement ce nest pas le cas et le r^le du tableur est de remplacer les lments de la matrice des valeurs qui o ee sont associs a une formule par lvaluation de la formule en question. A priori e e il sut dvaluer chaque formule et de modier en consquence la matrice des e e valeurs, mais un problme dlicat se pose : dans quel ordre doit-on valuer les e e e formules ? Ce problme est appel tri topologique : tant donns un ensemble ni e e e e dobjets et un ensemble ni de relations de dpendance entre ces objets, classer les e objets de sorte quaucun ne dpende dun objet situ aprs lui dans le classement. e e e Lalgorithme du tri topologique est le suivant : 1. Noter pour chaque objet o de combien dobjets il dpend et quels sont e les objets qui dpendent de lui. Ces objets seront appels successeurs e e de o. Initialiser la liste rsultat a . e 2. Tant quil reste des objets ayant un compte de dpendance nul : e slectionner un objet ayant un compte de dpendance nul, le placer e e dans la liste rsultat et diminuer dune unit les comptes de dpene e e dance de tous ses successeurs. 3. Sil reste des objets non classs alors le problme na pas de solution, e e sinon retourner la liste rsultat. e La terminaison et la correction de cet algorithme sont videntes. Lobjet de e ce TP est dimplmenter lalgorithme du tri topologique dans le cas particulier e dun tableur. On utilisera les dclarations caml suivantes : e
type lcell == type formule = type tableau = n : v : f : (int*int) list;; (* Rien | Somme of lcell;; { int; p : int; (* int vect vect; (* formule vect vect; (* liste de cellules *)

dimensions *) valeurs des cellules *) formules *)

Modlisation dun tableur e dep: int vect vect; suc: lcell vect vect; mutable lt : lcell };; (* nombre de dpendances *) e (* successeurs *) (* ordre de calcul *)

183

Si t est une variable de type tableau et i, j sont deux entiers on aura : { t.n est le nombre de lignes du tableau ; { t.p est le nombre de colonnes du tableau ; { t.v.(i).(j) est la valeur ligne i, colonne j ; { t.f.(i).(j) est la formule ligne i, colonne j ; { t.dep.(i).(j) est le compte de dpendance de la cellule ligne i, colonne j ; e { t.suc.(i).(j) est la liste des successeurs de la cellule ligne i, colonne j ; { t.lt est la liste des cellules trie par ordre topologique ; e { si t.f.(i).(j) = Rien alors la valeur t.v.(i).(j) nest soumise a aucune contrainte ; { si t.f.(i).(j) = Somme[c0; . ..; ck1 ] alors la valeur t.v.(i).(j) doit ^tre e gale a la somme des valeurs des cellules c0 , . .., ck1. e Ici on sest limit aux formules de type addition de cellules, dautres types e de formules pourraient ^tre naturellement implmentes. Le tableau donn en e e e e exemple est dni par : e
let t = { n = 3; p = 3; v = [| [| 1; 2; 3 |]; [| 4; 5; 6 |]; [| 7; 8; 9 |] |]; f = [| [|Rien; Somme[2,2]; Somme[0,0] |]; [|Somme[2,0; 2,0]; Somme[2,0; 2,2]; Somme[1,0; 2,1]|]; [|Somme[0,2]; Somme[1,1; 0,1]; Rien |] |]; dep = make_matrix 3 3 0; suc = make_matrix 3 3 []; lt = [] };;

1. Tri topologique Programmer lalgorithme du tri topologique. Voici a titre indicatif une dcompo e sition possible des oprations a eectuer : e
dpendances : tableau -> unit e calcule les matrices dep et suc dun tableau a partir de sa matrice f. place : tableau -> (int*int) -> unit place une cellule dans la liste lt et dcrmente le compte de dpendance e e e

de chaque successeur de la cellule place. e


dcompte : tableau -> lcell -> unit e

dcrmente les comptes de dpendance des cellules transmises en deuxie e e e me argument et appelle place pour chaque cellule dont le compte de dpendance devient nul. e

184 tri_topo : tableau -> unit

Travaux pratiques

eectue le tri topologique du tableau transmis.


place et dcompte sont deux fonctions mutuellement rcursives, elles devront ^tre e e e dclares de faon conjointe par : e e c let rec place t (i,j) = ... and dcompte t liste = ...;; e

2. Calcul du tableau Maintenant que le tableau est ( tri topologiquement ) il reste a valuer les fore ( e ) mules dans lordre et a modier en consquence la matrice v du tableau. Program e mer cela. On doit trouver pour le tableau servant dexemple les valeurs suivantes :
0 0 1 2 1 2

1 2 1

9 10 19

1 21 9

3. Complment e Lorsque lon modie la valeur dune cellule qui nest pas soumise a contraintes, il faut rvaluer toutes les formules qui font intervenir cette cellule, directement ou ee indirectement. Une solution nave consiste a recalculer tout le tableau, mais on peut faire mieux en notant pour chaque cellule non contrainte la liste des cellules a recalculer, trie par ordre topologique. e

Analyse syntaxique

1. Prsentation e Lobjectif de ce TP est deectuer lanalyse syntaxique dun programme puis de lexcuter a laide dun interprteur a partir de lexpression arborescente fournie e e par lanalyseur. Le langage de programmation que devra reconna^ tre lanalyseur est le suivant : { Les valeurs dnies dans le langage sont les nombres entiers et les fonce tions a un argument. { Les oprations dnies dans le langage sont les oprations arithmtiques e e e e usuelles entre nombres entiers : +, , , / et % (modulo) ainsi que lapplication de fonction : si e1 et e2 sont deux expressions alors e1 e2

Analyse syntaxique

185

dsigne lapplication de la fonction e1 a la valeur e2. Une telle ape plication nest valide que si e1 dsigne eectivement une fonction et e e2 une valeur appartenant au domaine de e1, mais cette restriction ne sera pas prise en compte dans le cadre de lanalyse syntaxique ; cest linterprteur devant valuer une expression qui signalera une erreur e e a lexcution en prsence dune application invalide. De m^me, les e e e oprations arithmtiques impossibles telle que laddition dune fonction e e et dun nombre entier ne seront signales qu lexcution. e a e { Les priorits entre oprations binaires sont les priorits algbriques habie e e e tuelles : lapplication de fonction est prioritaire devant la multiplication et la division qui sont prioritaires devant laddition et la soustraction, elles-m^mes prioritaires devant le modulo. Les oprations de m^me e e e priorit sont values de gauche a droite et des parenthses peuvent e e e e modier lordre dvaluation dune expression. e { Les constructions syntaxiques du langage sont la liaison locale dune expression a un identicateur ( let x = e1 in e2), la dnition de fonc e tion ( fun x -> e1) et lalternative ( if e1 then e2 else e3) o e1, e2, e3 u sont des expressions et x un identicateur. Dans le cas de lalternative, linterprteur devra valuer e1 , vrier quil sagit dun nombre entier, e e e puis valuer e2 si e1 = 0 ou e3 si e1 = 0. Lexpression non slectionne e e e ne doit pas ^tre value. Les dnitions introduites par let seront e e e e systmatiquement considres comme rcursives. e e e e Ce langage, bien que rduit, est susant pour coder des calculs intressants. Par e e exemple :
let f = fun x -> if x*(x-1) then 1 else f(x-1) + f(x-2) in f 5

2. Analyse lexicale La premire tape de lanalyse dune phrase est le dcoupage de cette phrase en e e e lexmes. On dnit le type suivant pour les lments lexicaux du langage : e e ee
type lex`me = e | Nombre of int (* constante | Ident of string (* identificateur | Opr of int * char (* opr. infixe | Let | In | Fun | If | Then | Else (* mots-cls e | Egal | Fl`che e (* = et -> | ParO | ParF (* parenth`ses e ;;

*) *) *) *) *) *)

Ecrire une fonction lex`mes : string -> lex`me list qui dcompose une cha^ e e e ne de caractres en liste de lexmes. Un identicateur est une suite de caractres e e e alphabtiques la plus longue possible. Les mots let, in, fun, if, then et else e sont des mots-cls et non des identicateurs, ils seront cods par les lexmes e e e correspondants. Un oprateur inxe est constitu dun unique caractre, + - * / e e e %, auquel on attache un niveau de priorit : 1 pour le modulo, 2 pour laddition e et la soustraction, 3 pour la multiplication et la division. Les parenthses et le e

186

Travaux pratiques

symbole dgalit sont cods par le caractre correspondant, la che de dnition e e e e e e de fonction est code par les caractres ->. La cha^ transmise en argument e e ne a lex`mes peut aussi contenir des blancs (espace, tabulation, retour a la ligne e cods respectivement , \t et \n en caml) qui seront considrs comme des e ee sparateurs. Si un caractre de la cha^ nest pas reconnu alors la fonction lex`mes e e ne e devra dclencher une erreur. Exemple : e
lex`mes "let f = fun x -> if x*(x-1) e then 1 else f(x-1) + f(x-2) in f 5";; - : lex`me list = e [Let; Ident "f"; Egal; Fun; Ident "x"; Fl`che; If; Ident "x"; e Opr (3, *); ParO; Ident "x"; Opr (2, -); Nombre 1; ParF; ...

3. Analyse syntaxique Lanalyseur syntaxique a pour r^le de transformer une liste de lexmes telle que o e celle retourne par la fonction lex`mes prcdente en une expression code sous e e e e e forme arborescente selon la dnition du type expression suivante : e
type expression = | Const of int (* | Var of string (* | Fct of string * expression (* | Bin of expression * char * expression (* | Appl of expression * expression (* | Test of expression * expression * expression | Letin of string * expression * expression (* ;;

nombre identificateur fonction oprateur binaire e appl. de fonction (* slection e dfinition locale e

*) *) *) *) *) *) *)

La transformation seectue par rcritures de la liste a analyser selon les rgles : ee e 1. 2. 3. 4. 5. 6. 7.


Nombre(n) Const(n) et Ident(x) Var(x)

( expression ) expression exp1 Opr(p, op) exp2 Bin(exp1 , op, exp2) exp1 exp2 Appl(exp1 , exp2 ) Fun Ident(x) Fl`che expression Fct(x, expression) e Let Ident(x) Egal exp1 In exp2 Letin(x, exp1 , exp2 ) If exp1 Then exp2 Else exp3 Test(exp1 , exp2 , exp3 )

En principe il sut dappliquer ces rgles tant que possible jusqu rduire e a e la liste a une unique expression. Mais on doit aussi tenir compte des priorits e des oprateurs binaires lors de lapplication des rgles 3 et 4 et prciser de quelle e e e manire on repre la n de la dernire expression pour chacune des rgles 5,6 e e e e et 7. On adoptera la convention de caml : une expression derrire Fl`che, In ou e e Else stant aussi loin que possible, cest--dire jusquau premier des vnements e a e e suivants : { la n de la phrase ; { la rencontre dune parenthse fermante non associe a une ouvrante ; e e

Analyse syntaxique

187

{ la rencontre dun In non associ a un Let ; e { la rencontre dun Then ou dun Else non associ a un If. e Ainsi, if a then b else c + d doit ^tre transform en : Test(a, b, Bin(c, + , d)). e e Algorithme danalyse syntaxique : parcourir la liste a analyser et empiler les lexmes sur une pile contenant les parties de la phrase dj traduites en e ea expressions et les lexmes dlimitant un groupe non encore complet. Les e e nombres et identicateurs seront traduits en constantes ou variables lors de lempilement. Eectuer sur la pile, au moment de lempilement, les rduce tions qui peuvent l^tre compte-tenu des rgles de priorit, les lexmes ParF, e e e e In, Then et Else tant considrs comme des oprateurs de priorit 0 pour e e e e e lapplication de la rgle 3. e Programmation : la pile de rduction sera implmente par une liste dont la e e e t^te est le sommet de pile. Comme elle doit contenir a la fois des lexmes et des e e expressions, on dnira un type mixte pour les lments de la pile : e ee
type lex`me_ou_expression = L of lex`me | E of expression;; e e type pile == lex`me_ou_expression list;; e

Ecrire une fonction empile : lex`me_ou_expression -> pile -> pile qui empile e un lexme ou une expression sur la pile passe en argument, procde rcursivement e e e e aux rductions ventuelles et retourne la nouvelle pile. La fonction expression cie e dessous utilise empile pour calculer lexpression associe a une liste de lexmes : e e
let expression liste = let pile = ref [L ParO] in do_list (fun x -> pile := empile (L x) !pile) liste; pile := empile (L ParF) !pile; match !pile with | [E e] -> e | _ -> failwith "erreur de syntaxe" ;;

On empile une parenthse ouvrante, tous les lexmes de la phrase a analyser e e puis une parenthse fermante, ce qui a pour eet de rduire la pile a une seule exe e pression si la liste a analyser est correcte. Cest cette expression qui est retourne. e Exemple :
expression (lex`mes "let f = fun x -> if x*(x-1) e then 1 else f(x-1) + f(x-2) in f 5");; - : expression = Letin ("f", Fct ("x", Test (Bin (Var "x", *, Bin (Var "x", -, Const 1)), Const 1,

188

Travaux pratiques Bin (Appl (Var "f", Bin (Var "x", -, Const 1)), +, Appl (Var "f", Bin (Var "x", -, Const 2))))), Appl (Var "f", Const 5))

4. Evaluation Pour valuer une expression comportant des variables on a besoin de conna^ e tre les valeurs de ces variables. On utilisera ici une liste dassociation forme de e couples (nom,valeur ) avec la convention quune variable x a pour valeur la valeur indique par le premier couple (x,qqch) gurant dans la liste. Sil ny a pas de e couple commenant par x alors le programme dvaluation provoquera une erreur. c e Une telle liste est appele liste denvironnement. On dnit le type des valeurs e e possibles pour une expression :
type valeur = | Int of int | Cloture of environnement * expression and environnement == (string * valeur) list ;;

Une valeur est soit un nombre entier x cod Int(x), soit une fonction f code e e Cloture(env,expr ) o expr est lexpression donne pour la dnition de f dans u e e fun x -> expr et env est la liste denvironnement qui tait en vigueur lors de la e dnition de f. Il faut mmoriser cet environnement car la liste denvironnement e e en vigueur lors de lvaluation dune application f(x) nest pas ncessairement la e e m^me, et cest celle a la dnition qui doit prvaloir dans une expression telle que : e e e
let a = 1 in let f = fun x -> x + a in let a = 2 in f 3

Ecrire une fonction valeur : environnement -> expression -> valeur qui calcule la valeur de lexpression fournie en deuxime paramtre a laide de la liste dene e vironnement fournie en premier paramtre. On aura par exemple : e
valeur [] (expression (lex`mes e "let f = fun x -> if x*(x-1) then 1 else f(x-1) + f(x-2) in f 5"));; - : valeur = Int 8

Solutions des exercices

190

Solutions des exercices

Exercice 1-1
let classe_3(a,b,c) = let (a,b) = if a <= b then (a,b) else (b,a) in if c <= a then (c,a,b) else if c <= b then (a,c,b) else (a,b,c) ;;

Il est eectu deux ou trois comparaisons pour classer la liste (a, b, c) ce qui est e minimal car un algorithme eectuant au plus deux comparaisons ne peut retourner que quatre permutations de (a, b, c) parmi les six possibles. Exercice 1-2
(* dit si n est parfait, n >= 2 let parfait(n) = let s = ref 0 in (* somme des for d = 1 to n-1 do if n mod d = 0 then s := !s done; n = !s (* rsultat = true ou e ;; *) diviseurs dj` vus *) e a + d; false *)

Exercice 1-3 Lalgorithme de Horner consiste a calculer par indices dcroissants les nombres : e yk = pk + pk+1 x + .. . + pn1xnk1 selon la relation de rcurrence : e yn = 0, yk = pk + xyk+1 si 0 k < n. Ici on veut calculer le polyn^me Q(X) = P(X + a) donc il sut de calculer les o polyn^mes successifs dnis par : o e Qn (X) = 0, et lon a Q = Q0 .
(* calcule le polyn^me q tel que q(x) = p(x+a) *) o let translate p a = let n = vect_length(p) in let q = make_vect n 0 in for k = n-1 downto 0 do (* ici on a : q (x ) = p +1 + p +2 (x + a ) + ... + p 1(x + a ) 2 *) for i = n-k-1 downto 1 do q.(i) <- a * q.(i) + q.(i-1) done; q.(0) <- a * q.(0) + p.(k) done; q (* rsultat *) e ;;

Qk (X) = pk + (X + a)Qk+1 (X) si 0

k < n,

Exercice 1-4

191

Exercice 1-4 1. Dcodage dune cha^ de caractres : lcriture dcimale dun entier nae ne e e e turel n est par dnition la suite (n0, n1, .. ., np1) dentiers compris entre e 0 et 9 telle que : n = n0 + 10n1 + .. . + 10p1np1, cette criture tant unique a prolongation par des zros prs. Le calcul de n e e e e a partir de la suite (n0, n1, . .., np1) se ramne donc a lvaluation en x = 10 e e du polyn^me : o P(x) = n0 + n1x + . . . + np1 xp1 que lon peut raliser par exemple avec lalgorithme de Horner. e
let valeur(s) = let p = string_length(s) in let v = ref(0) in for i = 0 to p-1 do v := !v*10 + valeur_chiffre(s.[i]) done; !v ;;

2. Comparaison de deux entiers : aprs limination des zros non signicatifs la e e e cha^ la plus longue reprsente le nombre le plus grand lorsque les longueurs ne e des cha^ nes dirent. Si s et s ont m^me longueur alors la comparaison des e e entiers reprsents par s et s concide avec la comparaison lexicographique e e de s et s : le premier caractre dirant entre s et s dcide du sens de la e e e comparaison.
(* compare les nombres a et b reprsents par s et s *) e e (* retourne 1 si a > b, -1 si a < b et 0 si a = b *) let compare s s = let n = string_length(s) and n = string_length(s) in (* saute les zros e let d = ref(0) and while (!d < n) & while (!d < n) & non significatifs *) d = ref(0) in (s.[!d] = 0) do d := (s.[!d] = 0) do d :=

!d + 1 done; !d + 1 done;

(* si les longueurs rsiduelles sont diffrentes *) e e (* alors la comparaison est termine e *) if n - !d > n - !d then 1 else if n - !d < n - !d then -1 else begin (* comparaison lexicographique *) let i = ref(0) in while (!i < n - !d) & (s.[!d + !i] = s.[!d + !i]) do i := !i + 1 done;

192

Solutions des exercices

if !i = n - !d then 0 else if s.[!d + !i] > s.[!d + !i] then 1 else -1 end ;;

Exercice 1-5 1. La dcroissance de (xn) et sa convergence vers a stablissent de faon e e c classique par tude de la fonction associe f : x 1 (x + a/x). Lalgorithme e e 2 de Heron nest pas rellement un algorithme car il implique de calculer une e innit de termes pour obtenir la limite. Par contre on peut en dduire e e un vritable algorithme de calcul approch de a a prs en testant la e e e condition : (xn )2 < a et en arr^tant les calculs ds quelle est ralise. e e e e 2. Si lalgorithme boucle alors il engendre une suite innie (xk ) entire, strictee ment dcroissante et positive, cest absurde. Il existe donc un rang > 0 tel e n que xn+1 xn . Par ailleurs (xn1 + n1)/2 a/x a donc xn a et si xn > a alors xn a + 1 > a donc xn+1 f(xn ) < xn ce qui est contradictoire avec la dnition de n. Ainsi xn = e a . Exercice 1-6 Notons T (n, p) le nombre cherch. On a : e T (n, 0) = T (n, n) = 1, T (n, p) = 1 + T (n 1, p) + T (n 1, p 1) si 0 < p < n. Si lon pose T (n, p) = T (n, p) + 1 alors on obtient : T (n, 0) = T (n, n) = 2, T (n, p) = T (n 1, p) + T (n 1, p 1)

si 0 < p < n.

Il en rsulte par rcurrence que T (n, p) = 2Cp et donc T (n, p) = 2Cp 1. Ainsi e e n n la fonction binome fait environ deux fois plus de calculs que le rsultat quelle e fournit ! Exercice 1-7 Si lon utilise la relation de rcurrence de Pascal alors il faut mmoriser les valeurs e e dj calcules ce qui peut ^tre fait en utilisant un vecteur. Lexercice 1-3 adapt ea e e e au calcul de (X + 1)n fournit une solution relativement ecace si lon veut tous les coecients Cp pour un n donn. Une solution pour calculer un seul coecient e n Cp est dutiliser une autre formule de rcurrence, par exemple : e n Cp = n n n! = Cp1 p! (n p)! p n1

Exercice 1-8

193

ce qui donne le programme :


(* calcule C(n,p) pour 0 <= p <= n *) let rec binome(n,p) = match p with | 0 -> 1 | _ -> (n * binome(n-1,p-1))/p ;;

Ce programme prsente toutefois un risque de dbordement de capacit e e e e e lorsque nCp1 est suprieur au plus grand entier reprsentable en machine, ce n1 qui peut se produire m^me si Cp est infrieur a ce plus grand entier. Noter par e e n ailleurs que la formule n * (binome(n-1,p-1)/p) est incorrecte car il est possible que Cp1 ne soit pas divisible par p (par exemple si n est pair et p = 2). Le manuel n1 de rfrence de caml prcise que lexpression ambigue : n * binome(n-1,p-1)/p ee e est interprte comme (n * binome(n-1,p-1))/p. ee Exercice 1-8 Soit N(n, p) le nombre cherch. Compte tenu des sens uniques, on a : e N(0, p) = N(n, 0) = 1 ; N(n, p) = N(n 1, p) + N(n 1, p 1) + N(n, p 1). Ces relations ne sont pas directement exploitables car elle conduiraient a refaire de nombreuses fois les m^mes calculs (on montre que le nombre dappels a e une fonction rcursive implmentant navement ces relations est gal a 3 N(n, p) 1 e e e 2 2 comme a lexercice 1-6). Pour viter la rptition des calculs, on peut utiliser une e e e matrice (n + 1) (p + 1) pour conserver les valeurs dj calcules, ou mieux, ea e travailler sur une colonne que lon ( dplace ) de i = 0 a i = n : ( e )
(* Calcule le nombre de chemins de A(0,0) a B(n,p) *) ` let Nchemins(n,p) = let colonne = make_vect (p+1) 1 (* sauvegarde de N(i-1,0..p) *) and v = ref 1 (* sauvegarde de N(i-1,j-1) *) in for i = 1 to n do v := 1; for j = 1 to p do (* ici on a colonne.(0..j-1) = N(i,0..j-1), colonne.(j..p) = N(i-1,j..p), !v = N(i-1,j-1). *) let w = colonne.(j) in colonne.(j) <- colonne.(j) + !v + colonne.(j-1); v := w done done; colonne.(p) (* rsultat *) e ;;

194

Solutions des exercices

Exercice 1-9 Soit n = 2p et Pn et Pn les temps dexcution cherchs. On a Pn+1 = Pn + Kna2 e e puisque xn est cod sur na chires, do : e u Pn = Ka2 (1 + 2 + . . . + (n 1)) = K Par ailleurs P2k = Pk + K(ka)2 , donc : Pn = Ka2 (1 + 22 + 42 + . . . + (2p1 )2 ) = K n2 1 2 Kn2a2 a . 3 3 n(n 1) 2 Kn2a2 a . 2 2

Ainsi, avec cette hypothse sur la dure dune multiplication, puiss_2 a un temps e e e dexcution de lordre de 2 du temps dexcution de puiss_1. e 3 Remarque : la conclusion demeure pour n quelconque car on a les relations : P2n = Pn + Ka2 n2, et lon obtient par rcurrence : e n N , Ka2(n 1)2 3 Pn Ka2(n + 1)2 . 3 P2n+1 = Pn + Ka2 (n2 + 2n),

Exercice 1-10 Notons n = n020 + n121 + .. . + nk12k1 lcriture binaire de n. On calcule de e proche en proche les quantits : e yi = x n 0 2 par les relations : y0 = 1, z0 = x, zi+1 = z2, yi+1 = yizni . i i
0

+n1 21 + .. . +ni1 2i1

et

zi = x2

let puiss_3(x,n) = let y = ref 1 and z = ref x and p = ref n in while !p > 0 do if !p mod 2 = 1 then y := !y * !z; z := !z * !z; p := !p / 2 done; !y ;;

Exercice 1-12

195

Exercice 1-11 Le programme puiss_2 de lexercice 1-9 requiert 6 multiplications. En remarquant que 15 = 3 5, on calcule en 2 multiplications x3 = y puis en 3 multiplications supplmentaires y5 = x15, soit en tout 5 multiplications. Est-ce le minimum ? e Il sut de chercher toutes les puissances de x que lon peut obtenir en moins de 4 multiplications ce qui peut ^tre fait a la main. On trouve les exposants e 1,2,3,4,5,6,7,8,9,10,12 et 16. Donc le nombre minimal demand est bien 5. e Exercice 1-12 1. let rec fibonacci(n) =
if n < 2 then 1 else fibonacci(n-1) + fibonacci(n-2);;

Le nombre dappels a fibonacci pour calculer Fn est gal a 2Fn 1 (dmons e e tration similaire a celle de lexercice 1-6). 2.
(* fibo(n) calcule le couple (Fn-1, Fn) *) let rec fibo(n) = match n with | 0 -> (0,1) | 1 -> (1,1) | _ -> let (u,v) = fibo(n-1) in (v,u+v) ;; let fibonacci(n) = let (u,v) = fibo(n) in v;;

Il y a rcursion simple, donc le nombre dappels a fibo pour calculer Fn est e gal a n pour n 1. e 3. Par rcurrence sur p. e 4. Avec p = n, p = n 1, p = n + 1 on obtient les relations : F2n = F2 + F2 , n n1 Notons T (n) = (Fn1, Fn). On a donc : T2n = (Fn1(2Fn Fn1 ), F2 +F2 ), n n1 F2n1 = Fn1(2Fn Fn1), F2n+1 = Fn(Fn + 2Fn1).

T2n+1 = (F2 +F2 , Fn(Fn +2Fn1 )), n n1

cest--dire que T2n et T2n+1 se calculent facilement en fonction de Tn . On a en dduit le programme suivant : e
(* fibo(n) calcule le couple (Fn-1, Fn) *) let rec fibo(n) = match n with | 0 -> (0,1) | 1 -> (1,1) | _ -> let (u,v) = fibo(n/2) in if n mod 2 = 0 then (u*(2*v - u), u*u + v*v) else (u*u + v*v, v*(v + 2*u)) ;;

Soit Tn le nombre dappels a fibo pour calculer Fn. On a Tn = 1 + T T1 = 1, do Tn = 1 + log2 n . u

n/2

et

196

Solutions des exercices

Exercice 1-13 1. Si x est pair strictement suprieur a 1 alors on a f(x) = 2f(x/2) et x/2 < x. e Si x est impair strictement suprieur a 1 alors on a f(x) = 1 + 2f((x + 1)/2) e et (x + 1)/2 < x. Donc dans les deux cas rcursifs on rappelle f en une e ou deux tapes avec un argument strictement infrieur a x ; ceci prouve la e e terminaison du calcul de f(x) par rcurrence sur x. e 2. Soit g(x) = f(x) + x. En remplaant f(x) par g(x) x dans la dnition de f c e et en simpliant on obtient un programme calculant g :
let rec if x else else ;; g(x) = <= 1 then 1+x if x mod 2 = 0 then 2*g(x/2) g(x+1)

et il est immdiat de constater que g(x) est toujours une puissance de 2. e 3. Par rcurrence sur x on montre pour x > 0 que g(x) est la premire puise e sance de 2 suprieure ou gale a 2x et f(x) = g(x) x est le complment a e e e additionner a x pour obtenir cette puissance de 2. Exercice 1-14 1. (* calcule le ppcm des elments du vecteur a e

*) (* on suppose que a contient au moins un elment. *) e let ppcm_i a = let p = ref a.(0) in for i = 1 to vect_length(a) - 1 do p := ppcm2(!p,a.(i)) done; !p ;; elments a.(i)..a.(j) *) e *) = a.(i) ppcm2(a.(i),a.(j)) in ppcm2(ppcm_rec a i k, ppcm_rec a (k+1) j)

2.

(* calcule le ppcm des (* on suppose i <= j. let rec ppcm_rec a i j if j = i then else if j = i+1 then else let k = (i+j)/2 ;;

let ppcm_dr(a) = ppcm_rec a 0 (vect_length(a)-1);;

Performances : ppcm_i eectue n1 appels a ppcm2 pour un vecteur de longueur n. Pour ppcm_dr, si T (n) est le nombre dappels a ppcm2 eectus, alors on a : e T (1) = 0, T (n) = T ( n/2 ) + T ( n/2 ) + 1 si n 2.

On constate immdiatement par rcurrence que T (n) = n 1 donc les algorithmes e e sont de performances identiques si lon ne compte que lopration ppcm2. ppcm_dr e

Exercice 1-15

197

est probablement plus lente que ppcm_i compte tenu des oprations non comptes e e (division de a en 2, gestion des appels rcursifs) et certainement plus complique e e a crire et a lire . .. e Exercice 1-15 Soient A(x) = a0 +a1 x+a2 x2 et B(x) = b0 +b1 x+b2 x2 : il sagit de dterminer les e cinq coecients du polyn^me C(x) = A(x)B(x), ce qui peut se faire en calculant o les valeurs de C en cinq points et en calculant le polyn^me de Lagrange associ. o e Par exemple, en prenant les points 0, 1, 1, 2 et 2 on obtient : C(x) = c0 + c1 x + c2 x2 + c3 x3 + c4 x4 C(0) 4 (x 5x2 + 4) = 4 C(1) 4 (x + x3 4x2 4x) 6 C(1) 4 (x x3 4x2 + 4x) 6 C(2) 4 (x + 2x3 x2 2x) + 24 C(2) 4 + (x 2x3 x2 + 2x), 24 do : u c0 = C(0) 1 2 c1 = (C(1) C(1)) + (C(2) C(2)) 3 12 5 2 1 c2 = C(0) + (C(1) + C(1)) (C(2) + C(2)) 4 3 24 1 1 c3 = (C(1) C(1)) + (C(2) C(2)) 6 12 1 1 1 c4 = C(0) (C(1) + C(1)) + (C(2) + C(2)), 4 6 24 avec : C(0) = a0 b0 C(1) = (a0 + a1 + a2)(b0 + b1 + b2 ) C(1) = (a0 a1 + a2)(b0 b1 + b2 ) C(2) = (a0 + 2a1 + 4a2 )(b0 + 2b1 + 4b2) C(2) = (a0 2a1 + 4a2 )(b0 2b1 + 4b2). On en dduit un algorithme calculant le produit de deux polyn^mes de e o longueurs infrieures ou gales a 3n en cinq multiplications de polyn^mes de e e o longueurs infrieures ou gales a n : e e

198

Solutions des exercices

Soient A et B les polyn^mes a multiplier. Les dcomposer sous la forme : o e A = A0 + xn A1 + x2nA2 , B = B0 + xn B1 + x2n B2

avec deg(Ai ) < n, deg(Bi ) < n. Calculer les produits : P0 = A 0 B 0 P1 P2 P3 P4 = (A0 + A1 + A2 )(B0 + B1 + B2 ) = (A0 A1 + A2 )(B0 B1 + B2 ) = (A0 + 2A1 + 4A2)(B0 + 2B1 + 4B2) = (A0 2A1 + 4A2)(B0 2B1 + 4B2).

Alors AB = C0 + xnC1 + x2nC2 + x3n C3 + x4nC4 avec : C0 = P 0 1 C1 = (8(P1 P2 ) + (P4 P3 )) 12 1 C2 = (30P0 + 16(P1 + P2 ) (P3 + P4 )) 24 1 C3 = (2(P2 P1 ) + (P3 P4 )) 12 1 C4 = (6P0 4(P1 + P2 ) + (P3 + P4 )). 24 Si les polyn^mes A et B sont a coecients entiers alors on vrie aisment que o e e les divisions par 12 ou 24 dans les expressions de C1 , C2, C3 et C4 sont des divisions exactes, donc le calcul de AB peut ^tre conduit sans fractions. En utilisant cet e algorithme de multiplication rcursivement pour calculer P0, . .., P5, on obtient un e algorithme de multiplication de polyn^mes eectuant 5 log3 (n) multiplications de o coecients pour calculer le produit de polyn^mes de longueurs infrieures ou gales o e e a n. La mthode de Knuth calcule le m^me produit en 3 log2 (n) multiplications e e de coecients, et on a : 5 3
log3 (n) log2 (n)

51+log3 (n) = 5nlog3 (5) , 3log2 (n) = nlog2 (3),

avec log3 (5) 1.47 < log2 (3) 1.58, donc cette mthode de multiplication e rcursive est asymptotiquement meilleure que celle de Knuth. Toutefois, les cale culs a eectuer sont plus complexes et elle ne bat exprimentalement la mthode e e de Knuth que pour de grandes valeurs de n, ce qui la rend de peu dutilit prae tique La multiplication par transformation de Fourier rapide (voir le problme e ( Interpolation de Lagrange et multiplication rapide ) ) bat ces deux algorithmes ( ) de multiplication ds n dpasse quelques milliers). e e

Exercice 2-2

199

Exercice 2-1 Version vecteur :


(* renvoie le plus grand elment de v *) e let maximum v = if vect_length(v) = 0 then failwith "vecteur vide" else begin let m = ref v.(0) in for i = 1 to vect_length(v)-1 do m := max !m v.(i) done; !m end ;;

Version liste cha^ ee : n


(* renvoie le plus grand elment de l *) e let rec maximum l = match l with | [] -> failwith "liste vide" | [a] -> a | a :: suite -> max a (maximum suite) ;;

Pour les listes cha^ ees, on peut obtenir une fonction rcursive terminale n e (pouvant sexcuter en mmoire constante) en ajoutant un deuxime paramtre e e e e contenant le maximum du dbut de la liste : e
let rec maxi2 m l = match l with | [] -> m | a::suite -> maxi2 (max a m) suite ;; let maximum l = match l with | [] -> failwith "liste vide" | a :: suite -> maxi2 a suite ;;

Exercice 2-2
(* applique f a chaque elment de l en commenant par la fin *) ` e c let rec do_list_rev f l = match l with | [] -> () | a::suite -> do_list_rev f suite; let _ = f(a) in () ;;

200

Solutions des exercices

Exercice 2-3 Avec concatnation en queue : e


let rec rev_q l = match l with | [] -> [] | a::suite -> rev_q(suite) @ [a] ;;

Complexit : on considre que la concatnation en queue de deux listes cha^ ees e e e n a un temps dexcution gal a a o est la longueur de la premire liste et a une e e u e constante. Soit T (n) le temps de calcul de limage miroir dune liste de n lments ee a laide de la fonction rev_q. On a lquation de rcurrence : e e T (n) = T (n 1) + a(n 1). Do : u T (n) = T (0) + a(0 + 1 + . .. + (n 1)) = T (0) + a Avec concatnation en t^te : e e
(* calcule "miroir(l) @ r" par concatnations en t^te *) e e let rec rev1 l r = match l with | [] -> r | a::suite -> rev1 suite (a::r) ;; let rev_t l = rev1 l [];;

n(n 1) an2 . 2 2

Complexit : le temps de calcul de rev1 l r est manifestement proportionnel a la e longueur de l donc pour une liste a n lments le temps de calcul de rev_t l est ee proportionnel a n. Exercice 2-4 1. Rotation dune liste cha^ ee L. On peut dcouper L en deux listes : n e L1 = (a0 , . . ., ak1), L2 = (ak , . .., an1)

et lon a L = L2 @ L1. Le dcoupage seectue en temps proportionnel a k et e la concatnation seectue en temps proportionnel a n k, donc la rotation e a une complexit proportionnelle a n. e Rotation dun vecteur V dans un deuxime vecteur W. e Pour i = 0..n 1 faire W.(i) V.((i + k) mod n) n. L aussi la complexit est proportionnelle a n. a e 2. Rotation dun vecteur V sur place. On peut eectuer une rotation dune position par lalgorithme : x V.(0) Pour i = 0..n 2 faire V.(i) V.(i + 1) n pour. V.(n 1) x.

Exercice 2-5

201

La rotation sur place de k positions peut alors ^tre eectue par k rotations e e dune position avec une complexit totale proportionnelle a kn. e 3. Rotation Tournesol. Soit la permutation a eectuer. dcomposition en cycles a supports disjoints : e = c1 c2 . .. cp , o chaque ci est un cycle de la forme : u ci = (j, (j + k) mod n, (j + 2k) mod n, . . .) admet une

pour un certain entier j que lon peut supposer compris entre 0 et k 1. Une itration de la boucle while : e
let temp = v.(!i0) ... v.(!i) <- temp; compte := !compte + 1;

eectue sur place la permutation circulaire (!i0, (!i0 + k) mod n, . ..) donc lun des cycles ci composant , plus prcisment celui contenant !i0, e e tout en cumulant dans compte le nombre dlments dplacs. A la n de ee e e cette boucle while on a donc dplac au moins n lments et il reste a vrier e e ee e que les cycles eectus sont distincts pour prouver que chaque lment a t e ee ee dplac une et une seule fois. e e Notons d le pgcd de n et k. Alors deux entiers i et j appartiennent au m^me cycle si et seulement sils sont congrus modulo d donc le nombre e dlments dun cycle est n/d et les cycles contenant 0, 1, . .. , d 1 sont disee tincts. Ce sont exactement les cycles raliss par le programme Tournesol e e puisquon atteint ainsi d (n/d) = n lments dplacs. Ainsi le programme ee e e est valide. Intr^t : le temps de ralisation dun cycle de longueur n/d est de la forme ee e a + b(n/d) o a et b sont des constantes (a est le temps dinitialisation et u b est la dure dexcution dun cycle), donc le temps de ralisation de la e e e rotation complte est de la forme ad + bn + c = O(n) au lieu kn pour e lalgorithme donn a la question prcdente. e e e Exercice 2-5 Test de prsence : e
let rec contient f l = match l with | [] -> false | a::suite -> (f a) or (contient f suite) ;;

Lexpression boolenne (f a) or (contient f suite) est value en caml comme : e e e


if (f a) then true else (contient f suite)

202

Solutions des exercices

cest--dire que la partie (contient f suite) nest pas value si (f a) retourne a e e true. Ainsi, la fonction contient sarr^te ds quun lment satisfaisant le prdicat e e ee e f est trouv, sans parcourir le reste de la liste. e Dernier lment vriant le critre : on peut calculer limage miroir de l (cf. ee e e exercice 2-3) puis chercher le premier lment de cette liste vriant le critre ee e e a laide du programme cherche_liste prsent a la section 2-4. On peut aussi e e parcourir la liste en conservant le dernier lment trouv jusque l : ee e a
(* retourne le dernier elment de l vrifiant f *) e e (* ou a dfaut x ` e *) let rec dernier_1 f x l = match l with | [] -> x | a::suite -> if f(a) then dernier_1 f a suite else dernier_1 f x suite ;; (* retourne le dernier elment de l vrifiant f *) e e let rec dernier f l = match l with | [] -> failwith "non trouv" e | a::suite -> if f(a) then dernier_1 f a suite else dernier f suite ;;

Exercice 2-6 Une mthode simple est de comparer le dbut de A et B : sils concident alors B e e est une sous-liste de A au rang 0. Sinon on cherche si B est une sous-liste de la queue de A et on adapte le rang ventuellement trouv. e e Version liste cha^ ee : n
(* dit si le dbut de a est egal a la liste b *) e ` let rec est_dbut a b = match (a,b) with e | (_,[]) -> true | ([],_) -> false | (x::sa, y::sb) -> (x = y) & (est_dbut sa sb) e ;; (* cherche si b est une sous-liste de a et renvoie (* le premier rang dapparition de b dans a si oui. (* Sinon, renvoie -1. let rec cherche_sous_liste a b = match a with | [] -> -1 | _::suite -> if est_dbut a b then 0 e else let i = cherche_sous_liste suite if i >= 0 then i+1 else -1 ;; *) *) *)

b in

Exercice 2-7

203

Version vecteur :
(* cherche si b est un sous-vecteur de a et renvoie *) (* le premier rang dapparition de b dans a si oui. *) (* Sinon, renvoie -1. On suppose b non vide. *) let cherche_sous_vect a b = let and and and la = vect_length(a) lb = vect_length(b) i = ref 0 trouve = ref false in

while (!i+lb <= la) & (not !trouve) do let j = ref 0 in while (!j < lb) & (a.(!i + !j) = b.(!j)) do j := !j+1 done; trouve := (!j = lb); i := !i+1 done; if !trouve then !i-1 else -1 ;;

Exercice 2-7
(* vecteur circulaire avec indice de dbut et longueur *) e type a cercle = {v:a vect; mutable d:int; mutable l:int};; (* ins`re x en t^te de c *) e e let ins_tete c x = let n = vect_length(c.v) in if c.l >= n then failwith "plus de place" else begin c.d <- (c.d + n - 1) mod n; c.v.(c.d) <- x; c.l <- c.l + 1 end ;; (* ins`re x en queue de c *) e let ins_queue c x = let n = vect_length(c.v) in if c.l >= n then failwith "plus de place" else begin c.v.((c.d + c.l) mod n) <- x; c.l <- c.l + 1 end ;;

204 (* extrait la t^te de c *) e let extr_tete c = let n = vect_length(c.v) in if c.l = 0 then failwith "liste vide" else begin let x = c.v.(c.d) in c.d <- (c.d + 1) mod n; c.l <- c.l - 1; x end ;; (* extrait le dernier elment de c *) e let extr_dernier c = let n = vect_length(c.v) in if c.l = 0 then failwith "liste vide" else begin c.l <- c.l - 1; c.v.((c.d + c.l) mod n) end ;;

Solutions des exercices

Remarques : { ins_tete dcrmente lindice de dbut par linstruction : e e e


c.d <- (c.d + n - 1) mod n;

et non (c.d - 1) mod n car loprateur mod en caml retourne un rsultat ngatif e e e si son premier argument est ngatif. e { Linsertion dun lment en t^te ou en queue peut chouer si le vecteur c.v est ee e e entirement rempli. On peut remdier a ce problme en recopiant le vecteur c.v e e e dans un vecteur plus grand en cas de dbordement : e
type a cercle = {mutable v:a vect; mutable d:int; mutable l:int};; (* allonge c.v par doublement de taille *) let allonge c = c.v <- concat_vect c.v c.v;;

Le temps dune insertion nest alors plus constant, mais le temps cumul Tn de e n insertions reste asymptotiquement proportionnel a n car concat_vect v1 v2 sexcute en un temps asymptotiquement proportionnel a la somme des longueurs e de v1 et v2 donc on a lquation de rcurrence : e e T2n = Tn + (n) qui a pour solution Tn = (n) (cf. section 6-3). { Une autre possibilit dimplmentation des listes a double entre est dutiliser e e e deux listes cha^ ees L1 et L2 telles que L = L1 @ miroir(L2 ) (cf. exercice 2-3). n Dans ce cas les oprations dinsertion et dextraction peuvent ^tre eectues de e e e manire fonctionnelle, cest--dire sans perdre la liste initiale : e a

Exercice 3-1 type a dbliste = {dbut:a list; fin:a list};; e let ins_tete l x = {dbut = x::l.dbut; fin = l.fin};; e e let ins_queue l x = {dbut = l.dbut; fin = x::l.fin};; e e let extr_tete(l) = match l.dbut with e | x::suite -> (x, {dbut=suite; fin=l.fin}) e | [] -> match rev(l.fin) with | x::suite -> (x, {dbut=suite; fin=[]}) e | [] -> failwith "liste vide" ;; let extr_dernier(l) = match l.fin with | x::suite -> (x, {dbut=l.dbut; fin=suite}) e e | [] -> match rev(l.dbut) with e | x::suite -> (x, {dbut=[]; fin=suite}) e | [] -> failwith "liste vide" ;;

205

Avec cette implmentation, les oprations dinsertion en t^te et en queue e e e sont eectues en temps constant, une suite de k extractions a la m^me extrmit e e e e seectue dans le pire des cas en un temps asymptotiquement proportionnel a la longueur n de la liste, et une suite de k extractions sans contrainte dextrmit e e seectue dans le pire des cas en un temps asymptotiquement proportionnel a kn. Exercice 3-1
(* insertion sans rptition dans un vecteur tri *) e e e let ins`re_vect compare v x = e let n = vect_length(v) and i = ref(0) and c = ref(PLUSPETIT) in (* cherche a quelle place insrer x *) ` e while (!i < n) & (!c = PLUSPETIT) do c := compare v.(!i) x; i := !i + 1 done; (* elment dj` prsent ? *) e e a e if !c = EQUIV then copy_vect v (* sinon effectue linsertion *) else begin let w = make_vect (n+1) x in for j = 0 to !i-2 do w.(j) <- v.(j) done; for j = !i-1 to n-1 do w.(j+1) <- v.(j) done; w end ;;

206

Solutions des exercices

(* insertion sans rptition dans une liste cha^ne trie *) e e e e let rec ins`re_liste compare l x = match l with e | [] -> [x] | a::suite -> match compare a x with | PLUSPETIT -> a :: (ins`re_liste compare suite x) e | EQUIV -> l | _ -> x :: l ;;

Exercice 3-2
(* fusion sans rptition de deux listes cha^nes *) e e e let rec fusion_sr compare l1 l2 = match (l1,l2) with | ([],_) -> l2 | (_,[]) -> l1 | (a::s1, b::s2) -> match compare a b with | EQUIV -> fusion_sr compare l1 s2 | PLUSPETIT -> a :: (fusion_sr compare s1 l2) | _ -> b :: (fusion_sr compare l1 s2) ;; (* fusion sans rptition de deux vecteurs *) e e let fusion_vect_sr compare v1 v2 = let let and and in v i j k = = = = make_vect (vect_length(v1)+vect_length(v2)) v1.(0) in ref 0 (* indice de v1 *) ref 0 (* indice de v2 *) ref 0 (* indice de v *)

while (!i < vect_length(v1)) & (!j < vect_length(v2)) do match compare v1.(!i) v2.(!j) with | EQUIV -> v.(!k) <- v1.(!i); k:= !k+1; i:= !i+1; j:= !j+1 | PLUSGRAND -> v.(!k) <- v2.(!j); k:= !k+1; j:= !j+1 | _ -> v.(!k) <- v1.(!i); k:= !k+1; i:= !i+1 done; (* ici, un des deux vecteurs est epuis *) e (* on recopie la fin de lautre *) while !i < vect_length(v1) do v.(!k) <- v1.(!i); k := !k+1; i := !i+1 done; while !j < vect_length(v2) do v.(!k) <- v2.(!j); k := !k+1; j := !j+1 done; sub_vect v 0 !k (* rsultat *) e ;;

Exercice 3-5

207

Remarque : fusion_vect_sr initialise le vecteur rsultat avec v1.(0) ce qui dclene e che une erreur si v1 est de longueur nulle. On peut corriger ce dfaut en traitant e a part le cas o lun des vecteurs est vide et en retournant une copie de lautre u dans ce cas. Exercice 3-3 La fusion sans rptition fournit la runion de deux ensembles. Le calcul de e e e lintersection peut ^tre conduit par un algorithme similaire : e
let rec intersection compare e1 e2 = match (e1,e2) with | ([],_) -> [] | (_,[]) -> [] | (a::s1, b::s2) -> match compare a b with | EQUIV -> a :: (intersection compare e1 s2) | PLUSPETIT -> (intersection compare s1 e2) | _ -> (intersection compare e1 s2) ;;

La dirence et la dirence symtrique se traitent de manire analogue. Toutes e e e e ces oprations ont une complexit asymptotique O( 1 + 2 ) o 1 et 2 sont les e e u cardinaux des ensembles e1 et e2. Exercice 3-4 Comme dans lexercice 3-3, une adaptation de lalgorithme de fusion donne le rsultat : e
let rec addition p q = match (p,q) with | ([], _) -> q | (_, []) -> p | ((a,e)::p, (b,f)::q) -> if e < f then (a,e) :: (addition p q ) else if e > f then (b,f) :: (addition p q) else let c = a + b in if c = 0 then addition p q else (c,e) :: (addition p q) ;;

Exercice 3-5 Fusion de trois listes : on peut fusionner L1 et L2 dans une liste L puis fusionner L et L3. Le nombre maximal de comparaisons est : Ncomp = (
1

1) + (

1) = 2

+2

2.

Il y a intr^t avec cette stratgie a prendre pour L3 la liste la plus longue, mais si les ee e longueurs des listes ne sont pas connues a lavance, alors le temps de dtermination e de la liste la plus longue peut ^tre plus co^teux que lconomie ralise en temps e u e e e de comparaisons. Une autre possibilit est de fusionner les trois listes en parallle suivant lale e gorithme :

208

Solutions des exercices

renvoie le numro de la liste contenant le plus petit lment e ee fonction minimum(L1,L2 ,L3 : liste) i 0 si L1 = alors i 1 si L2 = alors si i = 0 alors i 2 si i = 1 et si t^te(L2) < t^te(L1) alors i 2 e e si L3 = alors si i = 0 alors i 3 si i = 1 et si t^te(L3) < t^te(L1) alors i 3 e e si i = 2 et si t^te(L3) < t^te(L2) alors i 3 e e retourner i n fusionne L1 , L2 , L3 dans L fonction fusion3(L1,L2 ,L3 : liste) i minimum(L1, L2, L3) si i = 0 alors [] si i = 1 alors t^te(L1) :: fusionne(queue(L1), L2 , L3) e si i = 2 alors t^te(L2) :: fusionne(L1,queue(L2), L3) e si i = 3 alors t^te(L3) :: fusionne(L1, L2 ,queue(L3)) e n Chaque lment plac dans la liste rsultat donne lieu a au plus deux comparaisons ee e e (une seule pour lavant dernier et aucune pour le dernier) do : u Ncomp = 2( Cet algorithme est donc moins bon. Fusion de quatre listes : on peut envisager au moins quatre algorithmes. a. Fusion de L1 et L2 dans L, fusion de L et L3 dans L et fusion de L et L4 avec 3 1 + 3 2 + 2 3 + 4 3 comparaisons. b. Fusion de L1 et L2 dans L, fusion de L3 et L4 dans L puis fusion de L et L avec 2 1 + 2 2 + 2 3 + 2 4 3 comparaisons. c. Fusion en parallle comme pour trois listes, le minimum de 4 objets tant e e dtermin en au plus 3 comparaisons soit au total 3 1 + 3 2 + 3 3 + 3 4 6 e e comparaisons. d. Fusion en parallle avec un calcul de minimum plus astucieux : supposons e que lon ait class les t^tes de L1 , L2 , L3 et L4 . On conna^ alors le minimum e e t qui peut ^tre insr dans L, et on peut classer la nouvelle t^te de la liste do e ee e u vient ce minimum par rapport aux trois autres en seulement 2 comparaisons. On fusionne ainsi les quatre listes avec au maximum 2 1 + 2 2 + 2 3 + 2 4 3 comparaisons.
1

3)

3.

Exercice 3-7

209

Le meilleur algorithme parmi ceux envisags pour fusionner quatre listes e est b ou d avec une prfrence pour b qui est plus simple a programmer. Plus ee gnralement, on peut fusionner p listes tries de longueurs 1 , . . ., p avec moins e e e de log2 p ( 1 + . .. + p ) comparaisons en fusionnant les listes deux par deux, puis en fusionnant les listes obtenues deux par deux, et ainsi de suite. Exercice 3-6
(* applique une passe du tri a bulles a l, retourne la liste *) ` ` (* obtenue et lindicateur fini qui dit si l etait trie e *) let rec bulles1 compare l fini = match l with | [] -> [], fini | [a] -> [a], fini | a::b::suite -> if compare a b = PLUSGRAND then let l,f = bulles1 compare (a::suite) false in (b::l),f else let l,f = bulles1 compare (b::suite) fini in (a::l),f ;; let rec bulles_liste compare l = let l,fini = bulles1 compare l true in if fini then l else bulles_liste compare l ;;

Remarque : a lissue dune passe du tri a bulles le dernier lment de la liste ee obtenue est le maximum de cette liste donc il est a la bonne place et peut ^tre e ignor lors des passes suivantes. Cette optimisation pourrait ^tre programme en e e e ajoutant un troisime paramtre a bulles1 indiquant combien dlments restent e e ee a comparer. Exercice 3-7 Soit (n) la moyenne cherche. Considrons une liste L = (a0 , .. ., an ) a n + 1 e e lments et soient L = (a0 , . .., an1), L = (b0 , . .., bn1) la liste trie associe ee e e a L , et p la position nale de an dans la liste trie associe a L. Le tri a bulles de e e L eectue Ninv (L) changes, et lon a Ninv (L) = Ninv(L ) + n p. On en dduit e e la relation : (n + 1) = (n) + 1 Kn+1
L

(n p) = (n) + si 0

1 Kn+1
L

K1 an =0

(n p).

Lorsque an varie de 0 a K 1, la liste L tant xe, on a : e e np = n . .. a n < b0 ; n p = n 1 si b0 si bn1 an < b1 ; an < K.

donc :
K1 an =0

np = 0

(n p) = nb0 + (n 1)(b1 b0 ) + .. . + 1(bn1 bn2 ) = b0 + . .. + bn1 = a0 + . .. + an1.

210

Solutions des exercices

On a alors : 1 K 1 Kn
n+1 L an =0 K1

(n p) =

1 K
n+1 L

(a0 + . . . + an1 ) = n

K1 2K

K1 (valeur moyenne de ai sur lensemble des listes L). Donc 2 L K1 (n + 1) = (n) + n avec (1) = 0, et nalement : 2K car ai = (n) = n(n 1) K1 . 4K

Lorsque K est grand, K1 1 donc le nombre moyen dchanges eectus e e 4K 4 par le tri a bulles dun vecteur de longueur n est de lordre de n2/4, ce qui implique que la complexit en moyenne du tri a bulles est quadratique (sous lhypothse e e dquidistribution de tous les vecteurs de longueur n). e Exercice 3-8 1. Non en gnral. Par exemple si a0 est le plus grand lment de L et si e e ee (a1 , .. ., an1) est trie par ordre croissant, alors L est 1-presque trie a e e gauche mais pas a droite. 2. La complexit du tri a bulles sur une liste L est proportionnelle au nome bre dinversions de L et, lorsque L est p-presque trie a gauche, ce nombre e dinversions est major par np. On a le m^me rsultat pour une liste pe e e presque trie a droite. e Exercice 3-9 On remarque que merge eectue la fusion de deux listes cha^ ees suivant la relan tion dordre dnie par la fonction boolenne order (order x y renvoie true si et e e seulement si x y).
sort fonctionne de la manire suivante : on constitue par initlist l une e liste de sous-listes de l tries et de longueur 2, la dernire tant ventuellement e e e e de longueur 1. Puis on fusionne ces sous-listes deux par deux avec merge2, et on recommence tant quil reste au moins deux sous-listes (fonction mergeall). Par rcurrence sur la profondeur de rcursion, on montre que la liste renvoye e e e par mergeall est constitue de sous-listes tries formant une partition de la liste e e initiale l. La rcursion est nie car le nombre de sous-listes renvoyes dcro^ e e e t strictement a chaque appel jusqu ce quil ne reste plus quune seule sous-liste a qui est la liste trie associe a l. e e

Exercice 3-10

211

Exercice 3-10
(* Cherche la plus grande squence croissante initiale *) e (* de la liste l et renvoie cette squence et le reste e *) (* de la liste. *) let rec cherche_squence compare l = match l with e | [] -> ([], []) | [a] -> ([a], []) | a::(b::suite as l) -> if compare a b = PLUSGRAND then [a],l else let (s,r) = cherche_squence compare l in (a::s, r) e ;; (* fusionne les sous-squences croissantes de l deux par deux *) e let rec fusionne_squences compare l = match l with e | [] -> [] | _ -> let (l1, r1) = cherche_squence compare l in e let (l2, r2) = cherche_squence compare r1 in e (fusion compare l1 l2) @ (fusionne_squences compare r2) e ;; (* code principal : on fusionne les squences deux par *) e (* deux tant quil y en a plusieurs *) let rec fusion_naturelle compare l = let (l1,r1) = cherche_squence compare l in e if r1 = [] then l else let (l2,r2) = cherche_squence compare r1 in e fusion_naturelle compare ((fusion compare l1 l2) @ (fusionne_squences compare r2)) e ;;

On tablit sparment la validit de cherche_squence, fusionne_squences e e e e e e et fusion_naturelle par rcurrence sur la longueur de la liste passe en argument. e e La complexit asymptotique de cherche_squence est proportionnelle a la taille de e e la squence initiale trouve donc la complexit des oprations : e e e e
let (l1, r1) = cherche_squence compare l in e let (l2, r2) = cherche_squence compare r1 in fusion l1 l2 e

est proportionnelle a la somme des tailles des listes l1 et l2. Il en est de m^me e pour la concatnation en queue dans : e
(fusion compare l1 l2) @ (fusionne_squences compare r2) e

et donc fusionne_squences compare l a une complexit asymptotique O(p) o p e e u est la taille de l. Enn, fusion_naturelle itre fusionne_squences tant quil reste e e au moins deux squences croissantes maximales, et le nombre de telles squences e e est divis par deux ou plus a larrondi suprieur prs a chaque itration. Donc le e e e e nombre ditrations est O(ln n) et le temps dexcution de fusion naturelle est e e O(n ln n).

212

Solutions des exercices

Remarque : plut^t que de rechercher systmatiquement les squences croissantes a o e e chaque appel a fusionne_squences, on pourrait dcouper dans un premier temps e e l en listes de squences croissantes, puis les fusionner deux par deux comme dans e lexercice 3-9. Exercice 3-11
(* dcoupe l en deux listes spares par le pivot p *) e e e let rec dcoupe compare p l = match l with e | [] -> [],[] | a::suite -> let (l1,l2) = dcoupe compare p suite in e if (compare a p) = PLUSPETIT then (a::l1,l2) else (l1,a::l2) ;; let rec tri compare l = match l with | [] -> [] | a::suite -> let (l1,l2) = dcoupe compare a suite in e (tri compare l1) @ (a :: (tri compare l2)) ;;

Remarques : { Cet algorithme de tri est stable, car dcoupe place dans la liste de droite les e lments quivalents a p en conservant leurs dispositions relatives. ee e { Lusage de la concatnation en queue, @, nest pas pnalisant ici car la come e plexit de cette concatnation dans le calcul de : e e
(tri compare l1) @ (a :: (tri compare l2))

est O(n) o n est la taille de l et dcoupe a une complexit (n) donc le u e e co^t temporel de dcoupe suivi de @ reste (n). On peut toutefois viter la u e e concatnation en queue avec le code suivant : e
(* trie la liste l et la concat`ne a m *) e ` let rec tri compare l m = match l with | [] -> m | a::suite -> let (l1,l2) = dcoupe compare a suite in e tri compare l1 (a :: (tri compare l2 m)) ;;

Exercice 3-12
let tri_rapide_itratif compare v = e (* empile le premier appel *) let pile = ref [(0,vect_length(v)-1)] in while !pile <> [] do let (a,b) = hd(!pile) in if a < b

(* bornes du vecteur a traiter *) `

Exercice 4-1 then let c = segmentation compare v a b in (* empile le plus grand sous-vecteur en premier *) if c-a < b-c then pile := (a,c-1)::(c+1,b)::(tl !pile) else pile := (c+1,b)::(a,c-1)::(tl !pile) else pile := tl !pile done ;;

213

Taille maximale de la pile : soient 1 , .. ., i les longueurs des sous-vecteurs empils e a la n dune itration de la boucle while. Si i e 2 alors le sous-vecteur de longueur i est remplac lors de litration suivante par deux sous-vecteurs de e e longueurs i et i+1 avec i 1 alors le i+1 et i + i+1 = i 1. Si i sous-vecteur de longueur i est retir de la pile. On a donc par rcurrence : e e
i

i1

+ .. . +

ip

ip1

ip1

pour 0

p < i, do lon dduit : u e n


1

+ ... +

2(

+ .. . + i)

...

2i1 i .

Si i > log2 n alors i < 2 et litration suivante de la boucle while ne provoquera e pas de nouvel empilement. Le nombre de sous-vecteurs empils est donc toujours e major par 1 + log2 n. e Exercice 4-1 On raisonne par rcurrence sur la longueur dune formule postxe f : e { si f est de longueur 1 alors f est un nombre et il ny a aucune rduction a e eectuer ; { si f est de longueur au moins gale a 2 supposons quil y ait deux rductions e e direntes possibles, par exemple : e (1) (2) x [x] y [y]

o x, y sont des nombres et , des oprateurs unaires (le fait que et u e soient des oprateurs unaires ne restreint pas la gnralit du raisonnement e e e e qui suit). On note f1 la formule dduite de f par application de (1), f2 e la formule dduite de f par application de (2), f3 la formule dduite de f1 e e par application de (2) et f4 la formule dduite de f2 par application de (1). e Comme les sous-listes [x, ] et [y, ] ne se chevauchent pas dans f, on a f3 = f4 . Par hypothse de rcurrence f1 et f2 admettent des valeurs bien e e dnies, et comme f3 est obtenue a la fois par rduction de f1 et de f2 , les e e valeurs de f1 et f3 sont gales de m^me que les valeurs de f2 et f3 . On en e e dduit que f1 et f2 ont m^me valeur ce quil fallait dmontrer. e e e

214

Solutions des exercices

Exercice 4-2 Ceci impose de prvoir plusieurs types de valeurs dont le type boolen et les e e oprations associes pour pouvoir valuer condition, et donc de tester a chaque e e e opration si les oprandes ont le type requis. Par ailleurs, la forme postxe associe e e e a une formule conditionnelle est : exp1, exp2, condition, si a lordre des termes prs, et donc les deux expressions exp1 et exp2 devront ^tre e e values avant de savoir laquelle est a retenir, ce qui ne permet pas dvaluer une e e e formule conditionnelle telle que : si x = 0 alors sin x sinon1. x

Le langage PostScript rsout ce problme en introduisant un type de valeur e e procdure constitu dune formule postxe reprsentant les calculs que doit exe e e e cuter la procdure. Une procdure place sur la pile est value par des oprateurs e e e e e e spcialiss tels exec, loop et if. e e Exercice 4-3 Une mthode simple consiste a valuer limage miroir de cette formule a laide de e e lalgorithme dvaluation postxe en permutant les oprandes lors de lvaluation e e e dune opration binaire. e Exercice 4-4
let evalue(f) = (* piles des valeurs et des oprateurs *) e let pv = ref [] and po = ref [] in (* empile une valeur en effectuant les oprations *) e (* unaires en attente *) let rec pushv x = match !po with | OP_UNAIRE(f)::so -> po := so; pushv(f x) | _ -> pv := x :: !pv in (* dpile une valeur *) e let popv() = match !pv with | [] -> failwith "formule incorrecte" | x::sv -> pv := sv; x in (* effectue les oprations binaires de priorit e e (* suprieure ou egale a p e ` let rec rduit(p) = match !po with e | OP_BINAIRE(q,f)::so when q >= p -> *) *)

Exercice 4-4 let y = popv() in let x = popv() in po := so; pushv (f x y); rduit(p) e | _ -> () in (* empile un oprateur ou une parenth`se en e e *) (* effectuant les oprations binaires prioritaires *) e let pusho lexeme = match lexeme with | VALEUR(_) -> failwith "cas impossible" | OP_UNAIRE(_) -> po := lexeme :: !po | OP_BINAIRE(p,_) -> rduit(p); po := lexeme :: !po e | PARENTH`SE_OUVRANTE -> po := lexeme :: !po E | PARENTH`SE_FERMANTE -> E rduit(-1); e match !po with | PARENTH`SE_OUVRANTE::so -> po := so; pushv(popv()) E | _ -> failwith "formule incorrecte" in (* traitement dun lex`me *) e let traitement(lexeme) = match lexeme with | VALEUR(x) -> pushv x | _ -> pusho lexeme in (* parcours de la formule et extraction du rsultat *) e traitement PARENTH`SE_OUVRANTE; E do_list traitement f; traitement PARENTH`SE_FERMANTE; E match (!pv, !po) with | [x],[] -> x | _ -> failwith "formule incorrecte" ;;

215

Remarques : on a suppos que toutes les priorits des oprateurs binaires sont e e e positives, donc linstruction rduit(-1) eectue toutes les oprations unaires et e e binaires en instance jusqu rencontrer une parenthse ouvrante dans la pile des a e oprateurs. De m^me, lintroduction dune parenthse ouvrante avant le parcours e e e de f et dune parenthse fermante aprs ce parcours permet deectuer simplement e e les dernires oprations en instance. e e

216

Solutions des exercices

Exercice 4-5 Il sut de remplacer dans lexercice 4-4 la pile de valeurs pv par une pile de lexmes e et dy empiler les oprateurs retirs de po dans les fonctions rduit et pushv au lieu e e e de calculer les rsultats de ces oprations. Lorsque f a t entirement parcourue, e e ee e pv contient limage miroir de la liste f dsire. e e Exercice 4-6 Lexercice 4-5 fournit un algorithme de construction de f , ce qui prouve son existence. On en dmontre lunicit par rcurrence sur la longueur de f. e e e { Une formule inxe de longueur 1 bien forme est rduite a une variable, et la e e seule formule postxe quivalente est elle aussi rduite a cette variable. e e { Considrons une formule inxe bien forme f de longueur n > 1 comportant e e donc au moins un oprateur. Les rgles de priorit dterminent de manire non e e e e e ambigue le dernier oprateur, op, a valuer : cest un oprateur unaire si f est de e e e la forme f = op(qqch) et cest loprateur binaire de niveau le plus externe, de e priorit la plus basse et le plus a droite dans les autres cas. Cet oprateur doit e e donc ^tre plac en dernire position de f et le dbut de f est constitu dune ou de e e e e e deux formules postxes calculant le ou les oprandes de op dans le bon ordre. Ces e formules sont les formules postxes associes aux sous-formules de f dnissant e e les oprandes de op, donc elles sont uniques par hypothse de rcurrence. e e e Exercice 5-1 On a p = p nand p ; p et q = p nand q ; p ou q = p nand q. Donc le connecteur nand permet dexprimer les trois connecteurs et, ou, non et donc toutes les formules boolennes. e La ngation ne peut ^tre exprime uniquement a laide de et et de ou car e e e toute formule non constante constitue de ces connecteurs vaut faux lorsque toutes e les variables valent faux. Exercice 5-2 1. peutetre 2.
type normand = Vrai | Faux | Peutetre;; let non = fun | Vrai -> Faux | Faux -> Vrai | Peutetre -> Peutetre ;; let et | Vrai | Faux | _ | _ ;; = fun Vrai -> _ -> Faux -> _ ->

Vrai Faux Faux Peutetre

Exercice 5-3

217

let ou p q = non(et (non p) (non q));; let oubien p q = et (ou p q) (non(et p q));;

3.

#(* vrifie que deux fonctions normandes de trois *) e (* variables sont egales *) let est_gal f g = e let val = [|Vrai; Faux; Peutetre|] in let res = ref(true) in for i = 0 to 2 do for j = 0 to 2 do for k = 0 to 2 do res := !res & ( f val.(i) val.(j) val.(k) = g val.(i) val.(j) val.(k) ) done done done; !res ;; est_gal : e (normand -> normand -> normand -> a) -> (normand -> normand -> normand -> a) -> bool = <fun> #(* associativit *) e est_gal (fun p q r -> et (et p q) r) e (fun p q r -> et p (et q r));; - : bool = true #est_gal (fun p q r -> ou (ou p q) r) e (fun p q r -> ou p (ou q r));; - : bool = true #(* distributivit *) e est_gal (fun p q r -> et (ou p q) r) e (fun p q r -> ou (et p r) (et q r));; - : bool = true (* etc *)

4. Non : on montre par rcurrence sur la longueur dune expression et-ou-non e que si la fonction f associe est non constante alors la valeur de f est peutetre e lorsque toutes les variables valent peutetre. Exercice 5-3 1. f vaut faux si et seulement si parmi p1 , .. ., pn il y a un nombre pair de variables valant vrai. Soit g un facteur de f : g spcie un cas o f vaut e u faux, donc spcie les valeurs de toutes les variables p1 , . .., pn . Le nombre e minimal de facteurs de f est donc le nombre de rsultats faux dans la table e de vrit de f, soit 2n1. e e 2. Non : partant de la forme normale conjonctive dune fonction boolenne f, on e peut toujours regrouper deux facteurs qui ne dirent que par la variable pn . e En eet, si u est une proposition quelconque, alors on a : (u + pn )u (u + pn )(u + pn ) u(u + pn ) u.

218

Solutions des exercices

Exercice 5-4 On a : p p vrai, p + q p q pq et (p q)(r s) pr ps qr qs. Ces trois rgles permettent de mettre rcursivement une formule exprime a laide de e e e et, ou et non sous la forme dune somme exclusive des constantes vrai, faux et de produit de variables. On peut aussi considrer quune fonction boolenne est une application de e e (Z/2Z)n dans Z/2Z, et quune telle application est polynomiale car Z/2Z est un corps ni pour les lois et . La transformation dune formule logique en somme exclusive correspond donc a une criture polynomiale de la fonction associe. e e On dmontre lunicit a ordre prs dune telle criture, aprs suppression e e e e e des termes nuls ou rpts, par rcurrence sur n. Pour n = 1 il sut de conse ee e tater que les quatre expressions possibles, vrai, faux, p et vrai p dnissent e des fonctions boolennes de p distinctes. Supposons lunicit tablie pour toute e e e formule boolenne a n 1 variables et considrons une formule boolenne f a n e e e variables p1 , .. ., pn, ayant deux dcompositions en sommes exclusives simplies. e e En regroupant dans chaque dcomposition les termes ayant pn en facteur, on a : e f a bpn c dpn o a, b, c, d sont des sommes exclusives simplies en les variables p1 , .. ., pn1. u e En prenant pn = 0 on obtient a c donc a = c par hypothse de rcurrence, et e e en prenant pn = 1 on obtient a + b c + d avec a = c do b d et donc b = d u par hypothse de rcurrence encore (= dsigne ici lgalit a ordre prs). e e e e e e Puisquil y a unicit on peut tester si f reprsente une tautologie en calculant e e sa forme somme exclusive simplie : ou bien elle se rduit a vrai et f reprsente e e e bien une tautologie, ou bien elle se rduit a faux et f nest jamais satisable, ou e bien elle contient dautres termes et sa valeur nest pas constante. Comme pour la mthode ( forme conjonctive ) , cette mthode a un co^t mmoire (et donc aussi e e u e ( ) temps) exponentiel dans le pire des cas. Par exemple la forme somme exclusive rduite de : e (p1 p2 )(p1 p3 ). ..(p1 pn ) est : p1 p2 . ..pn n 2 p2 . ..pn o (2 , . .., n ) dcrit {0, 1}n1, donc cette forme comporte 2n1 + 1 termes. u e Exercice 5-5 La seule dicult est de raliser la runion sans rptition des listes de variables e e e e e de deux sous-formules. Comme les cha^ nes de caractres peuvent ^tre compares e e e par lordre lexicographique (ordre total qui est celui que fournit <= en caml), on peut utiliser la mthode de fusion sans rptition sur les listes de variables tries e e e e selon cet ordre.
let rec liste_variables f = match f with | Const(_) -> [] | Var(p) -> [p]

Exercice 5-6 | Mono(_,g) -> liste_variables g | Bin(_,g,h) -> union (liste_variables g) (liste_variables h) where rec union l l = match (l,l) with | [],_ -> l | _,[] -> l | p::suite, p::suite -> if p < p then p :: (union suite l) else if p > p then p :: (union l suite) else p :: (union suite suite) ;;

219

Exercice 5-6
let rec simplifie f = match f with | (Const(_) | Var(_)) -> f | Mono(op,g) -> begin match simplifie g with | Const(x) -> Const(op x) | g -> Mono(op,g) end | Bin(op,g,h) -> begin match (simplifie g, | Const(x),Const(y) | Const(x),h | g,Const(x) | g,h end

simplifie h) with -> Const(op x y) -> simplifie_`_gauche op x h a -> simplifie_`_droite op g x a -> Bin(op,g,h)

where simplifie_`_gauche op x f = a match (op x true),(op x false) with | true,true -> Const(true) | true,false -> f | false,true -> Mono(non,f) | false,false -> Const(false) and simplifie_`_droite op f x = a match (op true x),(op false x) with | true,true -> Const(true) | true,false -> f | false,true -> Mono(non,f) | false,false -> Const(false) ;;

Les fonctions auxiliaires simplifie_`_gauche et simplifie_`_droite testent si a a les expressions op x f ou op f x dans lesquelles f est inconnue dpendent eectivee ment de f, et si oui de quelle manire. Ces fonctions sont trs gnrales puisquil e e e e nest fait aucune hypothse sur les connecteurs utiliss, mais en contrepartie on e e doit ( redcouvrir ) a chaque fois les rgles de simplication. Si le temps de calcul e ( e )

220

Solutions des exercices

dun connecteur est constant, ce qui est probable, la complexit asymptotique de e cette mthode de simplication est O(N) o N est la longueur de la formule a e u simplier. Un codage ( en dur ) des rgles de simplication napporterait pas e ( ) damlioration signicative. Remarquons que les doubles ngations ne sont pas e e simplies, et que les fonctions simplifie_`_droite et simplifie_`_gauche peue a a vent crer des doubles ngations supplmentaires. On pourrait corriger ce dfaut e e e e par la m^me mthode a laide dune fonction de simplication dun oprateur e e e unaire. Exercice 5-7 On vrie aisment que le circuit propos convient. Je nai pas de meilleure e e e rponse a la deuxime question que de passer en revue tous les circuits a quatre e e portes ou moins et de constater quaucun ne convient. Voici un programme de recherche listant tous les circuits de taille minimale a n portes ou moins gnrant e e les fonctions S0 et S1 :
(* tables de vrit *) e e type table == bool list;; (* un circuit est une liste de tables de vrit *) e e (* classes par ordre lexicographique e *) (* ajoute une table a un circuit *) ` let rec ajoute t circ = match circ with | [] -> [t] | a::suite -> if t = a then circ else if t < a then t::circ else a :: ajoute t suite ;; (* variables et let e0 = [true; and e1 = [true; and e2 = [true; and s0 = [true; and s1 = [true; ;; fonctions a obtenir *) ` true; true; true; false; true; false; false; true; false; true; false; true; false; false; true; false; true; true; false; true;

false; true; false; true; false;

false; false; true; true; false;

false] false] false] false] false]

(* fonctions de transfert *) let non a = map (fun x -> not x) a;; let et a b = map2 (prefix &) a b;; let ou a b = map2 (prefix or) a b;; let ouex a b = map2 (prefix <>) a b;; let nonet a b = non(et a b);; let nonou a b = non(ou a b);; let binops = [et; ou; ouex; nonet; nonou];;

Exercice 5-7 (* liste des paires de points dun circuit *) let rec paires = function | [] -> [] | a::suite -> (map (fun b -> (a,b)) suite) @ paires(suite) ;; (* * ensembles de circuits * djavus e = circuits de taille < n examins e * trouvs e = circuits contenant s0 et s1 * possibles = circuits de taille < n-1 ou de taille * n-1 contenant s0 ou s1 *) let djavus = ref(set__empty eq__compare);; e let trouvs = ref(set__empty eq__compare);; e let possibles = ref(set__empty eq__compare);; (* examine un circuit *) let nouveau n circ = if not(set__mem circ !djavus) then begin e let l = list_length(circ) and a0 = mem s0 circ and a1 = mem s1 circ in if l < n then djavus := set__add circ !djavus; e e if a0 & a1 then trouvs := set__add circ !trouvs; e e if (l < n-1) or ((l = n-1) & (a0 or a1)) then possibles := set__add circ !possibles end ;; (* engendre tous les circuits dduits de *) e (* "circ" par adjonction dune porte *) let successeurs n circ = (* ajoute un inverseur ou une porte binaire *) let job1 a = nouveau n (ajoute (non a) circ) and job2 (a,b) f = nouveau n (ajoute (f a b) circ) in do_list job1 circ; do_list (fun p -> do_list (job2 p) binops) (paires circ) ;; (* engendre rcursivement tous les circuits e (* par nombre croissant de portes jusqu` la a (* la taille n et retourne tous les circuits (* de taille minimale contenant s0 et s1 let cherche(n) = djavus := set__empty eq__compare; e trouvs := set__empty eq__compare; e *) *) *) *)

221

222 possibles := set__empty eq__compare; djavus := set__add [e2;e1;e0] !djavus; e e possibles := set__add [e2;e1;e0] !possibles; while set__is_empty !trouvs e & not(set__is_empty !possibles) do let p = !possibles in possibles := set__empty eq__compare; set__iter (successeurs n) p done; set__elements !trouvs e ;;

Solutions des exercices

cherche(7) recherche tous les circuits a 4 portes ou moins contenant S0 et S1 et nen trouve aucun. cherche(8) trouve 24 circuits a 5 portes convenant qui se

rduisent aprs limination des symtries aux 8 circuits suivants : e e e e

Exercice 5-9

223

Exercice 5-8 Soit p la profondeur du circuit calculant Sn : par rcurrence le nombre dentres e e de ce circuit est au plus gal a 2p et toutes les entres A0 . . .An1, B0 . ..Bn1 e e doivent ^tre prises en compte car chacune de ces entres est susceptible dinuer e e sur Sn . On a donc 2p 2n do le rsultat. u e Exercice 5-9 Premi`re mthode e e Soit N = An1 . ..A1 A0 le nombre a diviser par 3 et R = R1 R0 le reste a obtenir avec 0 R 2. On procde par rcurrence en supposant disposer du reste e e 2 2 R = R1 R0 de la division par 3 de N = An1 . ..A1 : A0 0 0 0 1 1 1 R0 0 1 0 0 1 0 R1 0 0 1 0 0 1 R0 0 0 1 1 0 0 R1 0 1 0 0 0 1
2 2

Il appara^ que R0 = 1 si et seulement si R0 = 0, R1 = A0 et que R1 = 1 si et t ee seulement si R0 = A0 , R1 = A0 , ce qui donne la cellule de division lmentaire : R0 R0 A0 R1 R1 Un diviseur n-bits sobtient alors par mise en cascade de telles cellules, ce qui donne un circuit a 5n portes de profondeur 3n. Deuxi`me mthode e e u Comme 4 1 [3 ], on a N A1A0 + A3A2 + .. . + A2p1A2p2 [3 ] o p = n/2 et A2p1 = 0 si n est impair. Donc, pour obtenir le rsidu de N e modulo 3, il sut de grouper les bits de N deux par deux, de calculer les rsidus e modulo 3 de chaque groupe, puis dadditionner modulo 3 les rsidus obtenus. Le e 2 2 circuit logique ci-dessous calcule le rsidu B1 B0 de A1 A0 modulo 3. e A0 B0
2 2 2

A1

B1

224

Solutions des exercices

Considrons a prsent le problme de laddition modulo 3 : tant donns e e e e e 2 2 deux nombres A = A1 A0 et B = B1B0 compris entre 0 et 2, on veut obtenir 2 C = C1 C0 lui aussi compris entre 0 et 2 tel que A + B C [3 ]. On construit la table de vrit de (C0 , C1) : e e A0 0 0 0 1 1 1 0 0 0 A1 0 0 0 0 0 0 1 1 1 B0 0 1 0 0 1 0 0 1 0 B1 0 0 1 0 0 1 0 0 1 C0 0 1 0 1 0 0 0 0 1 C1 0 0 1 0 1 0 1 0 0

On en dduit : C0 = B0 si A0 = A1 = 0, C0 = B0 + B1 si A0 = 1, et C0 = B1 e si A1 = 1, soit dans tous les cas : C0 = B0 (A0 + A1 ) + A0(B0 + B1 ) + A1B1 . On obtient de m^me : C1 = B1 (A0 + A1 )+A1 (B0 + B1 )+A0 B0 et lon peut construire e un circuit ( additionneur modulo 3 ) implmentant ces formules : e ( )
A0 A 0 B0

B0 (A0 + A1 ) C1 A1 A1 (B0 + B1 ) C0

B0

A0 (B0 + B1 )

B1 (A0 + A1 )

B1

A 1 B1

Enn, on calcule la somme modulo 3 des p rsidus en assemblant p 1 e additionneurs modulo 3 en arbre binaire comme le multiplieur parallle dcrit a e e la section 6-1, gure 14. On obtient ainsi un circuit calculant le rsidu modulo 3 e dun nombre de n bits ayant une profondeur 2 + 4 log2 p = 4 log2 n 2 et un nombre de portes lmentaires gal a 3 n/2 + 12(p 1) 15 n. ee e 2

Exercice 5-10

225

Exercice 5-10 1. A0

B0 2. A0 S0 E0 I0 B0 A1 S1

S E1 I1 B1 3. On compare les bits par groupes de n puis on compare avec un dernier comparateur n-bits les n sorties S, I obtenues :
B0 B1 B2 B3 A0 A1 A2 A3

E I

S0..3

I0..3

S E I

4. Cest possible, mais il existe de meilleures solutions : la construction dun comparateur 256-bits par association de comparateurs requiert 17 comparateurs 16-bits et a une profondeur double de celle de ces comparateurs, ce qui donne rcursivement 255 comparateurs 2-bits, soit 2805 portes et une e profondeur de 32.

226

Solutions des exercices

Une autre solution est de fusionner les rsultats de deux comparateurs e 128-bits en utilisant le circuit additionnel de la question 2 a condition que ces comparateurs fournissent les sorties S, E et I. Le co^t de cette association est u de 5 portes et la profondeur est augmente de 2. En ralisant les comparateurs e e 128-bits suivant le m^me principe, on peut obtenir un comparateur 256-bits e avec 256 comparateurs 1-bit et 255 modules de fusion, soit au total 2043 portes et une profondeur de 18. Dailleurs il nest pas ncessaire de calculer la sortie I pour les comparae teurs intermdiaires, S et E contiennent toute linformation ncessaire pour e e raliser les fusions. La sortie I nale peut ^tre calcule par : I = S + E ce qui e e e ncessite une seule porte et une profondeur de 1. Avec cette conomie, on obe e tient un comparateur 256-bits constitu de 1278 portes ayant une profondeur e de 19 . .. Exercice 5-10 La table de vrit du circuit demand est la suivante (on na marqu que les 1 e e e e dans les colonnes a{g pour une meilleure lisibilit) : e n 0 1 2 3 4 5 6 7 8 9 D 0 0 0 0 0 0 0 0 1 1 C B 0 0 0 0 0 1 0 1 1 0 1 0 1 1 1 1 0 0 0 0 A 0 1 0 1 0 1 0 1 0 1 a b 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 c 1 1 1 1 1 1 1 1 1 d e f 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 g

1 1 1 1 1 1 1

En distinguant selon la valeur du couple (D, C), on obtient la table suivante : D 0 0 1 C 0 1 0 a A+B A+B 1 b c 1 A+B AB 1 1 1 d e A+B A A B AB 1 A f A+B AB 1 g B AB 1

Do les formules : u

a = (C A) + B + D, b = C(A B), c = A + B + C + D,

d = C(A + B) + C(A B) + D, e = A(B + C), f = C A + B + CAB + D, g = CB + CAB + D.

Exercice 6-3

227

Exercice 6-1 T (n 1) T (n) a = + + b. 1. On a T (n) = nT (n 1) + an + b donc n! n! (n 1)! (n 1)! Comme la srie k=0 1/k! est convergente, on en dduit quil existe > 0 e e tel que T (n) n!. 2. Il y a n mineurs dordre n 1 a calculer, C2 mineurs dordre n 2 et de n manire gnrale Ck mineurs dordre n k. Le temps de calcul dun mineur e e e n dordre k connaissant tous les mineurs dordre k 1 est tk = ak + b en supposant que les mineurs dordre k 1 sont mmoriss de telle sorte quils e e puissent ^tre retrouvs en temps constant. Donc le temps de calcul dun e e dterminant n n est : e
n n n

T (n) =
k=0

Ck tnk = n
k=0

C k tk = n
k=0

(ak + b)Ck = n2n1a + 2nb. n

La complexit spatiale est proportionnelle a : e max(Ck , 0 n k


n/2 n) = Cn

2(n1)/2 . n

La mthode du pivot de Gauss qui a une complexit O(n3 ) est nettement e e plus performante, mais elle produit des fractions et des rsultats approchs, sauf e e si lon eectue le calcul en grant a part numrateur et dnominateur mais dans e e e ce cas les coecients manipuls sont de plus en plus gros et il faut eectuer les e oprations en multiprcision, ce qui modie la complexit. e e e Exercice 6-2 Si n est impair, on augmente les matrices dune ligne et dune colonne nulle. Le temps de calcul vrie donc lquation : T (n) = 7T ( n/2 ) + O(n2) o O(n2) e e u reprsente le temps des additions/soustractions et des recopies de coecients. On e en dduit : T (n) = (nlog2 7 ). e Exercice 6-3 Si on se limite a des cha^ nes de longueur exactement n, en considrant quil y a e 256 caractres possibles, cela fait 256n cha^ e nes direntes supposes quiprobables. e e e La probabilit de trouver deux caractres dirents a une position donne dans e e e e chaque cha^ est p = 255/256 donc le rang moyen dapparition de la premire ne e dirence est infrieur ou gal a 256/255 1.004 (et suprieur ou gal a 1). Le e e e e e nombre moyen de comparaisons de caractres eectues est gal a ce rang moyen, e e e donc est compris entre 1 et 1.004. Si les longueurs ne sont pas xes, soit pk la probabilit que la premire e e e cha^ soit de longueur k. On peut ajouter un marqueur de n a chaque cha^ ne ne (pris en dehors des 256 caractres usuels) et comparer les k+1 premiers caractres e e des deux cha^ nes. Le nombre moyen de caractres compars (pour une premire e e e cha^ de longueur k) est : ne ck = 255 256 255 256 m 256m1 m=1 m 256m1 m=1
k

+ =

k+1 255 = k 256 256 256 255

k+1 m m1 + 256 256m1 m=1 m=k+1

228

Solutions des exercices

et le nombre moyen de caractres compars pour une premire cha^ de longueur e e e ne quelconque est : p0 c0 + p1 c1 + .. . + pn cn 256 N= . p0 + p1 + .. . + pn 255 Exercice 6-4 1. Le calcul naf de la suite de Fibonacci (un = un1 + un2) donne T (n) = T (n 1) + T (n 2) + K. 2. Daprs la relation de rcurrence la fonction T est croissante, donc on peut e e crire : T (n) 2T (n 2) + f(n) et par rcurrence, T (n) 2n/2. Le temps e e dexcution est au moins exponentiel. e On peut obtenir une estimation plus prcise en considrant les racines de e e lquation caractristique x2 = x + 1 associe a lquation de rcurrence e e e e e un = un1 + un2, cest--dire : a 1+ 5 = 2 et 1 5 1 = = = 1 . 2

On a T (n) = ( + )T (n 1) T (n 2) + f(n), donc en posant : u(n) = T (n) T (n 1) et on obtient les deux relations : u(n) = u(n 1) + f(n), v(n) = v(n 1) + f(n). u(n) v(n) . v(n) = T (n) T (n 1)

Ceci permet de calculer exactement u(n), v(n) puis T (n) = On obtient : nk n u(1) v(1) + f(k) T (n) = k=2
n n

nk

Donc si f est a croissance polynomiale alors T (n) n pour un certain > 0. Exercice 6-5 T (2p ) = 2T (2p1) + p2p donc T (2p ) = 2p T (1) + Par monotonie, il vient : T (n) = (n(ln n)2).
p

k
k=1

p2 2p1.

Exercice 6-8

229

Exercice 6-6 On pose np = 2p 1 de sorte que (np 1)/2 = 2p1 1 = np1. On peut donc tudier la relation partielle : e T (np ) = 2T (np1) + 2p 1, qui a pour solution : T (np ) = 2p T (n0) + 2k 1 2k k=0
p

p2p .

On en dduit, par monotonie : T (n) = (n ln(n)). e Exercice 6-7 Soient Trec (n), Mrec (n), Titer (n), Miter (n), les complexits temporelles et spatiales e de u_rec et u_iter. On a immdiatement Titer (n) = O(n2) et Miter (n) = O(n). e Par ailleurs il existe des constantes a et b telles que :
n n1

Trec (n) = a + bn +
k=1

Trec (n k) = a + bn +

Trec (k)
k=0

= 2Trec (n 1) + b donc Trec (n) 2n pour un certain > 0. En supposant une rcupration systmatique de la mmoire utilise par les e e e e e variables locales ds quune fonction est termine, comme u_rec nutilise quun e e nombre xe de mmoires locales (n, s, k et ladresse de retour), le nombre de e positions mmoire ncessaires au calcul de u_rec est proportionnel au nombre e e maximal dappels imbriqus, soit Mrec (n) = O(n). e Exercice 6-8 On a de manire immdiate Titer (n) = O(n) et Miter (n) = O(n). Par ailleurs Trec e e vrie la relation : e Trec (n) = a + Trec ( n/2 ) + Trec ( n/3 ). Soit > 0. En posant U(n) = Trec (n) + a on obtient : n 1 1 U( n/2 ) + U( n/3 ) 2 3

U(n)

donc si lon a 1/2 + 1/3 1 alors la fonction U est borne et lon en dduit e e que Trec (n) = O(n ). Comme lquation 1/2 + 1/3 = 1 admet une unique e racine 0 0.787, on obtient nalement Trec (n) = O(n0 ). Enn Mrec (n) est proportionnel au nombre maximal dappels imbriqus, soit Mrec (n) = O(ln n). e La mthode rcursive nave savre donc plus ecace que la mthode itrative e e e e e avec stockage des rsultats intermdiaires ! Dans le cas particulier de cette quation e e e

230

Solutions des exercices

de rcurrence, on peut obtenir un algorithme plus rapide que u_rec en remarquant e que le calcul de un ne ncessite que la connaissance des termes prcdents de la e e e forme u n/2a3b et donc quil sut de construire une matrice indexe par a et b, e de taille log2 n log3 n , pour viter le recalcul de termes. On obtient alors un e algorithme calculant un en temps O(ln2 n) et en mmoire O(ln 2 n). e Exercice 7-1 Le nombre total de nuds est n = n0 + n1 + .. . + np et le nombre de ls est f = 0 n0 + 1 n1 + . . . + p np . Donc si a nest pas vide, on a n = f + 1 soit : n0 = 1 + n2 + . . . + (p 1)np. Exercice 7-2 Sil y a n nuds alors il y a n 1 ls, donc chaque nud a en moyenne (n 1)/n ls. Le nombre moyen de ls droit dpend de larbre considr mais, si lon fait la e ee moyenne sur tous les arbres binaires de taille n, on obtient par symtrie (n1)/2n e ls droit en moyenne. Le nombre moyen de frres (moyenne sur tous les nuds e et sur tous les arbres binaires de taille n) semble plus compliqu. e Exercice 7-3 Ces ordres ne dirent que par le moment o lon traite un nud intrieur, ils e u e concident donc sur les feuilles. Exercice 7-4 La condition donne est ncessaire par dnition des ordres prxe et postxe. e e e e Pour la rciproque, considrons deux nuds x et y tels que x prcde y en ordre e e e e prxe et succde a y en ordre postxe, et soit z le premier ascendant commun e e a x et y en remontant vers la racine : si z nest gal ni a x ni a y alors x et e y appartiennent a deux branches distinctes issues de z et leurs ordres prxe et e postxe relatifs concident, cest absurde. On obtient aussi une contradiction si z = y et donc ncessairement z = x. e Exercice 7-5
(* transforme une for^t gnrale en arbre binaire *) e e e let rec bin_of_g_foret f = match f with | [] -> B_vide | G_noeud(x,fils)::suite -> B_noeud(x, bin_of_g_foret fils, bin_of_g_foret suite) ;; (* transforme un arbre gnral en arbre binaire *) e e let bin_of_g(a) = bin_of_g_foret([a]);; (* transforme un arbre binaire en for^t gnrale *) e e e let rec g_foret_of_bin a = match a with | B_vide -> [] | B_noeud(x,g,d) -> G_noeud(x, g_foret_of_bin g) :: g_foret_of_bin d ;;

Exercice 7-7

231

Exercice 7-6 Les ordres prxe sur a et a concident ; lordre postxe sur a concide avec e lordre inxe sur a ; lordre postxe sur a na pas dinterprtation simple pour a. e Exercice 7-7 successeur prxe e
let rec succ_pref(i,n) = if 2*i <= n then 2*i (* fils gauche *) else if (i mod 2 = 0) & (i+1 <= n) then i+1 (* fr`re droit *) e else if i > 1 then succ_pref(i/2, 2*(i/2)-1) (* successeur du p`re apr`s suppression des fils *) e e else failwith "plus de successeur" ;;

La correction de la fonction succ_pref se dmontre par rcurrence sur n. e e Notons fn (i) = succ pref(i, n) : f1 est manifestement correcte. Si fn est correcte (cest--dire si fn (i) est correct pour 1 i n), soit p le prdcesseur de n + 1 a e e dans la numrotation prxe : il faut montrer que fn+1 (i) = fn (i) pour 1 i n e e et i = p, que fn+1 (p) = n + 1 et que fn+1 (n + 1) = fn (p). { Si n+1 est pair, alors p = (n+1)/2, donc pour i = p et i n les rsultats des e trois tests sont inchangs si lon remplace n par n + 1, do fn+1 (i) = fn (i). e u On a aussi clairement fn+1 (p) = n + 1 et fn+1 (n + 1) = f2p1 (p) = fn (p). { Si n + 1 est impair alors p = n, donc pour i < n les rsultats des trois tests e sont l aussi inchangs et lon a fn+1 (i) = fn (i). Enn, fn+1 (p) = n + 1 et a e fn+1 (n + 1) = fn1 (n/2) = fn (n). Le calcul de succ_pref peut seectuer en mmoire constante puisque cest e une fonction rcursive terminale. Par contre le temps dexcution de succ_pref e e nest pas constant et le temps maximal de calcul de succ pref(i, n) est clairement (ln n). Cependant on constate que, lors du parcours en ordre prxe du vecteur, e un entier i est ( appel ) par succ_pref (cest--dire que lon demande un calcul e ) a ( succ pref(i, p) pour un certain entier p) au plus deux fois : une fois pour obtenir le successeur normal de i, et une deuxime fois pour obtenir le successeur ( anormal ) e ( ) succ pref(i, 2i 1) lorsque lon a ni de visiter la descendance de i sil en a une. Ceci dcoule directement de la correction de succ_pref. Donc le temps cumul de e e calcul de tous les successeurs lors de ce parcours est O(n). successeur postxe
(* cherche le noeud le plus a gauche descendant de i *) ` let rec descend(i,n) = if 2*i <= n then descend(2*i,n) else i;; let succ_post(i,n) = if i = 1 then failwith "plus de successeur" else if (i mod 2 = 1) or (i = n) then i/2 (* p`re *) e else descend(i+1,n) (* descendant gauche du fr`re droit *) e ;;

232

Solutions des exercices

Les corrections de descend et succ_post sont immdiates. Comme la fonce tion descend est rcursive terminale, descend et succ_post peuvent sexcuter en e e mmoire constante. e successeur inxe
let rec succ_inf(i,n) = if 2*i+1 <= n then descend(2*i+1,n) (* desc. gauche du fils droit *) else if i mod 2 = 0 then i/2 (* p`re *) e else if i > 1 then succ_inf(i/2,i-1) (* successeur du p`re apr`s suppression de ce fils *) e e else failwith "plus de successeur" ;;

On tablit la correction de succ_inf par rcurrence sur n de la m^me manire e e e e que celle de succ_pref. Cette fonction a elle aussi une complexit spatiale conse tante puisque rcursive terminale. e Exercice 7-8 x prcde y dans lordre prxe (inxe, postxe) inverse si et seulement si x succde e e e e a y dans lordre postxe (inxe, prxe) direct. e Exercice 7-9 parcours eectue un parcours en profondeur dabord en ordre prxe dune for^t. e e courspar eectue un parcours en largeur dabord en respectant lordre naturel des branches. Soient n le nombre de nuds et la largeur de la for^t : si le temps e de traitement dun nud est constant alors la complexit temporelle de parcours e est (n) et celle de de courspar est O(n + n ) (et (n2 ) pour un arbre binaire complet). Exercice 7-10
let rec liste_prfixe(a) = match a with e | B_vide -> [] | B_noeud(e,g,d) -> e :: ((liste_prfixe g) @ (liste_prfixe d)) e e ;;

Complexit : soit ng (i) le nombre de descendants gauche dun nud i. Le temps e de calcul de
e :: ((liste_prfixe g) @ (liste_prfixe d)) e e

non compris le temps pass dans les appels rcursifs est de la forme ng (i) + e e donc le temps total de calcul pour un arbre a de taille n est : T (a) =
ia

ng (i) + n

nh + n

o h la hauteur de larbre (en eet, dans u ng (i) un nud donn est compt e e autant de fois quil a dascendants a sa droite, donc au plus h fois). La complexit e en nh est eectivement atteinte pour un arbre en forme de peigne gauche (chaque

Exercice 7-12

233

branche droite contient un seul nud). Une meilleure solution consiste a parcourir larbre en ordre postxe inverse (cf. exercice 7-8) en accumulant les nuds rencontrs, ce qui permet de ne faire que des insertions en t^te de liste et donne une e e complexit linaire en n : e e
let rec liste_prfixe(a,l) = match a with e | B_vide -> l | B_noeud(e,g,d) -> let l = liste_prfixe(d,l) in e let l = liste_prfixe(g,l) in e e :: l ;;

Exercice 7-11 Voir le chier arbres.ml disponible sur le serveur de lINRIA :


http://pauillac.inria.fr/~quercia/automatx.tgz

Exercice 7-12 1. let rec est_sous_arbre(a,b) = match (a,b) with


| (B_vide,B_vide) -> true | B_noeud(ea,ga,da), B_noeud(eb,gb,db) -> (a = b) or est_sous_arbre(a,gb) or est_sous_arbre(a,db) | _ -> false ;;

Lgalit entre arbres est prdnie en caml (comme lgalit entre deux e e e e e e structures quelconques de m^me type non fonctionnel). Si ce ntait pas le e e cas, on pourrait la dnir par : e
let rec egal(a,b) = match (a,b) with | (B_vide,B_vide) -> true | (B_noeud(ea,ga,da),B_noeud(eb,gb,db)) -> (ea = eb) & egal(ga,gb) & egal(da,db) | _ -> false ;;

2. let rec est_inclus(a,b) = match (a,b) with


| (B_vide,_) -> true | (_,B_vide) -> false | (B_noeud(ea,ga,da),B_noeud(eb,gb,db)) -> ((ea = eb) & concide(ga,gb) & concide(da,db)) or est_inclus(a,gb) or est_inclus(a,db) and concide(a,b) = match (a,b) with | (B_vide,_) -> true | (_,B_vide) -> false | (B_noeud(ea,ga,da),B_noeud(eb,gb,db)) -> (ea = eb) & concide(ga,gb) & concide(da,db) ;;

234

Solutions des exercices

Exercice 7-13 On ne peut pas rpondre prcisment a la question car les donnes fournies (annes e e e e e de naissance et de dcs des individus) ne permettent pas de savoir dans quel ordre e e ont eu lieu les naissances et les dcs dans une m^me anne, ni a quelles dates la e e e e royaut tait eectivement en vigueur (Louis XVII, et les descendants de Charles X ee nont pas rgn car le rgime politique en vigueur alors tait le rgime rpublicain). e e e e e e Le programme ci-dessous fait abstraction des changements de rgime et suppose e que dans une m^me anne toutes les naissances ont lieu avant tous les dcs et que, e e e e en cas de dcs multiples, les individus meurent en respectant lordre dynastique. e e On parcourt larbre en ordre prxe et on imprime tous les noms dindividus e encore en vie aprs le dcs du dernier roi rencontr jusqualors. e e e e
type individu == string*int*int;; (* nom, naissance, dc`s *) e e (* imprime les noms des rois a partir de la date d *) ` (* retourne la date de dc`s du dernier roi e e *) let rec imprime(d, (G_noeud((x,_,b), fils))) = if b >= d then print_endline(x); let f = ref(fils) and d = ref(max b d) in while !f <> [] do d := imprime(!d, hd(!f)); f := tl(!f) done; !d ;;

Remarquer que larbre donn est incohrent : le cousin de Louis XV est cens ^tre e e ee n deux ans aprs le dcs de son pre, cette incohrence gure dans le document e e e e e e cit en rfrence. e ee Exercice 7-14 1. On constitue lexpression parenthse par parcours prxe inverse comme a ee e lexercice 7-10 pour garantir une complexit linaire (rappel : rev calcule e e limage dune liste de longueur n en temps (n)).
let rec exp_of_arbre a accu = match a with | G_noeud(e,f) -> Pargauche :: Etiquette(e) :: exp_of_for^t (rev f) (Pardroite :: accu) e and exp_of_for^t f accu = match f with e | [] -> accu | n::suite -> exp_of_for^t suite (exp_of_arbre n accu) e ;;

2. let rec arbre_of_expr liste = match liste with


| Pargauche :: Etiquette(e) :: suite -> let (f,reste) = for^t_of_expr(suite) in (G_noeud(e,f), reste) e | _ -> failwith "expression mal forme" e

Exercice 7-16 and for^t_of_expr liste = match liste with e | Pardroite :: suite -> ([],suite) | _ -> let (a,suite) = arbre_of_expr(liste) in let (f,reste) = for^t_of_expr(suite) in e (a::f, reste) ;;

235

arbre_of_expr(liste) vrie que le dbut de liste est lexpression dun arbre et e e renvoie cet arbre et le reste de la liste. De m^me, for^t_of_expr(liste) extrait la e e for^t reprsente par le dbut de liste et termine par une parenthse fermante, e e e e e e et renvoie cette for^t et le reste de la liste sans la parenthse fermante. La liste e e complte reprsente bien un arbre si et seulement si arbre_of_expr(liste) termine e e sans erreur et si le reste de la liste est vide.

Exercice 7-15
(* imprime une formule en plaant des parenth`ses si *) c e (* ncessaire. "p" est la priorit de loprateur e e e *) (* prcdent ou suivant. e e *) let rec imprime_avec_parenth`ses p f = match f with e | Valeur(_) -> imprime(f) | Op1(_) -> imprime(f) | Op2(_,q,_,_) -> if q < p then begin print_char (; imprime(f); print_char ) end else imprime(f) (* imprime une formule sans placer de parenth`ses autour *) e and imprime(f) = match f with | Valeur(v) -> print_string(v) | Op1(nom,g) -> print_string(nom); print_char (; imprime(g); print_char ) | Op2(nom,p,g,h) -> imprime_avec_parenth`ses p g; e print_char ; print_string(nom); print_char ; imprime_avec_parenth`ses p h e ;;

Exercice 7-16 Soit h(n) la hauteur maximale dun arbre -quilibr de taille infrieure ou gale e e e e a n. On a la relation : h(n) 1 + h( n ) et donc par rcurrence, e h(n) k + h( k n ). En prenant k = ln(n)/ ln() on obtient h(n) = O(ln n) et lingalit inverse e e est vraie pour tout arbre binaire de taille n, quil soit quilibr ou non. e e

236

Solutions des exercices

Exercice 7-17 Pour h N soit m(h) le plus petit nombre de nuds dun arbre de hauteur h quilibr a k prs. On a pour h 2 : e e e m(h) = 1 + m(h 1) + min(m(h 1), m(h 2), . .., m(h k 1)). Par consquent la fonction m est croissante sur N et m(0) = 1, m(1) = 2, donc e elle est croissante sur N. On en dduit : e m(h) = 1+m(h1)+m(hk1) 1+m(h) = (1+m(h1))+(1+m(hk1)). Soit lunique racine positive de l quation xk+1 = xk + 1 (1 < < 2). Par e rcurrence on a m(h) ch pour une certaine constante c donc : e h ln(m(h)) ln c . ln ln(n) ln c . ln

Pour un arbre binaire quilibr a k prs et a n nuds on a alors : e e e h

Exercice 7-18 1. La transformation ( ls gauche - frre droit ) met en correspondance les e ( ) arbres gnraux ordonns a n nuds et les arbres binaires a n nuds dont e e e la branche droite est vide. Donc Gn = Bn1. 2. Cest immdiat par rcurrence sur n. Lexercice 7-14 fournit par ailleurs e e un algorithme de calcul de larbre reprsent par une liste admissible de e e parenthses. e 3. On note f(i) la dirence entre le nombre de parenthses ouvrantes et le e e nombre de parenthses fermantes dans [u0, .. ., ui1]. La gure ci-dessous e prsente les graphes des fonctions f associes aux itres par T de la suite e e ee u = [ ( ) ( ( ) ) ) ( ].

Exercice 7-19

237

Soit im le premier entier i [[2, 2n]] o f atteint son minimum : T a pour u eet de diminuer im dune unit modulo 2n 1 donc il existe un unique e entier k tel que T k (u) corresponde a im = 2n, cest--dire tel que T k (u) soit a admissible. 4. Il y a Cn e e 2n1 suites u constitues de n parenthses ouvrantes et n parenthses fermantes la premire tant ouvrante, et ces suites se rpartissent en e e e e Cn /(2n 1) groupes de 2n 1 suites dduites les unes des autres par e 2n1 laction de T . Chaque groupe contient une et une seule suite admissible, donc le nombre de suites admissibles est : Cn 1 2n1 = Cn1 2n 1 n 2n2 et lon a : Gn = 1 n1 C , n 2n2 Bn = 1 Cn . n + 1 2n

Exercice 7-19 1. Soit h la hauteur de a et x un nud de profondeur h. Sil existe un nud y de profondeur h < h 1 ayant une branche vide, alors on peut ( dplacer ) ( e ) le nud x pour le mettre a la place de cette branche vide. Larbre a obtenu est un arbre binaire a n nuds tel que Le (a ) = Le (a) + h h + 1 < Le (a) donc la longueur du chemin externe de a nest pas minimale. Ceci prouve quune condition ncessaire pour que Le (a) soit minimale est que tous les e nuds de profondeur infrieure ou gale a h 2 ont deux ls, ce qui quivaut e e e a dire quil y a 2k nuds de profondeur k pour tout k [[0, h 1]]. Rciproquement, supposons cette dernire condition remplie et notons e e p le nombre de nuds de a de profondeur h. Alors n = p + 2h 1 avec 1 p 2h do h = log2 n , p = n + 1 2h et : u Le (a) = 2p(h + 1) + (2h p)h = (n + 1)h + 2p, quantit indpendante de larbre considr, et donc minimale. Lingalit e e ee e e Le (a) (n + 1) log 2 n pour un arbre binaire quelconque a n nuds est alors immdiate. e 2. On reprsente les comparaisons eectues par A lors du tri dune permutae e tion par des questions de la forme : ( est-ce que (i) (j) ? ) o i et j ( ) u sont deux entiers ( choisis ) par A en fonction des rponses obtenues pour e ( ) les questions prcdentes (lingalit dans la question pourrait ^tre stricte, e e e e e mais cest une distinction sans importance puisquon trie des listes dlments ee distincts). On construit alors un arbre de dcision a associ a A de la manire e e e suivante : la racine de a est tiquete par la premire comparaison eectue e e e e par A sur une permutation . Cette premire comparaison est indpendante e e de puisque A est un algorithme de tri par comparaisons. Les branches de larbre de dcision sont dnies rcursivement : la branche gauche est e e e

238

Solutions des exercices

larbre de dcision associ au tri de toutes les permutations pour lesquelles e e la rponse a la premire question est oui, la branche droite est larbre de e e dcision associ au tri des permutations ayant rpondu non a la premire e e e e question. Ces branches sont tiquetes par les questions poses par A pour e e e le tri des permutations considres, premire question excepte. ee e e Larbre a obtenu est un arbre ayant une branche vide pour chaque permutation de [[1, n]] : cette branche vide est issue de la dernire question e que A a pos lors du tri de , et deux permutations distinctes ne peuvent e aboutir sur la m^me branche vide sinon elles seraient indiscernables par A e et A ne serait pas un algorithme de tri. Il peut y avoir dautres branches vides correspondant aux questions pour lesquelles toutes les permutations a qui la question a t pose ont rpondu de la m^me manire, soit a larbre ee e e e e dduit de a en supprimant ces questions inutiles. Le nombre de comparaisons e eectues par A pour trier une permutation est gal a la profondeur de e e la branche vide associe a dans a , donc la complexit moyenne de A est e e au moins gale au quotient par n! de la longueur du chemin externe de a . e Comme a a exactement n! branches vides, il a au moins n! 1 nuds et, daprs la premire question, Le (a ) n! log2 (n! 1) . e e Exercice 8-1 On examine tous les nuds en ordre inxe et on vrie au fur et a mesure que les e tiquettes forment une suite croissante. e
(* vrifie que les etiquettes de a sont en ordre croissant *) e (* et suprieures a m. Retourne la plus grande etiquette *) e ` (* trouve ou m pour un arbre vide e *) let rec vrifie compare a m = match a with e | B_vide -> m | B_noeud(e,g,d) -> let g1 = vrifie compare g m in e let d1 = vrifie compare d e in e if compare e g1 = PLUSPETIT then failwith "arbre mal form" e else d1 ;; let est_de_recherche compare a = match a with | B_vide -> true | _ -> try let _ = vrifie compare a (minimum a) in true e with Failure "arbre mal form" -> false e ;;

Exercice 8-2 On peut trier une liste en construisant un arbre binaire de recherche associ et e en le parcourant en ordre inxe. Comme le parcours inxe dun arbre a une complexit linaire en la taille de larbre, on obtient ainsi un algorithme de tri e e par comparaisons de complexit Tn + O(n), do le rsultat compte tenu de la e u e complexit intrinsque dun tri par comparaisons. e e

Exercice 8-5

239

Exercice 8-3
(* place les elments de v.(a..b) dans un arbre de recherche *) e let rec construit v a b = if a > b then B_vide else if a = b then B_noeud(v.(a),B_vide,B_vide) else let c = (a+b)/2 in B_noeud(v.(c), construit v a (c-1), construit v (c+1) b) ;; let arbre_of_vect v = construit v 0 (vect_length(v)-1);;

Si T (n) est le temps dexcution de arbre_of_vect pour un sous-vecteur de e longueur n alors on a : T (n) T n1 2 +T n1 2 + K,

do lon dduit T (n) max(T (1), K)n par rcurrence sur n. Ainsi, T (n) = O(n) u e e et m^me T (n) = (n) car chaque lment du sous-vecteur est plac dans larbre. e ee e Le cas dune liste cha^ ee trie peut se traiter de m^me, mais il faut parcourir n e e la liste pour reprer llment mdian et ceci doit ^tre fait a chaque niveau de e ee e e rcursion, ce qui donne une complexit (n ln n). Il est prfrable de recopier la e e ee liste dans un vecteur avant de la mettre en arbre. Exercice 8-4 Par rcurrence sur n, on montre que larbre obtenu par insertion aux feuilles est e identique a celui obtenu par insertion a la racine en inversant lordre dinsertion des lments. ee Exercice 8-5 Pour fusionner un arbre a de racine r et un arbre b on dcoupe b en arbres major e e et minor par r et on fusionne ces sous-arbres avec les branches de b. e
let rec fusion compare a b = match a with | B_vide -> b | B_noeud(e,g,d) -> let (g,d) = dcoupe compare e b in e B_noeud(e, fusion compare g g, fusion compare d d) ;;

Complexit : soient na la taille de a et hb la hauteur de b. fusion est appel e e exactement une fois pour chaque nud et chaque branche vide de a, et le temps de dcoupage du deuxime arbre est O(hb ) (car les arbres dcoups dans b ont e e e e une hauteur infrieure ou gale a celle de b). Le temps de fusion dans le pire des e e cas est donc O(na hb ). Ce temps peut ^tre atteint si na est ngligeable devant e e hb et si la hauteur des arbres dcoups ne diminue que dune quantit borne a e e e e chaque dcoupage. e On pourrait symtriser les r^les de a et b en permutant les arbres a chaque e o appel rcursif, mais lanalyse semble dlicate et exprimentalement les arbres ainsi e e e

240

Solutions des exercices

obtenus sont trs dsquilibrs. Une solution plus s^re est de parcourir a et b en e ee e u ordre inxe et de reconstituer un arbre binaire de recherche a partir de la fusion des listes associes. e Exercice 8-6 Dans quicksort chaque lment a partir du deuxime est compar a la t^te de la ee e e e liste, puis le tri se poursuit rcursivement sur les sous-listes u et v obtenues. Dans e linsertion aux feuilles le premier lment insr est la t^te de liste et il est plac a ee ee e e la racine de larbre en construction. Tous les autres lments seront compars au ee e premier puis insrs dans la branche gauche ou droite en fonction du rsultat de la ee e comparaison. Donc les lments insrs dans la branche gauche sont exactement ee ee les lments de la liste u, et ils sont insrs dans lordre dni par u, ce qui tablit ee ee e e le rsultat par rcurrence. e e Complexit moyenne de quicksort : le nombre de comparaisons a eectuer pour e insrer un lment dans un arbre binaire de recherche est gal a la profondeur de e ee e la position dinsertion moins 1, donc le nombre total de comparaisons eectues e est gal a la somme des profondeurs de tous les nuds de larbre nal diminue e e de n. Comme la longueur moyenne du chemin interne dun arbre binaire construit alatoirement est quivalente a 2n ln(n) (cf. section 7-4), on en dduit que le e e e nombre moyen de comparaisons eectues est (n ln n). e Exercice 9-1 Oui avant simplication, non aprs. Par exemple avec e = CL[(1, x); (1, y); (1, z)], e e = y et f = CL[(1, x)] on a e < e donc CL[(1, e); (1, f)] < CL[(1, e ); (1, f)], mais aprs simplication, CL[(1, y); (1, z)] > CL[(1, x); (1, y)]. On construit un e contre-exemple similaire pour le produit, et en ce qui concerne la substitution, subs(y = x, e) > subs(y = x, e ) aprs simplication. e Exercice 9-2 Recherche dune sous-expression :
let rec figure e f = (compare e f = EQUIV) or (match e,f with | CL(e1), CL(f1) -> contient e1 f1 | PG(e1), PG(f1) -> contient e1 f1 | _ -> false) or (match e with | Fct(_,e1) -> figure e1 f | CL(l) -> figure_liste l f | PG(l) -> figure_liste l f | _ -> false) and figure_liste l f = match l with | [] -> false | (_,e)::suite -> (figure e f) or (figure_liste suite f)

Exercice 9-2

241

and contient l l | _, [] | [], _ | (a::s), (b::s) ;;

= match l,l with -> true -> false -> if b = a then contient s s else (b > a) & (contient s l)

figure_liste parcourt la liste l jusqu trouver un terme dans lequel gure f ou a avoir puis la liste, et contient dit si une liste en contient une autre, ces listes e e

tant supposes tries par ordre croissant. e e e Lalgorithme de substitution suit le m^me schma de parcours que figure, e e mais au lieu de sarr^ter sur la premire substitution russie, on doit continuer a e e e parcourir le reste de la formule pour remplacer les autres occurrences ventuelles e de f par g. On eectue une substitution simple, cest--dire que la formule obtenue a aprs substitution nest pas rexamine pour chercher de nouvelles substitutions e e e possibles. En eet, une substitution rcursive peut ne pas terminer : e
substitue x x (xx ) : x xx (xx )(x
x

((xx )(x ) )((x

x (xx )

.. ..

(* compte-rendu dune tentative de substitution *) type a compte_rendu = Succ`s of a | Echec;; e (* remplace les occurrences dans e de f par g *) let rec substitue e f g = if compare e f = EQUIV then g else let res = match e,f with | CL(e1), CL(f1) -> (match supprime e1 f1 with | Succ`s(h1) -> Succ`s(CL((1.0,g)::(subs_liste h1 f g))) e e | Echec -> Echec) | PG(e1), PG(f1) -> (match supprime e1 f1 with | Succ`s(h1) -> Succ`s(PG((1.0,g)::(subs_liste h1 f g))) e e | Echec -> Echec) | _ -> Echec in | | | | | | match res with Succ`s(h) -> h e Echec -> match e with Fct(n,e1) -> Fct(n, substitue e1 f g) CL(l) -> CL(subs_liste l f g) PG(l) -> PG(subs_liste l f g) _ -> e

242

Solutions des exercices (* idem pour une liste *) and subs_liste l f g = match l with | [] -> [] | (c,e)::suite -> (c,substitue e f g)::(subs_liste suite f g) (* supprime les elments de l dans l si l est inclus dans l *) e and supprime l l = match l,l with | _, [] -> Succ`s(l) e | [], _ -> Echec | (a::s), (b::s) -> if b = a then supprime s s else if b > a then match supprime s l with | Succ`s(l) -> Succ`s(a::l) e e | Echec -> Echec else Echec ;;

Exercice 9-3 On note T (n) le nombre maximal de nuds que peut contenir la drive dune e e expression de n nuds. La drivation de f1 .. .fn1 (x) montre que T (n) n2/2. e Supposons quil existe un nombre K 1 tel que T (k) Kk2 pour tout k strictement infrieur a n et considrons une formule e a n nuds (n 2). e e Si e = f(u) alors e = u f (u) comporte au plus K(n 1)2 + a(n 1) + b nuds o a est le nombre doccurrences de x dans f (x) et b le nombre de nuds u de f (x) autres que ces occurrences. En considrant que a et b sont borns, on e e peut supposer que a 2K et b K quitte a changer K, et donc le nombre de nuds de u f (u) est major par Kn2. e Si e = a1 e1 + . .. + ap ep alors e = a1 e1 + . . .ap ep . Soient n1, .. ., np les nombres de nuds de e1, . .., ep : n1 + .. . + np = n 1 et le nombre de nuds de e est major par : e 1 + K(n2 + . .. + n2 ) 1 p
a

1 + K(n1 + . .. + np )2

Kn2. ai eie1e, donc le i

Si e = ea1 . . .epp o ei contient ni nuds alors e = u 1 nombre de nuds de e est major par : e

1 + p + K(n2 + . .. + n2 ) + (p + 1)(n1 + .. . + np) 1 p Kn2 + Kp2 + (K n(2K 1))p + n K


(p)

K((n p)2 + p 1) + n(p + 1)

On a n2 + .. . + n2 (n p)2 + p 1 car le p-uplet (n1, . .., np ) varie dans 1 p lensemble convexe dquations n1 + .. . + np = n 1, ni 1, donc sa distance a e lorigine est maximale quand ce p-uplet est un point extrmal. Par ailleurs : e (1) = K(1 n) + n(2 K), (n 1) = (1 K)n2 + K(n 1)

Exercice 9-4

243

et ces quantits sont ngatives si K e e 2 et n 1. Comme est une fonction convexe, on a aussi (p) 0 pour K 2, p [1, n 1]. Lhypothse T (n) Kn2 e est donc rcurrente et par consquent tablie. La complexit spatiale est proe e e e portionnelle au nombre de nuds crs (m^me en tenant compte de la pile de ee e rcursion puisque sa hauteur est celle de e) donc est O(n2 ). De m^me, le temps e e de cration dun nud tant born, et la drivation se rsumant a la cration de e e e e e e nuds et a quelques calculs en nombre born par nud, la complexit temporelle e e est elle aussi O(n2 ). Exercice 9-4 Il sagit en fait dun problme de parcours de graphe o lon ne veut passer quune e u seule fois par chaque nud. Une solution nave est dajouter a la reprsentation e des nuds un indicateur mutable signalant que le nud a dj t trait : eaee e
type a rsultat = Inconnu | Calcul of a;; e e type a mexpression = { exp : a expression; mutable res : a mexpression rsultat e } and a expression = | MConst of a | MVar of string | MFct of string * (a mexpression) | MCL of (a * a mexpression) list | MPG of (a * a mexpression) list ;;

Un nud n de type mexpression est constitu de deux champs : n.exp qui e dcrit la structure algbrique de n et n.res qui contient le rsultat du calcul en e e e cours si lon est dj pass par n, ou Inconnu sinon. La drivation scrit alors : ea e e e
let fder f | "exp" -> | "ln" -> | "cos" -> | "sin" -> ....... | _ -> in {exp=r; ;; u = let r = match f with MFct("exp",u) (* exp(u) = exp(u) MPG [(-1.0,u)] (* ln(u) = u^-1 MCL [(-1.0,{exp=MFct("sin",u); res=Inconnu})] (* cos(u) = -sin(u) MFct("cos",u) (* sin(u) = cos(u) (* autres drives usuelles e e MFct(f^"",u) (* f(u) = f(u) res=Inconnu}

*) *) *) *) *) *)

let rec drive x m = match m.res with e | Calcul(r) -> r e | Inconnu -> let e = match m.exp with | MConst(_) -> MConst(0.0) | MVar(v) -> if v = x then MConst(1.0) else MConst(0.0)

244

Solutions des exercices | MFct(f,u) -> MPG [(1.0,drive x u); (1.0,fder f u)] e | MCL(liste) -> MCL(map (driveCL x) liste) e | MPG(liste) -> MCL(map (drivePG liste x) liste) e in let m = {exp=e; res=Inconnu} in m.res <- Calcul(m); m e and driveCL x (a,e) = (a,drive x e) e e and drivePG liste x (a,e) = e (a, {exp=MPG( (1.0,drive x e) :: (-1.0,e) :: liste ); e res=Inconnu}) ;;

Cette structure de donnes semble ( fonctionner ) , cest--dire que les brane a ( ) ches partages ne sont drives quune fois et le partage est conserv dans la e e e e drive, mais elle a un grave dfaut : drive x m modie physiquement m et il e e e e faut rinitialiser tous les champs res des nuds de m a Inconnu avant de calculer e une drive par rapport a une autre variable, cette rinitialisation aectant non e e e seulement m, mais aussi la drive que lon vient de calculer. Autrement dit, e e le rsultat dun calcul peut ^tre modi sans quon en soit conscient lors dun e e e calcul ultrieur ! e Une solution moins dangereuse consiste a ranger les drives que lon calcule e e avec la variable de drivation dans une table indpendante et a consulter cette e e table a chaque fois que lon veut driver une expression. La technique des tables de e hachage permet un accs aux formules mmorises en un temps moyen constant, e e e cest para^ t-il cette technique qui est utilise dans le logiciel maple. e Exercice 9-5 Soit Tn la taille maximale dun arbre tenant dans n mots mmoire. On a la relation e de rcurrence : e T1 = T2 = 1, Tn = 1 + max(pTnp1 , 1 p n 2).

En particulier pour p x, Tn e pTnp1 donc Tn cro^ au moins comme t pn/(p+1) . Ltude de la fonction p p1/(p+1) montre quelle passe par un maxie mum pour p = p0 3.59 o p0 est la racine de lquation x ln x = x + 1 et on u e n/(p +1) montre (dicilement) que Tn = O(p0 0 ) donc Tn a une croissance exponentielle. En particulier T100 > 1012, cest--dire que lon peut ( tasser ) un arbre a ( ) bien choisi de mille milliards de nuds dans 100 mots mmoire ! e Exercice 9-6
let rec simplifie e = match e with | Const(_) -> e | Var(_) -> e | Fct(f,u) -> begin match simplifie(u) with | Const(c) -> feval f c

Exercice 9-6 | u end -> Fct(f,u)

245

| CL(liste) -> begin let l1 = map simp_couple liste let l2 = dveloppeCL(l1) e let l3 = tri(l2) let l4 = constantesCL 0.0 l3 match l4 with | [] -> Const(0.0) | [(1.0,x)] -> x | _ -> CL(l4) end

in in in in

(* (* (* (*

simplifie les termes distributivit e tri et regroupement regr. les constantes

*) *) *) *)

| PG(liste) -> begin let l1 = map simp_couple liste in let l2 = dveloppePG(l1) e in let l3 = tri(l2) in let (c,f) = constantesPG 1.0 l3 in match (c,f) with | (_,[]) -> Const(c) | (0.0,_) -> Const(0.0) | (1.0,[1.0,g]) -> g | (1.0,g) -> PG(g) | (_,[1.0,CL(l)]) -> CL(distribue | (_,[1.0,g]) -> CL [c,g] | _ -> CL [c,PG(f)] end

(* (* (* (*

simplifie les facteurs distributivit e tri et regroupement regr. les constantes

*) *) *) *)

c l)

and simp_couple(a,e) = (a,simplifie e) (* eclate les CL. imbriques *) e and dveloppeCL(liste) = match liste with e | [] -> [] | (a,CL(l))::suite -> (distribue a l) @ (dveloppeCL suite) e | x::suite -> x :: (dveloppeCL suite) e (* eclate les produits imbriqus *) e and dveloppePG(liste) = match liste with e | [] -> [] | (a,PG(l))::suite -> (distribue a l) @ (dveloppePG suite) e | (a,CL([b,PG(l)]))::suite -> (a,Const(b)) :: (distribue a l) @ (dveloppePG suite) e | (a,CL([b,x]))::suite -> (a,Const(b)) :: (a,x) :: (dveloppePG suite) e | x::suite -> x :: (dveloppePG suite) e

246

Solutions des exercices

(* distribue un coefficient ou exposant *) and distribue c liste = match liste with | [] -> [] | (a,x)::suite -> (c*.a,x)::(distribue c suite) (* tri rapide, regroupement et elimination des termes nuls *) and tri(liste) = match liste with | [] -> [] | [(a,x)] -> if a = 0.0 then [] else [(a,x)] | (a,x)::suite -> let (b,l1,l2) = spare (a,[],[]) x suite in e if b = 0.0 then (tri l1) @ (tri l2) else (tri l1) @ [(b,x)] @ (tri l2) and spare (a,l1,l2) x liste = match liste with e | [] -> (a,l1,l2) | (b,y)::suite -> if y < x then spare (a,(b,y)::l1,l2) x suite e else if y > x then spare (a,l1,(b,y)::l2) x suite e else spare(a+.b,l1,l2) x suite e (* additionne les constantes *) and constantesCL c liste = match liste with | (a,Const(b))::suite -> constantesCL (a*.b +.c) suite | _ -> if c = 0.0 then liste else (1.0,Const(c))::liste (* multiplie les constantes *) and constantesPG c liste = match liste with | (a,Const(b))::suite -> constantesPG (c *. b**.a) suite | _ -> (c,liste) (* evaluation dune fonction *) and feval f u = match f with | "exp" -> Const(exp u) | "ln" -> Const(log u) | "cos" -> Const(cos u) | "sin" -> Const(sin u) ....... (* autres fonctions usuelles *) | _ -> Fct(f,Const(u)) (* fonction non evaluable *) ;;

Remarque : on trie les listes des combinaisons linaires et produits gnraliss e e e e par lalgorithme du tri rapide, modi pour regrouper en m^me temps les souse e expressions gales au pivot. La complexit de ce tri est O(n ln n) en moyenne e e seulement. Par ailleurs, on utilise la comparaison polymorphe < qui classe les constantes avant tous les autres types dexpressions, ceci parce que le constructeur Const est dclar en premier dans la dnition du type expression. On est e e e

Exercice 10-2

247

ainsi assur que tous les termes constants gureront en dbut de liste aprs classee e e ment, ce qui simplie le regroupement des constantes. Cette simplication est probablement ( non portable ) et devra ^tre revue si lon change de compilateur. e ( ) Exercice 9-7 Daprs lexercice 9-3, si e est une expression a n nuds alors e/x a O(n 2) e nuds donc la simplication de e/x prend un temps O(n4 ln n). Si lon simplie au fur et a mesure les sous-expressions que lon drive, en notant T (e) le temps de e calcul et simplication de e/x, on a : T (e) T (f(u)) T (a1 e1 + . .. + ap ep ) T (ea1 . ..epp ) 1
a

lorsque e est une constante ou une variable,

T (u) + n2 ln n, T (e1 ) + . .. + T (ep ) + n2 ln n, T (e1 ) + . .. + T (ep ) + n2 ln n.

On en dduit que T (e) = O(n3 ln n). Il semble donc prfrable de simplier e ee a chaque tape de la drivation plut^t que dattendre la n, la complexit ayant e e o e un meilleur majorant. Mais il sagit de majorants seulement et il nest pas vident e quils soient optimaux. Compte tenu du partage important de sous-expressions lors de la drivation, on peut aussi envisager de driver, simplier et mmoriser e e e chaque sous-expression, tout cela en m^me temps. e Exercice 10-1 1. Si |u| |x| alors la relation uv = xy implique que u est un prxe de x donc e il existe z A tel que x = uz. On a alors uv = uzy do v = zy. Le cas u |u| > |x| se traite de m^me. e 2. Si x et y ont m^mes longueurs on a immdiatement x = y. Sinon, supposons e e |x| > |y| : puisque xy = yx il existe z tel que x = yz et x = zy donc y et z commutent et on conclut par rcurrence sur la longueur du plus grand des e deux mots. Exercice 10-2 L1 = A aA vA iA oA nA . L2 = n +o nn +i oo nn +v ii oo nn +a vv ii oo nn o x dsigne u e toutes les lettres sauf x. Un lve ma signal lexpression plus simple : ee e L2 = a v i o n qui se dduit de la mienne par factorisations a droite successives. Montrons la e validit de cette dernire expression : soit u = ua uv uiuo un avec ux x . Si e e u contient les lettres a, v, i, o dans cet ordre alors ces lettres appartiennent respectivement aux facteurs uv ui uo un, ui uo un,uoun et un donc il ne peut y avoir de n dans u aprs le o. Rciproquement, si u ne contient pas les lettres a, e e v, i, o, n dans cet ordre, alors on note ua le plus long prxe de u sans a, ma le e suxe tel que u = uama , puis uv le plus long prxe de ma sans v, mv le suxe e correspondant, et ainsi de suite. On a donc u = ua uv uiuo unmn avec ux x et si mn = alors ma , mv, mi, mo et mn sont tous dirents de donc commencent e par les lettres a, v, i, o et n, ce qui est contraire a lhypothse faite sur u. e

248

Solutions des exercices

Exercice 10-3 Soit X lensemble des chires autres que 1 et 3 et L le langage cherch. On a : e L = (X + 3) (1 1X(X + 3) ) 1 . En eet, si u est un mot quelconque, on peut dcouper u en facteurs spars par e e e des suites de 1, cest--dire u = u1 1n1 .. .up 1np o les ui ne contiennent pas le a u chire 1, ui = pour i 2 et n1 1, .. . np1 1, np 0. Alors u L si et seulement si u2, .. . , up ne commencent pas par 3, soit u1 (X + 3) et ui X(X + 3) pour i 2. En dcoupant un mot suivant les suites de 3, on e obtient une autre expression : L = 3 ((X + 1) X33) (X + 1) .

Exercice 10-4 1. 01 2 3 4 5 6 78 9 . 2. Le langage des suites arithmtiques de raison nulle est : 0 + 1 + . .. + 9 . e Les suites arithmtiques de raison non nulle sont en nombre ni (puisque les e termes sont borns), il sut de les lister toutes. e Exercice 10-5 On note a, b, c, d, e les caractres (, ), {, } et * et a , b , c , d , e les ensembles e complmentaires dans lensemble de tous les caractres. Alors le langage des come e mentaires est dni par : e L = aeL1 eb + cd d o L1 est le langage des mots ne comportant pas la squence *). On a, comme a u e lexercice 10-3 : L1 = e (e (b + e) bb ) e . Exercice 10-6 1. Soit X solution de X = KX+L. On a donc X = K(KX+L)+L = K2 X+(K+)L puis de proche en proche : X = Kn X + (Kn1 + . . . + K + )L pour tout entier n 1. Comme K ne contient pas le mot vide, la longueur dun mot de Kn X est au moins gale a n, donc tout mot de X appartient a e lun des langages (Kn1 + . .. + K + )L pour n assez grand. Ceci prouve que X KL. Rciproquement, tout mot de K L appartient a un langage de la e forme (Kn1 + .. . + K + )L pour n convenable, donc appartient aussi a X, do X = K L. Enn, le langage K L est eectivement solution de lquation : u e KKL + L = (KK + )L = K L. Remarque : si K contient le mot vide alors K L est encore solution de lquae tion, mais il ny a plus unicit car tout langage contenant K L est aussi e solution.

Exercice 10-8

249

2. Le systme : e X = KX + LY + M Y =KX+LY +M peut ^tre rsolu par substitution. La premire quation donne : e e e e X = K (LY + M) = K LY + K M que lon reporte dans la deuxime : e Y = (K K L + L )Y + K M + M et K K L + L ne contient pas , donc on peut calculer Y puis X. Les expressions obtenues pour Y et X sont clairement rgulires. e e Exercice 10-7 En appliquant les rgles : M(N + P) = MN + MP, (N + P)M = NM + PM et e (M + N) = (M N) M , on peut liminer tous les + ou les remonter au niveau e dimbrication zro dans une expression rgulire dnissant L. On applique alors e e e e les rgles : = = , M = M = et M = M = M pour liminer les e e et internes. Comme L, il ne reste plus de au niveau zro. On obtient ainsi / e une expression rgulire pour L sous forme dune somme dexpressions dont une e e au moins nest pas car L = , donc on peut liminer tous les de cette somme. e Exercice 10-8 Soit M un langage dni par une expression rgulire de longueur n e e e 1. On montre par rcurrence sur n que si M est inclus dans un Lp alors M est ni. e Pour n = 1, M = ou M = ou M est rduit a une lettre, donc est ni. Pour e n 1, M est de lune des formes : { M = M1 + M2 : M1 et M2 sont inclus dans le m^me Lp que M et sont e dnis par des expressions plus courtes, donc sont nis. e { M = M : si M1 = alors M = est ni. Sinon, si u M1 , alors 1 |u|b |u|a = p car u M Lp et il en est de m^me pour u2 ce qui implique e p = 0. Mais le seul mot de L0 = L dont le carr soit aussi dans L0 est le mot e vide, donc M1 est rduit a et M = M = est ni. e 1 { M = M1 M2 : si M1 ou M2 est vide alors M est vide. Sinon, soient u M1 et v M2 . Comme uv Lp on a |u|b |u|a = p |v|b + |v|a = q et u est constitu dune suite de a suivie dune suite de b, donc u Lq . Comme e lentier q est indpendant de u daprs son expression en fonction de v, on a e e en fait M1 Lq et donc M1 est ni par hypothse de rcurrence. Le m^me e e e raisonnement sapplique a M2 et donc M est aussi ni.

250

Solutions des exercices

Exercice 11-1 On construit un automate simulant lvaluation de e de Horner :


0 0 1 1 1 0 0 2

ak 2k mod 3 par lalgorithme

Exercice 11-2 On interprte les mots sur {0, 1} comme les reprsentations binaires de nombres e e entiers naturels avec bit de poids faible en t^te. Notons f(x) (resp. g(x), h(x)) le e mot mis par lautomate lorsquil part de ltat 0 (resp. 1, 2) et lit le nombre x, e e complt par susamment de zros pour rejoindre ltat nal (ce nombre est bien ee e e dni puisque lautomate met 0 lorsquil lit un zro a partir de ltat 0). On a : e e e e f(0) = 0, g(0) = 1, h(0) = 2, f(2x) = 2f(x), g(2x) = 2f(x) + 1, h(2x) = 2g(x), f(2x + 1) = 2g(x) + 1, g(2x + 1) = 2h(x), h(2x + 1) = 2h(x) + 1.

Voici les premires valeurs prises par f, g, h : e x f(x) g(x) h(x) 0 0 1 2 1 3 4 5 2 3 4 5 6 6 9 12 15 18 7 10 13 16 19 8 11 14 17 20 7 8 9 10 21 24 27 30 22 25 28 31 23 26 29 32

On conjecture alors que f(x) = 3x, g(x) = 3x + 1 et h(x) = 3x + 2, et lon tablit e facilement la validit de cette conjecture par rcurrence sur x. En conclusion, e e lautomate squentiel prend un nombre x crit en binaire avec les bits de poids e e faible en t^te et complt par susamment de zros, et met le nombre 3x. e ee e e Exercice 11-3 Lautomate A B permet de faire fonctionner en parallle les automates A et B e sur un m^me mot en prenant comme tats initiaux les couples constitus dun tat e e e e initial pour A et un tat initial pour B. Les tats nals sont choisis en fonction e e du langage a reconna^ : pour LA LB un tat de A B est nal si et seulement tre e si ses composantes sont des tats nals dans A et B. De m^me pour LA LB et e e LA \ L B . Exercice 11-4 On dnit comme tats de lascenseur lagrgation des informations suivantes : e e e { sa position (nombre entier pour un tage, nombre demi entier entre deux e tages) ; e { sa direction (monte, descente, arr^t) ; e e { quels tages ont t demands et non encore servis. e ee e Lalphabet dentre est constitu de trois lettres 0, 1, 2 reprsentant chacune e e e un tage dappel (indiremment a lintrieur ou a lextrieur de la cabine), et e e e e

Exercice 11-5

251

dune quatrime lettre, , reprsentant le temps qui passe et qui sera mise a e e e intervalles rguliers pour forcer lascenseur a changer dtat lorsquil ny a pas e e dappels.
_ 0A _ 0M1 _ M1 _ 1A 2 0 _ 1M12 _ 2A 0 1 _ 1D1 _ 2D1 2 0 0 _ 1D01 0 1 _ 2D01 2 1 _ 1D0 _ M12 2 D01 _ 1 D0 2 1 _ 1D0 2 _ 2 _ D02 1 1D02 _ D012 _ 1M2 0 _ 2D0 _ 1D02 1 _ 1D012 _ 0 1D12 _ 1M02 1 _ 1M012 0 2 2 _ M12 _ 0M12 0 1 _ 1 _ 1M2 M2 0 _ 0 1M02 _ 0M2 _ M02 1 _ M012 2 _ M01

2 1

position direction destinations

Exercice 11-5 Premi`re tape : calcul des cltures par -transitions. e e o On reprsente les ensembles dtats par des vecteurs de boolens et il sagit de e e e construire une matrice m telle que m.(i).(j) vaut true si et seulement si lon peut passer de ltat i a ltat j par -transitions. Dans un premier temps on initialise m e e avec toutes les -transitions connues, puis on applique lalgorithme de Warshall pour trouver les tats accessibles par -transitions gnralises. e e e e
let cl^ture(n,liste) = o (* n = nombre dtats, liste = liste des e-transitions *) e (* retourne la matrice dincidence m *) (* cration et initialisation de la matrice dincidence *) e let m = make_matrix n n false in for i = 0 to n-1 do m.(i).(i) <- true done; do_list (fun (x,y) -> m.(x).(y) <- true) liste;

252

Solutions des exercices (* calcule la cl^ture par lalgorithme de Warshall *) o for i = 0 to n-1 do for j = 0 to n-1 do for k = 0 to n-1 do m.(j).(k) <- m.(j).(k) or (m.(j).(i) & m.(i).(k)) done done done; m (* rsultat *) e

;;

On prouve la correction de cl^ture avec linvariant de boucle : o a lentre de la boucle for i, pour tous j et k, m.(j).(k) vaut true si et e seulement sil existe un chemin par -transitions menant de ltat j a e ltat k et passant par des tats intermdiaires de numro strictement e e e e infrieur a i. e Complexit : O(n3 ) de manire vidente (si liste ne comporte pas de rptitions e e e e e et donc est de taille infrieure ou gale a n2). e e Deuxi`me tape : calcul des transitions sur lettre. e e A laide de la matrice m obtenue prcdemment et de la liste des transitions sur e e lettre fournie en argument, on construit la matrice t de transition gnralise de e e e lautomate, telle que t.(i).(a) est lensemble des tats accessibles a partir de e ltat i par transition sur la lettre a puis -transitions. e
let transitions_g(n,p,liste,m) = (* n = nombre dtats, p = nombre de lettres e (* liste = liste des transitions sur lettre (* m = matrice dincidence (* renvoie la matrice de transition gnralise e e e let t = make_matrix n p [||] in for i = 0 to n-1 do for a = 0 to p-1 do t.(i).(a) <- make_vect n false done done; (* initialise avec les transitions fournies *) do_list (fun (x,a,i) -> for y = 0 to n-1 do if m.(i).(y) then t.(x).(a).(y) <- true done) liste; t (* rsultat *) e ;;

*) *) *) *)

La complexit de cette tape est O(pn3 ) en considrant que liste contient au plus e e e pn2 triplets (cest--dire est sans rptitions). a e e

Exercice 11-5

253

Troisi`me tape : calcul des ensembles dtats accessibles depuis les e e e tats initiaux. e On applique la mthode vue en cours : ne gnrer que les ensembles dtats e e e e ncessaires. Pour cela on part de lensemble des tats initiaux (sous forme de e e vecteur de boolens) et on essaye toutes les transitions jusqu ce quil ny ait e a plus de nouvel tat cr. De faon a garder un temps daccs constant, les tats e ee c e e dj crs sont conservs dans un vecteur de longueur variable dont la taille est e a ee e double a chaque fois quil menace de dborder (ce doublement garantit un temps e e dinsertion moyen constant).
type a mmoire = { e mutable v : a vect; (* vecteur sur-dimensionn e *) mutable l : int};; (* nombre dlments prsents *) e e e (* cherche "tat" dans la mmoire "mem" et lins`re au besoin *) e e e (* "mem" est modifie sur place, renvoie lindice de "tat". *) e e let numro(mem,tat) = e e let i = ref(0) in while (!i < mem.l) & (mem.v.(!i) <> etat) do incr i done; if !i < mem.l then !i (* etat dj` enregistr *) e a e else begin (* etat non trouv, il faut linsrer *) e e if mem.l = vect_length(mem.v) then begin (* plus de place, agrandit le tampon *) let w = make_vect (2*mem.l) etat in for j = 0 to mem.l - 1 do w.(j) <- mem.v.(j) done; mem.v <- w end; (* maintenant il y a assez de place, ins`re "tat" *) e e mem.v.(mem.l) <- etat; mem.l <- mem.l + 1; !i (* indice de "tat" *) e end ;;

Il ny a plus qu calculer les sous-ensembles obtenus a partir du sous-ensemble a initial et a construire la nouvelle table de transition :
(* (* (* (* (* (* n = nombre dtats (autom. indterministe)*) e e p = nombre de lettres *) initiaux = liste des etats initiaux *) finals = liste des etats finals *) m = matrice dincidence *) t = matrice de transition gnralise e e e *)

254 (* renvoie le nombre dtats, la liste des e *) (* transitions et la liste des etats finals *) (* du nouvel automate *) let construit(n,p,initiaux,finals,m,t) =

Solutions des exercices

(* transforme "initiaux" en vecteur de boolens *) e (* et compl`te par epsilon-transitions e *) let e = make_vect n false in let f(x) = for i = 0 to n-1 do e.(i) <- e.(i) or m.(x).(i) done in do_list f initiaux; (* initialise la mmoire et la nouvelle liste e *) (* de transitions *) let mem = {v = [|e|]; l=1} and trans = ref([]) in (* boucle sur tous les ensembles dtats gnrs *) e e e e let num = ref(0) in while !num < mem.l do (* traitement de lensemble de numro !num *) e let e = mem.v.(!num) in for l = 0 to p-1 do (* calcule les etats accessibles avec la lettre "l" *) let e = make_vect n false in for i = 0 to n-1 do if e.(i) then for j = 0 to n-1 do e.(j) <- e.(j) or t.(i).(l).(j) done done; let n = numro(mem,e) in trans := (!num,l,n) :: !trans e done; incr num done; (* termin, il reste a dterminer les etats finals *) e ` e let f = ref([]) in for i = 0 to mem.l-1 do if exists (fun x -> mem.v.(i).(x)) finals then f := i :: !f done; (mem.l, !trans, !f) (* renvoie les rsultats promis *) e ;; (* dterminisation *) e let dterminise(n,p,teps,tlettre,initiaux,finals) = e let m = cl^ture(n,teps) o in let t = transitions_g(n,p,tlettre,m) in let (n,t,f) = construit(n,p,initiaux,finals,m,t) in (n,t,0,f) ;;

Exercice 11-6 (* exemple du cours : a -> 0, b -> 1 *) dterminise( 5, e (* n *) 2, (* p *) [], (* teps *) [(0,0,1); (0,0,4); (1,1,0); (1,1,2); (2,0,1); (2,0,3); (3,0,2); (3,0,4); (4,1,3); (4,1,0)], (* tlettre *) [0], (* initiaux *) [0] (* finals *) );; - : int * (int * int * int) list * int * int list = 5, (* n *) [4, 1, 3; 4, 0, 4; (* 1234 *) 3, 1, 2; 3, 0, 4; (* 023 *) 2, 1, 2; 2, 0, 2; (* rebut *) 1, 1, 3; 1, 0, 2; (* 14 *) 0, 1, 2; 0, 0, 1], (* 0 *) 0, (* init. *) [3; 0] (* final *)

255

Complexit : la recherche et linsertion ventuelle dun nouvel tat dans la mmoire e e e e prennent un temps O(N) o N est le nombre dtats dj enregistrs en supu e ea e posant que les comparaisons entre tats prennent un temps constant. La constie tution dune transition prend un temps O(n2 ) compte non tenu de la recherche de ltat cr dans la mmoire. Le temps total de cration du nouvel automate en e ee e e ngligeant les dures dinitialisation est donc O(n3 + Nn2 + N2 ) o N est le nome e u bre total dtats crs. On pourrait liminer la partie N2 due aux recherches dans e ee e la mmoire en utilisant une mmoire plus rapide (par exemple un arbre binaire e e de recherche). Notons que la technique consistant a doubler la taille du vecteur mmoire donne un temps moyen dinsertion constant, mais que cela na pas deet e sur la complexit totale puisque les recherches ont une complexit linaire. e e e Exercice 11-6 1. Soit u A : si u LA alors il existe une suite de transitions indexe par u e faisant passer A dun tat initial a un tat nal et par dnition les tats e e e e appartenant a cette suite sont accessibles et coaccessibles donc appartiennent a A . La m^me suite de transitions fait passer A dun tat initial a un tat e e e e e nal donc u LA . La rciproque est immdiate. 2. Calcul de lensemble des tats accessibles : pour chaque tat q de A on e e dtermine lensemble Sq de tous les tats accessibles a partir de q avec une e e transition ou une transition sur lettre (ensemble des successeurs de q dans A). Lensemble E des tats accessibles est alors obtenu par lalgorithme suivant : e E ; F {tats initiaux de A}. e tant que F = faire : E E F ; F retourner E.

qF

Sq \ E n tant que.

256

Solutions des exercices

Lensemble E retourn ne contient manifestement que des tats accessie e bles et si q est un tat accessible alors on montre que q est plac dans E par e e rcurrence sur la longueur dun chemin dans A reliant un tat initial a q. e e Lensemble des tats coaccessibles sobtient de m^me a partir de lensemble e e des tats nals de A et des ensembles de prdcesseurs dun tat. e e e e 3. A est dterministe si et seulement si les langages dentre des tats de A sont e e e deux a deux disjoints. 4. B et C reconnaissent le langage LA donc D et E reconnaissent le langage LA . En particulier E est quivalent a A. e Lalgorithme de dterminisation par la mthode des sous-ensembles sans e e tat rebut ne produit que des tats accessibles donc tous les tats de C sont e e e accessibles, et par consquent tous les tats de D sont coaccessibles. Les tats e e e de E sont des ensembles dtats de D non vides (car on dterminise sans tat e e e rebut), ils sont eux aussi tous coaccessibles. C tant dterministe a tats accessibles, les langages dentre des tats e e e e e de C sont deux a deux disjoints non vides donc les langages de sortie des tats e de D sont eux aussi deux a deux disjoints et non vides. Alors si {q1, . .., qn} est un tat de E, son langage de sortie dans E est la runion des langages de e e sortie dans D des tats q1 , . .., qn, elle est distincte de toute autre runion e e associe a un sous-ensemble dirent de {q1 , . .., qn}. e e 5. Soient q1 , . .., qn les tats de E et, pour chaque i, ui un mot de LA menant e E de son tat initial a qi . Soit E un automate dterministe quelconque e e e e reconnaissant LA et qi ltat de E atteint a partir de son tat initial par la suite de transitions indexe par ui. Les langages de sortie des qi dans E sont e deux a deux distincts donc il en est de m^me pour les langages de sortie des e qi dans E . En particulier les tats qi sont deux a deux distincts et E a au e moins autant dtats que E. e Ainsi E est un automate dterministe quivalent a A, minimal en nome e bre dtats. On peut dmontrer en prolongeant le raisonnement prcdent e e e e que si E a autant dtats que E alors E et E sont isomorphes par la correse pondance qi qi . Exercice 11-7 Si L = F + G(an ) alors L est rgulier. Si L est ni, L = L + (a0 ) . Si L est e inni, soit A un automate dterministe reconnaissant L. Etant dterministe, A a e e la forme suivante :
a a a a a a

On note n la longueur de la boucle, F le langage menant de ltat initial a un e tat nal avant la boucle et G le langage menant de ltat initial a un tat nal e e e intrieur a la boucle sans emprunter larc retour. Alors L = F + G(an) . e

Exercice 11-10

257

Exercice 11-8 Soit A un automate ni reconnaissant L. Si x est un tat de A, on note Ix le e langage menant de ltat initial de A a x et Fx le langage menant de x a un tat e e nal de A. Alors Ix et Fx sont rguliers (thm. de Kleene) et L est la runion e e pour tous les tats x de A des langages rguliers Ix Fx. e e e La rciproque de cette proprit est fausse, cest--dire que si L est rgulier, e ee a il nen va pas ncessairement de m^me pour L. Par exemple si L = {u2 tq u A } e e o A possde au moins deux lettres, alors L = A est rgulier mais L ne lest u e e pas car il admet une innit de langages rsiduels : (abn )1 L abn (abp )1L e e / pour n = p. Exercice 11-9 On procde par rcurrence sur la longueur dune expression rgulire dnissant e e e e e un langage L. { Si L = , L = ou L est une lettre, le rsultat est vident. e e { Si L = M + N alors pour u A on a u1L = u1M + u1 N donc M et N ayant un nombre ni de rsiduels, il en va de m^me pour L. e e { Si L = MN, notons M1 , . .. , Mp les rsiduels de M et N1 , . .. , Nq ceux e de N. Alors tout rsiduel de MN est la runion dun Mi N et de certains e e Nj , donc L a au plus p2q rsiduels (plus prcisment, si u A alors e e e w1 N). u1L = (u1 M)N +
u=vw vM

{ Si L = M , alors les rsiduels de L sont des runions de Mi M o M1 , . .., Mp e e u (w1M)M . sont les rsiduels de M : u1M = e
u=vw vM

Exercice 11-10 1. let vrifie(v) = e


let n = vect_length(v) and i = ref(0) and j = ref(0) in while (!i < n) & (v.(!i) = a) do i := !i+1 done; j := !i; while (!j < n) & (v.(!j) = b) do j := !j+1 done; (!i*2 = n) & (!j = n) ;;

2. lordinateur ne reconna^ pas le langage des parenthses embo^ ees, mais t e t seulement le langage des parenthses embo^ ees de longueur borne par sa e t e capacit mmoire et par le plus grand entier reprsentable en machine. e e e

258

Solutions des exercices

Exercice 11-11 Lautomate ci-contre reconna^ le langage L5 qui est t donc un langage rgulier (le numro dun tat core e e respond a la dirence |x|a |x|b mod 5, o x est le e u prxe dj lu du mot a analyser). Par contre, pour e ea tous n, p N avec n = p on a bn (an )1 L et bn (ap )1 L donc les rsiduels (an )1L sont deux / e a deux distincts ce qui prouve lirrgularit de L. e e
b a 4 b 3 b a a 2 a 0 a 1 b b

Exercice 11-12 1. Si n, p N alors parmi les rsiduels (an b)1 L, seul (ap b)1 L contient cp+1 , e donc ces rsiduels sont distincts et en nombre inni. e 2. On construit un automate ( additionneur ) qui eectue laddition en binaire ( ) des nombres m et n et vrie au fur et a mesure que le chire de p correse pondant est le bon. Les tats de lautomate ci-dessous sont nots N (pas de e e retenue, on attend un chire de m), Nx (pas de retenue, on a lu le chire x de m et on attend celui de n), Nxy (pas de retenue, on a lu les chires x de m et y de n) et de m^me pour R, Rx et Rxy lorsquil y a une retenue en e attente.
1 N0 0 N00 0 0 N 1 1 N10 0 1 N1 0 N11 0 R 1 1 0 R1 1 R11

Exercice 11-13 On montre que L vrie le lemme de ltoile avec n = 3. Soit u = p~ q avec e e p p A+ et q A . On dcompose u sous la forme u = xyz avec |xy| 3, |y| 1, e et xykz L pour tout k N de la manire suivante : e { Si |p| = 1 alors on choisit x = p~ , y = la premire lettre de q (qui existe p e puisque |u| 3) et z = le reste de q. Donc xyk z = p~yk z L pour tout p k N. { Si |p| 2 alors on choisit x = , y = la premire lettre de p et z = le reste e de u. On a p = yr avec r A+ donc xy0z = r~yq L, xy1z = u L et si r k 2 alors xyk z = yk r~yq L car y est une lettre. r Ainsi, L vrie le lemme de ltoile. Pourtant L nest pas rgulier, car si a, b e e e sont deux lettres distinctes alors les rsiduels Ln = (abn )1L sont deux a deux e distincts quand n dcrit N : Ln est le seul de ces rsiduels a contenir le mot bn a. e e Exercice 11-14 On montre par rcurrence sur la taille de E que lvaluation de E retourne : e e 0 si et seulement si L = , 1 si et seulement si L = , 2 si et seulement si L est ni dirent de et , e si et seulement si L est inni.

Solutions des probl`mes e

260

Solutions des problmes e

Tri par distribution

Question 1-a a0 = a mod 2. Question 1-b a/2 = a1 + 2a2 + 4a3 + . .. + 2n2an1 . Question 1-c
let rec bit_r p a = if p = 0 then a mod 2 else bit_r (p-1) (a/2);; let bit_i p a = let x = ref(a) in for i = 0 to p-1 do x := !x/2 done; !x mod 2 ;;

Remarque : il existe des mthodes de calcul du p-me bit de a en temps constant, e e par exemple : let bit p a = (a lsr p) mod 2;; Question 2-a permute(v): i 0; j 0 pour k = 0, 1, ..., n 1 faire : si v.(k) est pair alors v.(i) v.(k); i i + 1 sinon w.(j) v.(k); j j + 1 n pour pour k = 0, 1, ..., j 1 faire v.(i + k) w.(k) n pour n La validit se dmontre a laide de linvariant de boucle suivant : a lentre dans e e e la boucle, on a i + j = k et les sous-vecteurs v.(0...i 1) et w.(0...j 1) constituent une partition du sous-vecteur initial v.(0...k 1) telle que tous les lments pairs sont dans v et tous les impairs dans w, lordre initial des ee lments tant conserv dans chaque groupe. ee e e Question 2-b
let permute v = let n = vect_length(v) in let w = make_vect n 0 in let i = ref(0) and j = ref(0) in for k = 0 to n-1 do if v.(k) mod 2 = 0 then begin v.(!i) <- v.(k); i := !i+1 end else begin w.(!j) <- v.(k); j := !j+1 end; done; for k = 0 to !j-1 do v.(!i+k) <- w.(k) done ;;

Interpolation de Lagrange et multiplication rapide

261

Question 2-c a + 2b. Question 2-d Remplacer le test : if v.(k) mod 2 = 0 par : if (bit p v.(k)) = 0. Question 3-b
let tri let n let M let K for p ;; v = = = = = vect_length(v) in ref(v.(0)) in for i = 1 to n-1 do M := max !M v.(i) done; ref(0) in while !M > 0 do K := !K+1; M := !M/2 done; 0 to !K-1 do permute p v done

Question 3-c Si la suite (v0 mod 2p , .. ., vn1 mod 2p ) est croissante, alors les sous-suites de (v0 , . . ., vn1) dtermines par permute p v sont elles aussi croissantes ( modulo e e ( 2p ) puisque permute conserve lordre relatif des lments. On place en t^te de v ee e ) les lments ayant un bit de rang p nul, cest--dire ceux compris entre 0 et 2p 1 ee a modulo 2p+1 , puis les lments compris entre 2p et 2p+1 1 modulo 2p+1 donc ee la suite (v0 mod 2p+1 , . . ., vn1 mod 2p+1 ) est bien croissante. Question 3-d La complexit est O(n) ou plus prcisment O(n ln M). e e e

Interpolation de Lagrange et multiplication rapide


Question 1 On utilise lalgorithme de Horner vu en cours : Valeur(P, z) : calcule la valeur du polyn^me P au point z. o n longueur(P) r 0 pour i = n 1...0 faire : r r z + P.(i) retourner r n Validit : a la sortie de la boucle on a linvariant : r = ai + . .. + an1zni1. e Complexit : n multiplications et n additions, soit T (n) = 2n. e

262

Solutions des problmes e

Question 2 On itre le calcul de P(xi ) pour chaque i : e Liste valeurs(P, X) : calcule la liste des valeurs P(xi). n longueur(X) Y vecteur de longueur n pour i = 0...n 1 faire : Y.(i) Valeur(P, X.(i)) retourner Y n Complexit : n appels a Valeur, soit T (n) = 2n2. e Question 3 Fonctions auxiliaires de calcul sur les polyn^mes : o Combinaison(P, Q, a, b) : calcule aP + bQ p longueur(P) q longueur(Q) r max(p, q) R [|0; ...; 0|] (r fois zro) e pour i = 0...p 1 faire : R.(i) a P.(i) pour i = 0...q 1 faire : R.(i) R.(i) + b Q.(i) retourner R n Complexit : T (p, q) = p + 2q. e Produit(P, a, b) : calcule P(z) (az + b). n longueur(P) R vecteur de longueur n + 1 pour i = 1...n 1 faire : R.(i) b P.(i) + a P.(i 1) R.(0) b P.(0) R.(n) a P.(n 1) retourner R n Complexit : T (n) = 3n 1. e Formule de Lagrange On calcule pour chaque i le polyn^me Li et on cumule les polyn^mes yiLi dans le o o rsultat : e Lagrange(X, Y) : calcule le polyn^me P tel que P{X} = Y par la formule de Lagrange o n longueur(X) P [|0; ...; 0|] (n fois zro) e pour i = 0...n 1 faire : L [|Y.(i)|] (polyn^me constant) o pour j = 0...n 1 si j = i faire :

Interpolation de Lagrange et multiplication rapide

263

a 1/(X.(i) X.(j)) b X.(i) a L Produit(L, a, b) n pour j P Combinaison(P, L, 1, 1) n pour i retourner P n Complexit : dans la boucle pour j il est fait 4 oprations pour calculer a et b et e e 3k1 oprations pour calculer Produit(L, a, b) o k est la longueur courante de L. e u Cette longueur prend les valeurs 1, 2, .. ., n donc le nombre total doprations pour e calculer yiLi est :
n

(3k + 3) = 3 n2 + 9 n. 2 2
k=1

Laddition de P et yiLi co^te 3n oprations (n suraient si lon dnit une foncu e e tion daddition sans coecients). La complexit totale est donc : e T (n) = 3 n3 + 2 Formule de Newton On calcule rcursivement P et U : e Newton aux(X, Y, i) : calcule le polyn^me P pour x0 , .. ., xi et le polyn^me V(z) = (zx0). ..(zxi ). o o si i = 0 alors retourner ([|Y.(0)|], [| X.(0); 1|]) sinon : (Q, U) Newton aux(X, Y, i 1) c (Y.(i) Valeur(Q, X.(i)))/Valeur(U, X.(i)) P Combinaison(Q, U, 1, c) V Produit(U, 1, X.(i)) retourner (P, V) n sinon n Newton(X, Y) : n longueur(X) (P, V) Newton aux(X, Y, n 1) retourner P n Complexit : soit Taux (i) le temps ncessaire au calcul de Newton aux(X, Y, i). On e e a la relation de rcurrence : e Taux (0) = 1; Taux (i) = Taux (i 1) + 10i + 9.
15 2 2 n

= O(n3 ).

264

Solutions des problmes e

(en comptant 3i + 2 oprations pour la combinaison de Q et U). On en dduit e e pour n 1 :


n1

T (n) = Taux (n 1) = 1 +

(10i + 9) = 5n2 + 4n + 1 = O(n2).


i=0

Formule dAitken La formule donne contient deux appels rcursifs, ce qui conduit a calculer plusieurs e e fois les polyn^mes intermdiaires et a une complexit totale exponentielle. Il faut o e e donc mmoriser les calculs eectus : e e Aitken(X,Y) : calcule tous les polyn^mes Pa,b et renvoie le dernier. o n longueur(X) table tableau n n de polyn^mes vides o pour i = 0...n 1 faire : table.(i).(i) Y.(i) pour k = 1...n 1 faire : pour i = 0...n k 1 faire : a 1/(X.(i) X.(i + k)) b X.(i + k) a c a d X.(i) a P Produit(table.(i).(i + k 1), a, b) Q Produit(table.(i + 1).(i + k), c, d) table.(i).(i + k) Combinaison(P, Q, 1, 1) n pour i n pour k retourner T.(0).(n 1) n Complexit : le calcul de table.(i).(i + k) requiert 9k + 7 oprations (car les polye e n^mes table.(i).(i + k 1) et table.(i + 1).(i + k) sont de longueur k). On obtient : o
n1 nk1 n1

T (n) =
k=1 i=0

(9k + 7) =
k=1

(n k)(9k + 7) = 3 n3 + 7 n2 5n = O(n3 ). 2 2

Conclusion de cette question : la formule de Newton est la plus performante des trois pour le calcul des coecients du polyn^me dinterpolation. La formule o dAitken est intressante pour le calcul numrique de P(x) (dans ce cas sa come e plexit devient O(n2) car les appels a Produit et Combinaison sont remplacs e e par un nombre constant doprations complexes). La formule de Lagrange peut e aussi ^tre utilise pour un calcul numrique, mais elle prsente linconvnient par e e e e e rapport aux autres de ne pas ^tre volutive, cest--dire que les calculs faits ne e e a peuvent pas ^tre rutiliss si lon ajoute des points dinterpolation. e e e Question 4-a Soit x = xk : si k est pair alors xn/2 = 1 et P0 (x) = yk par dnition de P0. Si e k est impair alors xn/2 = 1 et P1(xe2i/n) = P1 (xk1) = yk par dnition de e P1 . Donc le polyn^me propos interpole bien Y pour la liste X et son degr est au o e e plus n 1 car ceux de P0 et P1 sont majors par n/2 1. e

Interpolation de Lagrange et multiplication rapide

265

Question 4-b Interpole(Y) : calcule le polyn^me dinterpolation de Y aux racines de lunit. o e n longueur(Y) si n = 1 retourner [|Y.(0)|] sinon : diviser Y en deux parties Y0 , Y1 comme dni dans lnonc e e e P0 Interpole(Y0) P1 Interpole(Y1) calcul du polyn^me P1 (xe2i/n) o z 1 pour k = 0...n/2 1 faire : P1 .(k) P1 .(k) z z z e2i/n n pour k combine P0 et P1 R vecteur de longueur n pour k = 0...n/2 1 faire : R.(k) (P0 .(k) + P1 .(k))/2 R.(k + n/2) (P0.(k) P1 .(k))/2 n pour k retourner R n sinon n Question 4-c Si lon excepte les appels rcursifs, Interpole eectue un nombre doprations e e complexes linaire en n. On a donc lquation T (2 ) = 2T (21 ) + a2 + b que e e lon rsout en : e T (21 ) T (2 ) = + a + b2 , 2 21 T (1) T (2 ) + ( 1)a + b( 1 2 ), = 2 2 1 T (2 ) a2 = O(n ln n) pour n . Question 4-d Le principe est le m^me : on divise P en deux polyn^mes e o P(z) = a0 + a1z + . .. + an1 zn1 = (a0 + a2 z2 + . .. + an2zn2) + z(a1 + a3 z2 + .. . + an1zn2) = P0(z2 ) + zP1(z2) o P0, P1 sont deux polyn^mes de longueur n/2. Pour calculer la liste (P(e2ik/n)), u o il sut de conna^ les listes (P0 (e4ik/n)) et (P1(e4ik/n)), cest--dire les listes tre a des valeurs de P0 et P1 aux racines n/2-mes de lunit. A partir de ces deux listes, e e on obtient une valeur P(e2ik/n) en un temps constant (deux oprations) donc le e e ) ( entrelacs ) : (

266

Solutions des problmes e

temps total de calcul suit une relation de rcurrence similaire a celle tablie pour e e lalgorithme dinterpolation. Question 5 On calcule les listes des valeurs de P et Q pour les racines 2n-mes de lunit e e en O(n ln n) oprations, on multiplie terme a terme ces deux listes en O(n) e oprations, ce qui donne la liste des valeurs du produit PQ pour les racines 2n-mes e e de lunit. Cette liste permet de reconstituer PQ par interpolation en O(n ln n) e oprations. e Le choix des racines de lunit permet donc de multiplier deux polyn^mes e o en O(n ln n) oprations, au lieu de n2 multiplications et n(n 1) additions come plexes pour la multiplication par distributivit et (nlog2 (3) ) pour la multiplication e rcursive de Karatsuba. Cependant cet algorithme, appel multiplication par e e transformation de Fourier rapide, ncessite deectuer des calculs en nombres e complexes, donc approchs. On obtient alors une approximation du produit. Sil e sagit de polyn^mes a coecients entiers, sachant que le rsultat est a coecients o e entiers on peut arrondir le rsultat approch : Knuth dmontre que lincertitude e e e sur les coecients de PQ est de lordre de (n ln n) o est lincertitude sur une u opration. Donc, pour n ln n e 1018, il sut de faire les calculs ( avec une ving( taine de chires aprs la virgule ) pour ^tre s^r davoir un arrondi correct. Par e e u ) ailleurs, le gain en vitesse nest rel que pour de trs grandes valeurs de n compte e e tenu des complications de lalgorithme et de la ncessit de garantir la prcision des e e e calculs intermdiaires. La multiplication par transformation de Fourier rapide e est utilise pour les calculs sur des trs grands nombres (plusieurs milliers de e e chires).

Plus longue sous-squence commune e

Question 1-a On parcourt simultanment A et C en e quil appara^ dans A. t

( retirant ) un lment de C a chaque fois ( ) ee

let rec sous_squence (a,c) = e if c = [] then true else if a = [] then false else if (hd a) <> (hd c) then sous_squence (tl a, c) e else sous_squence (tl a, tl c) e ;;

Validit : lorsque C ou A est vide alors sous_squence renvoie immdiatement e e e le rsultat correct. Supposons C et A non vides : si C est une sous-squence e e

Plus longue sous-squence commune e

267

de A alors il existe une suite dindices 0 i0 < i1 < . .. < iq1 < n tels que e ck = aik pour tout k. Donc, si c0 = a0 , alors i0 1 et C est une sous-squence de (a1 , . .., an1). Lorsque c0 = a0 on a (c1 , .. ., cq1) = (ai1 , . . ., aiq1 ) qui est une sous-squence de (a1 , . .., an1) car i1 1. e Rciproquement, si c0 = a0 et si (c1 , .. ., cq1) est une sous-squence de e e (a1 , . .., an1) alors il existe des indices 1 i1 < . .. < iq1 < n tels que ck = aik pour k 1, et cette relation a encore lieu pour k = 0 en posant i0 = 0, donc C est une sous-squence de A. Enn, si c0 = a0 et C est une sous-squence de e e (a1 , . .., an1) alors C est videment une sous-squence de A. e e Ceci prouve que, si lappel sous_squence a c termine, alors il renvoie le bon e rsultat. Et il y a terminaison car la longueur de largument a diminue dune unit e e a chaque appel rcursif. e Question 1-b On reprend lalgorithme prcdent en accumulant les indices des lments de A e e ee non apparis a ceux de C. La construction de la liste des indices nest pas termine e e lorsque C = () car il faut constituer la liste des indices des lments restant dans A. ee
let rec indices_`_supprimer(a,c,i) = a if a = [] then [] else if (c = []) or ((hd a) <> (hd c)) then i :: (indices_`_supprimer(tl a, c, i+1)) a else indices_`_supprimer(tl a, tl c, i+1) a ;; (* utilisation *) indices_`_supprimer(a,c,0);; a

Question 2-a Si ai1 = bj1 : si C = (c0 , .. ., cq1) est une plsc a Ai1 et Bj1 alors la liste C = (c0 , .. ., cq1, ai1) est une sous-squence commune a Ai et Bj . Ceci prouve e que i,j 1 + i1,j1. Si C = (c0 , . .., cq1) est une plsc a Ai et Bj avec q 2 alors C = (c0 , .. ., cq2) est une sous-squence commune a Ai1 et Bj1 , quelle e que soit la valeur de cq1. Ceci prouve que i1,j1 2 i,j 1 dans le cas i,j et lingalit est galement vraie si i,j = 1. e e e Si ai1 = bj1 : toute plsc a Ai1 et Bj est une sous-squence commune a Ai e et Bj donc i,j . De m^me, i,j e et donc i,j max( i,j1, i1,j). i1,j i,j1 Inversement, si C = (c0 , .. ., cq1) est une plsc a Ai et Bj , alors cq1 = ai1 ou cq1 = bj1 donc C est une sous-squence commune a Ai1 et Bj ou a Ai et Bj1. e Dans le premier cas on obtient : i,j et dans le second cas : i,j i1,j i,j1 do, dans tous les cas : i,j max( i,j1, i1,j). u Question 2-b On choisit ici de reprsenter A et B par des vecteurs pour accder en temps e e constant a ai1 et bj1 :

268

Solutions des problmes e let matrice_plsc(a,b) = let n = vect_length(a) and p = vect_length(b) in let l = make_matrix (n+1) (p+1) 0 in for i = 1 to n do for j = 1 to p do (* invariant de boucle : ici, tous les coefficients *) (* l.(u).(v) sont corrects si u < i ou (u = i et v < j) *) if a.(i-1) = b.(j-1) then l.(i).(j) <- 1 + l.(i-1).(j-1) else l.(i).(j) <- max l.(i-1).(j) l.(i).(j-1) done done; l ;;

Validit : a la suite de la cration de l on a l.(0).(j) = l.(i).(0) = 0 pour tous e e i et j. Ceci montre que la proprit nonce en commentaire est vrie lors ee e e e e de la premire entre dans la boucle interne (i = j = 1). Linvariance de cette e e proprit rsulte de ce que lon applique les formules du 2a et de ce que les valeurs ee e l.(i1).(j1), l.(i1).(j) et l.(i).(j1) ont t correctement calcules auparavant. ee e Complexit : le temps de cration de l est proportionnel a sa taille, soit O(np). e e Le temps de calcul dun coecient l.(i).(j) est born (un accs a a, un accs a b, e e e une comparaison, une addition ou un calcul de max et une aectation a un lment ee de tableau, plus quelques soustractions pour calculer i 1 et j 1) et chaque coecient de l est calcul au plus une fois, donc le temps de remplissage de l est e aussi O(np). Remarque : si A et B sont reprsentes par des listes cha^ ees et non des vecteurs, e e n on peut encore produire la matrice l en O(np) oprations car ces listes sont pare courues squentiellement : e
let matrice_plsc(a,b) = let n = list_length(a) and p = list_length(b) in let l = make_matrix (n+1) (p+1) 0 in let a = ref(a) in for i = 1 to n do let b = ref(b) in for j = 1 to p do (* invariant de boucle : ici, tous les coefficients *) (* l.(u).(v) sont corrects si u < i ou (u = i et v < j) *) if hd(!a) = hd(!b) then l.(i).(j) <- 1 + l.(i-1).(j-1) else l.(i).(j) <- max l.(i-1).(j) l.(i).(j-1); b := tl(!b) done; a := tl(!a) done; l ;;

Plus longue sous-squence commune e

269

Question 2-c = l.(n).(p) est la longueur dune plsc a A et B. Si an1 = bp1 alors daprs e 2a il existe une plsc a A et B obtenue en plaant an1 au bout dune plsc a c An1 et Bp1 . Si an1 = bp1 , alors on cherche une plsc a An1 et Bp ou a An et Bp1 suivant que l.(n 1).(p) > l.(n).(p 1) ou non. On traite ici le cas dune reprsentation de A et B par des vecteurs : e
let plsc(a,b,l) = let n = vect_length(a) and p = vect_length(b) in let q = l.(n).(p) in let c = make_vect q a.(0) in let i = ref(n) and j = ref(p) and k = ref(q) in while !k > 0 do if a.(!i-1) = b.(!j-1) then begin c.(!k-1) <- a.(!i-1); i := !i - 1; j := !j - 1; k := !k - 1 end else if l.(!i-1).(!j) > l.(!i).(!j-1) then i := !i-1 else j := !j-1 done; c ;;

Question 3-a On cre deux vecteurs boolens, EA et EB , indexs par les lments de E (convertis e e e ee en nombres entiers au besoin) tels que : { EA .(x) = true si est seulement si x appara^ dans A ; t { EB .(x) = true si est seulement si x appara^ dans B. t Ensuite on parcourt A en extrayant les lments x tels que EB .(x) vaut true et on ee parcourt B en extrayant les lments x tels que EA .(x) vaut true. Ceci donne les ee listes A et B .
(* On suppose les elments de E sont numrots de 0 a r-1 *) e e e ` let cre_tableau(a) = e let e_a = make_vect r false in for i = 0 to vect_length(a) - 1 do e_a.(numro(a.(i))) <- true e done; e_a ;;

270 let extrait(a,e_b) = let a = make_vect (vect_length a) a.(0) in let k = ref 0 in for i = 0 to vect_length(a) - 1 do if e_b.(numro(a.(i))) then begin e a.(!k) <- a.(i); k := !k + 1 end done; sub_vect a !k ;;

Solutions des problmes e

Question 3-b On passe en revue les listes At et Bt comme pour une fusion, en notant les indices des lments communs a A et B. On constitue alors A et B a partir de ces notes. ee
let intersection(a,b,at,bt) = let let and let n = vect_length(a) and p = vect_length(b) in dans_b = make_vect n false dans_a = make_vect p false in i = ref 0 and j = ref 0 in

while (!i < n) & (!j < p) do if a.(at.(!i)) = b.(bt.(!j)) then begin (* elment commun *) e let x = a.(at.(!i)) in (* note tous les elments de a egaux a cet elment *) e ` e while (!i < n) & (a.(at.(!i)) = x) do dans_b.(at.(!i)) <- true; i := !i+1 done; (* note tous les elments de b egaux a cet elment *) e ` e while (!j < p) & (b.(bt.(!j)) = x) do dans_a.(bt.(!j)) <- true; j := !j+1 done end else if a.(at.(!i)) < b.(bt.(!j)) then i := !i + 1 else j := !j + 1 done; (dans_a, dans_b) ;;

Plus longue sous-squence commune e let extrait(a,dans_b) = let a = make_vect (vect_length a) a.(0) in let k = ref 0 in for i = 0 to vect_length(a) - 1 do if dans_b.(i) then begin a.(!k) <- a.(i); k := !k + 1 end done; sub_vect a !k ;;

271

Question 4 Premier cas : soit r le cardinal de E. La cration de e_a se fait en O(r) oprations, e e le remplissage en O(n) oprations et lextraction de a a partir de a et e_b en O(n) e oprations. La complexit du pr-traitement est donc O(n + p + r). e e e Second cas : le calcul de at a partir de a se fait en O(n ln(n)) oprations si lon e emploie un algorithme de tri par fusion (le quicksort a aussi cette complexit, mais e en moyenne seulement) ; le calcul des vecteurs dans_a et dans_b a la complexit e dune fusion : O(n + p) et lextraction de a a partir de a et dans_b se fait en O(n) oprations. La complexit du pr-traitement est donc O(n ln(n) + p ln(p)). e e e En supposant n = p et r petit devant n dans 3a, on a donc une complexit de e pr-traitement O(n) ou O(n ln(n)) ce qui est ngligeable devant la complexit de e e e calcul de la plsc : O(n2 ). On peut donc toujours procder au pr-traitement, ce e e nest asymptotiquement pas pnalisant. Cependant, lutilit de ce pr-traitement e e e est discutable : dans le cas 3a, si E est petit et A, B sont grandes, alors il est probable que presque tous les lments de E gurent au moins une fois dans chacune ee des listes, et le pr-traitement ne diminue pas notablement les longueurs des listes e a traiter. Dans le cas 3b, si A et B sont alatoires, indpendantes, et de longueur e e petite devant card(E) alors elles sont probablement ( presque disjointes ) et le ( ) pr-traitement peut ^tre ecace. Par contre, si A et B ne sont pas indpendantes e e e (en particulier sil sagit de versions successives dun chier), il est probable que le pr-traitement ne permettra de retirer que quelques lments seulement. e ee Enn, si n et p sont ( petits ) , le temps de pr-traitement ne peut plus ^tre e e ( ) considr comme ngligeable. . . En conclusion, je dconseille ce pr-traitement. ee e e e Complment e Le systme Unix possde une commande diff listant les dirences entre e e e deux chiers texte suivant un algorithme inspir de la recherche dune plsc : la e distance entre deux chiers A et B considrs comme des listes de lignes est le ee nombre dlments de A et de B ne faisant pas partie dune plsc a A et B. Elle ee est note d(A, B). On dtermine cette distance en comparant A et B par les deux e e bouts : on progresse alternativement dune unit de distance a partir des dbuts e e de A et B, puis dune unit a partir des ns de A et B, jusqu un point milieu, e a cest--dire un couple (i, j) tel que d(Ai , Bj) = d(A, B)/2 . Le nombre de couples a

272

Solutions des problmes e

(i, j) examins au cours de cette recherche est major par (n + p)d(A, B) et il e e nest pas ncessaire de construire une matrice de taille np pour cela, il sut e de disposer de O(d(A, B)) positions mmoire. e On peut alors obtenir rcursivement une plsc a A et B en concatnant une e e plsc a Ai et Bj avec une plsc a A \ Ai et B \ Bj . Le temps de calcul dune plsc suivant cet algorithme (dcouvert indpendamment par EW. Myers (1986) et e e E. Ukkonen (1985)) est O(nd(A, B)) pour n = p. Pour plus de renseignements, consulter laide Emacs sur la commande diff et le code source (en C) de GNU-di.

Arbres de priorit quilibrs ee e

Question 1 Par rcurrence sur H(a). e Question 2


let rec insertion(a,e) = match a with | B_vide -> B_noeud(e,B_vide,B_vide) | B_noeud(r,g,d) -> if e >= r then B_noeud(e, insertion(d,r), g) else B_noeud(r, insertion(d,e), g) ;;

Correction : insertion(a, e) renvoie un APE contenant la seule tiquette e lorsque e a est vide. Si insertion(a, e) renvoie un rsultat correct pour tout arbre de e hauteur strictement infrieure a h, alors pour un arbre a = B noeud(r, g, d) de e hauteur h on insre la plus petite des tiquettes e ou r dans la branche droite, ce e e qui fournit un nouvel APE d correct par hypothse de rcurrence, puis on rene e voie a = B noeud(max(e, r), d , g). Ceci est un arbre de priorit car max(e, r) e est la plus grande tiquette gurant dans a et d , g sont des APE. De plus, e N(d ) = N(d) + 1 est compris entre N(g) et N(g) + 1, donc les deux branches ont m^me nombre de nuds a une unit prs, celle de gauche (d ) tant la plus e e e e lourde en cas dingalit. e e Complexit : O(H(a)). e

Arbres de priorit quilibrs ee e

273

Question 3
let rec transforme(a1) = match a1 with | B_vide -> a1 | B_noeud(e,B_vide,B_vide) -> a1 | B_noeud(e,g,d) -> (* compare les racines de g et d si elles existent *) let g_plus_grand_que_d = match (g,d) with | (B_noeud(x,_,_), B_noeud(y,_,_)) -> x >= y | _ -> true (* une des branches est vide, cest donc d *) in (* compare e au plus grand fils *) if g_plus_grand_que_d then match g with | B_vide -> a1 | B_noeud(e,g,d) -> if e >= e then a1 else B_noeud(e, transforme(B_noeud(e,g,d)), d) else match d with | B_vide -> a1 | B_noeud(e,g,d) -> if e >= e then a1 else B_noeud(e, g, transforme(B_noeud(e,g,d))) ;;

Correction : par rcurrence sur la hauteur de a1 comme a la question prcdente. e e e Complexit : O(H(a)). e Question 4-a Par rcurrence sur H(a). e Question 4-b
let rec retire_gauche(a) = | B_vide | B_noeud(r,B_vide,B_vide) | B_noeud(r,g,d) ;; let extraction(a) = let (a,e) = retire_gauche(a) in match a with | B_vide -> (a,e) | B_noeud(r,g,d) -> (transforme(B_noeud(e,g,d)), r) ;; match a with -> failwith "arbre vide" -> (B_vide,r) -> let (g,e) = retire_gauche(g) in (B_noeud(r,d,g),e)

Complexit : O(H(a)). e

274

Solutions des problmes e

Question 5 Le temps de constitution de lAPE vrie la relation de rcurrence : e e Tn = Tn1 + O(ln(n)). Donc Tn = O(ln 1 + ln 2 + .. . + ln n) = O(n ln n). Le temps dextraction de tous les noeuds de lAPE vrie la m^me relation, donc est aussi O(n ln n) et le e e temps de constitution de la liste nale, non compris les extractions dans lAPE, est O(n) car on eectue des insertions en t^te de liste. Le temps total du tri est e donc O(n ln n).

Compilation dune expression


Question 1 Lordre des oprations est, compte tenu de la priorit de sur + et des parenthses : e e e , , , +. Les oprandes de chaque soustraction doivent ^tre empils juste avant e e e lopration de soustraction et la multiplication doit ^tre eectue immdiatement e e e e aprs les soustractions. Les liberts dans le choix du code compil portent donc e e e sur le fait que chaque opration peut ^tre code de manire directe ou inverse. e e e e Ceci fait au total 16 possibilits de compilation (64 si lon considre que + et e e sont commutatives). Le code suivant nutilise que trois niveaux de pile :
empile_v b; empile_v c; binaire ; empile_v d; empile_v e; binaire ; binaire ; empile_v a; binaire_inv +.

Ce code est optimal puisque la multiplication doit immdiatement suivre la e deuxime soustraction et donc il faut au moins trois oprandes dans la pile avant e e deffectuer la deuxime soustraction. e Question 2 Si f = op1 (g) alors N(f) = N(g). Si f = g op2 h, il y a deux manires de compiler f : e { < calcul de g >; < calcul de h >; binaire op2 . { < calcul de h >; < calcul de g >; binaire_inv op2 . Le nombre de niveaux de pile utilis est max(N(g), 1 + N(h)) dans le premier cas e et max(N(h), 1 + N(g)) dans le second cas. On a donc : N(f) = min(max(N(g), 1 + N(h)), max(N(h), 1 + N(g))) si N(g) < N(h) N(h) = N(g) si N(g) > N(h) 1 + N(g) si N(g) = N(h).

Compilation dune expression

275

Question 3-a Algorithme : { une constante c est compile en empile_c c ; e { une variable v est compile en empile_v v ; e { pour compiler op1 (g), compiler g et insrer unaire op1 en queue du code e obtenu ; { pour compiler g op2 h, compiler sparment g et h, soient g et h les e e codes obtenus, puis comparer N(g) et N(h). Si N(g) < N(h) alors retourner le code : h ; g ; binaire_inv op2 , sinon retourner le code : g ; h ; binaire op2 . Le calcul de N(g) et N(h) dans le dernier cas peut ^tre eectu par parcours e e des formules g et h en appliquant les relations obtenues a la question prcdente. e e Le programme ci-dessous vite le double parcours en retournant a la fois le code e compil et le nombre de niveaux de pile utiliss par ce code. e e
type a | Const | Var | Op1 | Op2 ;; formule = of a of string of string * (a formule) of string * (a formule) * (a formule)

type a instruction = | Empile_c of a | Empile_v of string | Unaire of string | Binaire of string | Binaire_inv of string ;; let rec compile(f) = (* retourne le code de f et N(f) *) match f with | Const(c) -> ([Empile_c c], 1) | Var(v) -> ([Empile_v v], 1) | Op1(op1,g) -> let (code,n) = compile(g) in (code @ [Unaire op1], n) | Op2(op2,g,h) -> let (codeg,ng) = compile(g) and (codeh,nh) = compile(h) in if ng > nh then (codeg @ codeh @ [Binaire op2], ng) else if ng < nh then (codeh @ codeg @ [Binaire_inv op2], nh) else (codeg @ codeh @ [Binaire op2], 1+ng) ;;

276

Solutions des problmes e

Question 3-b On peut transformer la formule a compiler en un arbre dinstructions par un premier parcours en profondeur, chaque nud tant remplac par linstruction e e correspondante, puis mettre ces instructions en liste par un deuxime parcours en e profondeur en insrant les instructions en t^te dune liste initialement vide. e e Question 4 Soit k(n) le nombre minimal de nuds dune formule non calculable avec n niveaux de pile. Pour n 2, une telle formule est de la forme f = g op2 h avec N(g) n, N(h) n (sinon f nest pas minimale) et donc N(g) > n 1, N(h) > n 1 (sinon N(f) n). On en dduit k(n) = 2k(n 1) + 1 et k(1) = 3 do k(n) = 2n+1 1. e u En particulier, k(8) = 511.

Recherche dune cha de ne caract`res dans un texte e


Question 1-a
let position(t,m) = let i = ref 0 and j = ref 0 while (!j < vect_length(m)) if m.(!j) = t.(!i + !j) then j := !j + 1 else begin i := !i + 1; j done; if !j = vect_length(m) then ;; in & (!i + !j < vect_length(t)) do

:= 0 end !i else failwith "non trouv" e

Remarque : on peut remplacer le test : !i + !j < vect_length(t) par le test : !i < vect_length(t) - vect_length(m) cette dernire expression tant calcule en e e e dehors de la boucle. Complexit : i peut aller jusqu |t| |m| 1 et pour chaque valeur de i, j peut e a aller de 0 a |m| 1 (cas o cest la dernire comparaison qui choue, par exemple u e e m = aaaab et t = aaa.. .aaa) et il est fait un nombre constant doprations pour e chaque couple (i, j) donc le nombre total doprations dans le pire des cas est e O((|t| |m|)|m|) = O(|t||m|). Question 1-b Oui. Lorsquune comparaison choue on a mj = ti+j et la premire lettre de m e e ne peut pas ^tre retrouve dans t avant la position i + j puisque les positions pre e e cdentes contiennent les lettres m1, . .. , mj1. On peut donc remplacer linstruce tion i := !i + 1 par i := !i + !j + 1 dans le programme prcdent. De toutes e e faons, chaque lettre de t ne sera examine quau plus deux fois (que lalgorithme c e soit modi ou non), donc la complexit de la recherche devient O(|t|). e e Remarque : il nest pas ncessaire que toutes les lettres de m soient distinctes pour e obtenir cette situation, il sut en fait que la premire lettre de m soit distincte e de toutes les autres.

Recherche dune cha^ de caractres dans un texte ne e

277

Question 1-c Pour k, i N on note N(k, i) le nombre de mots m de longueur pour lesquels on eectue k comparaisons de lettres dans () avant de conclure a la prsence de m e dans t ou de passer a la position suivante i + 1. Alors : (t, ) = On a : N(k, i) = 1 N(k, i) = (|A| 1)|A| N(k, i) = |A| k N(k, i) = 0 Do : u (t, )
|t|1 i=0 1 k=0 k

1 |A|

|t|1 i=0 k=0

kN(k, i).

si k = , si k < et i + k < |t|, si k < et i + k = |t|, sinon.

k(|A| 1)|A|k + |A|


k=0

|t|(|A| 1) Question 1-d

k|A|k

|A| |t|. |A| 1

Par un calcul similaire on obtient ( , m) ~ Question 2-a automate non dterministe : e


0 a a,b,c 1 a 2 b 3

|A| |m|. |A| 1

aprs dterminisation : e e
c b,c 0 a b,c 01 a 012 a b b,c 03 a b a a b,c 014 a 0125 c b,c 06

278

Solutions des problmes e

Question 2-b On convient de reprsenter Am par une matrice de transition a telle que a.(i).(j) e donne le numro de ltat succdant a ltat i lorsquon lit la lettre j, et par un e e e e vecteur de boolens f tel que f.(i) = true si et seulement si ltat i est un tat nal. e e e Ltat initial de Am est par convention ltat 0 (i, j sont des entiers, lautomate e e est suppos dterministe complet). e e
let position a f m texte = let etat = ref 0 (* numro de ltat courant *) e e and i = ref 0 in (* indice dans le texte *) while not(f.(!tat)) & (!i < vect_length(texte)) do e etat := a.(!tat).(texte.(!i)); e i := !i + 1 done; if f.(!tat) then !i - vect_length(m) - 1 else failwith "non trouv" e e ;;

La complexit de position est O(|t|) puisque les accs a la matrice a et au vecteur e e f se font en temps constant. Question 2-c On montre par rcurrence sur |t| que Am passe de ltat a ltat S(m, t) en lisant e e e le texte t. Donc un mot t est reconnu par Am si et seulement si S(m, t) = m, soit si et seulement si m est un suxe de t, soit enn si et seulement si t A m. Question 2-d Le premier cas est vident. Dans le deuxime cas, ua nest pas un prxe de m e e e donc il faut retirer au moins une lettre a ua pour obtenir un prxe de m, et par e consquent S(m, ua) = S(m, u a). Notons v = S(m, u ) et w = S(m, u a) : il faut e dmontrer que S(m, va) = w. Pour cela on remarque que S(m, va) est un suxe e de u a en m^me temps prxe de m donc, par dnition de w, S(m, va) est un e e e suxe de w. Si w = on obtient lgalit cherche et sinon, w = w a et w est un e e e suxe de u en m^me temps prxe de m donc cest un suxe de v et w = w a e e est un suxe de va en m^me temps prxe de m, donc enn w est un suxe de e e S(m, va), ce qui achve la dmonstration. e e Question 2-e calcul de la premire ligne e Pour chaque lettre a = m.(0) : M.(0).(a) 0. Pour a = m.(0) : M.(0).(a) 1. calcul de proche en proche v 0. Pour u = 1, ..., |m| 1 : pour chaque lettre a = m.(u) : M.(u).(a) M.(v).(a). pour a = m.(u) : M.(u).(a) u + 1; v M.(v).(a). Fin pour. dernire ligne e Pour chaque lettre a : M.(|m|).(a) M.(v).(a). Complexit : O(|m||A|) = O(|m|). e

Recherche dune cha^ de caractres dans un texte ne e

279

Exemple : m a a b a a c u 0 1 2 3 4 5 6 v 0 1 0 1 2 0 a 1 2 2 4 5 2 1 b c 0 0 0 0 3 0 0 0 0 0 3 6 0 0

Question 2-f Comme tout automate dterministe reconnaissant Lm a au moins autant dtats e e que Lm a de rsiduels, il sut de prouver que Lm a au moins |m| + 1 rsiduels e e distincts. Soient u et uv deux prxes de m (m = uvw) avec v = . Alors le e langage rsiduel de uv contient w ce qui nest pas le cas du langage rsiduel de u. e e Donc les langages rsiduels des prxes de m sont deux a deux distincts et il y en e e a |m| + 1. Question 3-b Comme k p < k, on a p 1 donc le mot m est dcal vers la n de t. Il e e faut seulement justier que si p > 1 on ne risque pas de manquer des positions dapparition de m dans t : si on dcale m de q positions avec q < p alors la lettre e akq est mise en correspondance avec bi+k donc il y a non concordance. La complexit dans le pire des cas est la m^me quau 1-a car on peut seulee e ment armer que k 0 et p 1 donc on peut avoir a comparer chaque lettre de m avec chaque lettre de t (sauf pour les dernires lettres de t). e Question 3-c De faon a viter de recalculer lentier p a chaque comparaison ngative, on prcalc e e e cule la fonction de dcalage dans une matrice mat indexe par les positions dans m e e et les lettres de A :
(* p est la taille de lalphabet, retourne *) (* la matrice de dcalage associe au mot m *) e e let matrice p m = let n = vect_length(m) in let mat = make_matrix n p 1 in for i = 1 to n-1 do for a = 0 to p-1 do mat.(i).(a) <- mat.(i-1).(a) + 1 done; mat.(i).(m.(i-1)) <- 1 done; mat ;;

La validit de matrice est vidente, sa complexit est O(|m||A|) = O(|m|). e e e

280 let position mat m texte = let n = vect_length(m) in let imax = vect_length(texte) - n in let i = ref 0 and j = ref(n-1) in

Solutions des problmes e

while (!i <= imax) & (!j >= 0) do if m.(!j) = texte.(!i + !j) then j := !j-1 else begin i := !i + mat.(!j).(texte.(!i + !j)); j := n-1 end done; if !j < 0 then !i else failwith "non trouv" e ;;

Question 3-d Oui. Au lieu de chercher la dernire occurrence de bi+k dans a1 .. .ak1 , on e peut chercher la dernire occurrence du mot bi+k ak+1 .. .a|m|1 dans a1 . . .ak1 e et dcaler m en consquence. Ceci garantit que chaque lettre de t ne sera examine e e e quune fois dans le pire des cas, et 1/|m| fois en gnral. La construction de la e e table de dcalage est cependant plus complique. e e

Solutions des travaux pratiques

282

Solutions des travaux pratiques

Chemins dans Z2

1. Conversion mot liste de points


(* avance (x,y) dun pas dans la direction dir *) let avance dir (x,y) = match dir with | N -> (x, y + 1) | S -> (x, y - 1) | E -> (x + 1, y ) | W -> (x - 1, y ) ;; (* liste des points associs au mot "chemin" avec lorigine z *) e let rec points z chemin = match chemin with | [] -> [z] | dir::suite -> z :: points (avance dir z) suite ;;

2. Dtection et limination des boucles e e


(* dtecte les points multiples (algorithme en O(n^2)) *) e let rec multiples points = match points with | [] -> false | p::suite -> (mem p suite) or (multiples suite) ;; (* liste dassociation (point, prdcesseur) *) e e let rec prdcesseurs points = match points with e e | u::v::suite -> (v,u) :: prdcesseurs (v::suite) e e | _ -> [] ;; (* elimine les boucles *) let sans_boucle points = let z0 = hd(points) in let pred = prdcesseurs(points) in e e let l = ref([hd(rev points)]) in while hd(!l) <> z0 do l := (assoc (hd !l) pred) :: !l done; !l ;;

Files dattente et suite de Hamming

283

3. Remplissage
(* ordonnes extr^mes *) e e let rec extr^mes points = match points with e | [] -> failwith "liste vide" | [(x,y)] -> (y,y) | (x,y)::suite -> let (y1,y2) = extr^mes(suite) e in (min y1 y, max y2 y) ;; (* intersections avec une horizontale *) let rec intersecte y0 points = match points with | (x1,y1)::(x2,y2)::suite -> if (min y1 y2 = y0) & (max y1 y2 > y0) then x1 :: intersecte y0 ((x2,y2)::suite) else intersecte y0 ((x2,y2)::suite) | _ -> [] ;; (* remplissage *) let remplit points = let (ymin,ymax) = extr^mes(points) in e for y = ymin to ymax-1 do let l = ref(sort__sort (prefix <=) (intersecte y points)) in while !l <> [] do match !l with | x1::x2::suite -> noircit (x1,y) (x2,y+1); l := suite | _ -> failwith "cas impossible" done done ;;

Files dattente et suite de Hamming

1. Implmentation des les dattente e


(* cration, inspection *) e let nouv_file() = {avant = []; arri`re = []};; e let est_vide f = (f.avant = []) & (f.arri`re = []);; e let longueur f = list_length(f.avant) + list_length(f.arri`re);; e

284

Solutions des travaux pratiques (* insertion, suppression *) let ajoute f x = f.arri`re <- x :: f.arri`re;; e e let retire f = match f.avant with | x::suite -> f.avant <- suite; x | [] -> match rev(f.arri`re) with e | x::suite -> f.avant <- suite; f.arri`re <- []; x e | [] -> failwith "file vide" ;; let premier f = let x = retire f in f.avant <- x :: f.avant; x;;

2. La suite de Hamming a)
(* initialisation *) let h2 = nouv_file();; ajoute h2 2;; let h3 = nouv_file();; ajoute h3 3;; let h5 = nouv_file();; ajoute h5 5;; (* extrait lentier de Hamming suivant let suivant() = let x2 = premier(h2) and x3 = premier(h3) and x5 = premier(h5) in let x = min (min x2 x3) x5 in if x = x2 then (let _ = retire h2 in if x = x3 then (let _ = retire h3 in if x = x5 then (let _ = retire h5 in ajoute h2 (2*x); ajoute h3 (3*x); ajoute h5 (5*x); x ;; *)

()); ()); ());

b)

(* extraction optimise *) e let suivant() = let x2 = premier(h2) and x3 = premier(h3) and x5 = premier(h5) in let x = min (min x2 x3) x5 in if x = x2 then (let _ = retire h2 in ()); if x = x3 then (let _ = retire h3 in ()); if x = x5 then (let _ = retire h5 in ()); ajoute h5 (5*x); if x mod 5 > 0 then begin ajoute h3 (3*x); if x mod 3 > 0 then ajoute h2 (2*x) end; x ;;

Files dattente et suite de Hamming

285

Validit. On montre par rcurrence sur n la proprit suivante : soit Hn e e ee le n-me entier de Hamming suprieur ou gal a 2. Alors a lissue du e e e n-me appel a suivant, le nombre retourn est Hn et les les h2 , h3, h5 e e contiennent ensemble tous les entiers de Hamming compris entre Hn+1 et 5Hn de la forme 2Hk ou 3Hk ou 5Hk pour k n, chaque entier tant e prsent dans une seule des les. e Le cas n = 1 est immdiat. Supposons la proprit vraie au rang n et e ee examinons la situation a lissue du (n + 1)-me appel a suivant : le nombre x e retourn est Hn+1 car cest le plus petit des lments prsents dans h2 , h3, h5 a e ee e lissue de lappel prcdent. x tant retir de toutes les les qui le contiennent e e e e (il y en a fait une seule), tous les entiers restant dans h2, h3, h5 sont suprieurs e strictement a Hn+1. On sait dj que h2, h3 et h5 contiennent ensemble tous ea les entiers de Hamming suprieurs strictement a Hn+1 de la forme 2Hk ou e 3Hk ou 5Hk avec k n, il reste a tudier le cas des multiples de Hn+1. e Etude de 5Hn+1 : 5Hn+1 est insr dans h5 et cest un nouvel lment car ee ee avant cette insertion h2, h3 et h5 ne contenaient que des nombres infrieurs e ou gaux a 5Hn. e Etude de 3Hn+1 : si lentier Hn+1 est divisible par 5, Hn+1 = 5Hp , alors 3Hn+1 = 5(3Hp) = 5Hq et q < n + 1 car Hq = 3 Hn+1 < Hn+1 donc 3Hn+1 5 est prsent dans une et une seule des les h2, h3 , h5 avant lextraction de e Hn+1 et il nest pas rinsr lors de cette extraction. e ee Si Hn+1 nest pas divisible par 5 alors 3Hn+1 nappartient a aucune des les h2 , h3, h5 avant linsertion eectue lors de lextraction de Hn+1. En e eet, on ne peut avoir 3Hn+1 = 5Hk puisque Hn+1 nest pas divisible par 5 et on na pas non plus 3Hn+1 = 3Hk ou 3Hn+1 = 2Hk avec k n car ces relations impliquent Hk Hn+1 > Hn. Donc 3Hn+1 est bien prsent dans e une et une seule des les h2, h3, h5 a lissue du (n + 1)-me appel a suivant. e Etude de 2Hn+1 : en distinguant les cas ( Hn+1 divisible par 5 ) , ( Hn+1 ( ) ( non divisible par 5 mais divisible par 3 ) et ( Hn+1 divisible ni par 5 ni ) ( par 3 ) , on dmontre de m^me que 2Hn+1 est prsent dans une et une seule e e e ) des les h2 , h3 , h5 a lissue du (n + 1)-me appel a suivant. Ceci achve la e e dmonstration de validit de suivant. e e c)
(* initialisation *) let h2 = nouv_file();; let h3 = nouv_file();; let h5 = nouv_file();; ajoute h2 (1,0,0);; ajoute h3 (0,1,0);; ajoute h5 (0,0,1);;

(* compare deux triplets de Hamming *) let ln2 = log(2.0) and ln3 = log(3.0) and ln5 = log(5.0);; let minimum (a,b,c as x) (a,b,c as y) = let t = float_of_int(a-a)*.ln2 +. float_of_int(b-b)*.ln3 +. float_of_int(c-c)*.ln5 in if t <= 0. then x else y ;;

286

Solutions des travaux pratiques (* extrait le triplet de Hamming suivant *) let suivant() = let x2 = premier(h2) and x3 = premier(h3) and x5 = premier(h5) in let (a,b,c as x) = minimum (minimum x2 x3) x5 in if x = x2 then (let _ = retire h2 in ()); if x = x3 then (let _ = retire h3 in ()); if x = x5 then (let _ = retire h5 in ()); ajoute h5 (a,b,c+1); if c = 0 then begin ajoute h3 (a,b+1,c); if b = 0 then ajoute h2 (a+1,b,c) end; x ;;

d) Le programme suivant ache la somme n des longueurs des trois les h2 , h3 et h5 aprs extraction du n-me entier de Hamming : e e
(* taille des files pour n0, 2n0, 4n0, .., n1 *) let etude n0 n1 = h2.avant <- [1,0,0]; h2.arri`re <- []; e h3.avant <- [1,0,0]; h3.arri`re <- []; e h5.avant <- [1,0,0]; h5.arri`re <- []; e let borne = ref n0 in for n = 2 to n1 do let _ = suivant() in if n = !borne then begin let l = longueur h2 + longueur h3 + longueur h5 in printf__printf "n = %6d l = %6d\n" n l; borne := !borne * 2 end done ;; #tude 1000 100000;; e n = 1000 l = 256 n = 2000 l = 402 n = 4000 l = 638 n = 8000 l = 1007 n = 16000 l = 1596 n = 32000 l = 2526 n = 64000 l = 4002 - : unit = ()

On constate 8n 4 n ce qui conduit a conjecturer que n n2/3 pour une certaine constante . Cette conjecture est exacte, on trouvera une

Recherche de contradictions par la mthode des consensus e

287

dmonstration de ce fait et une tude de divers algorithmes permettant de e e calculer les n premiers entiers de Hamming, ou seulement le n-me, dans les e deux documents suivants :
http://pauillac.inria.fr/~quercia/papers/hamming.ps.gz http://pauillac.inria.fr/~quercia/papers/hamming-new.ps.gz

Recherche de contradictions par la mthode des consensus e

3. Programmation de ltape 1 e
(* compare deux clauses *) let implique (p1,n1) (p2,n2) = (subtract p1 p2 = []) & (subtract n1 n2 = []);; (* teste si une let rec present | [] -> | x::suite -> clause est implique par un syst`me *) e e c syst = match syst with false (implique x c) or (present c suite);; eliminant *) *) with

(* ajoute une clause au syst`me en e (* les clauses qui en dcoulent e let rec ajoute c syst = match syst | [] -> [c] | a::suite -> if implique c a then if implique a else if implique a ;;

c then syst else ajoute c suite c then syst else a :: (ajoute c suite)

(* simplifie un syst`me *) e let simplifie s = let rec simpl s1 s2 = match s2 with | [] -> s1 | c::suite -> simpl (ajoute c s1) suite in simpl [] s ;;

288

Solutions des travaux pratiques

4. Programmation des tapes 2 et 3 e


(* ajoute au syst`me le consensus eventuel de deux clauses *) e let ajoute_cons (p1,n1) (p2,n2) syst = match (intersect p1 n2, intersect p2 n1) with | ([x],[]) -> ajoute (union (except x p1) p2, union n1 (except x n2)) syst | ([],[x]) -> ajoute (union p1 (except x p2), union (except x n1) n2) syst | _ -> syst ;; (* ajoute a l tous les consensus entre c et une clause du syst`me *) ` e let rec ajoute_consensus c syst l = match syst with | [] -> l | c1::suite -> ajoute_consensus c suite (ajoute_cons c c1 l) ;; (* cl^t un syst`me par consensus *) o e let rec cloture s = let rec consensus s1 s2 = match s1 with | [] -> s2 | c::suite -> consensus suite (ajoute_consensus c s s2) in let t = simplifie(consensus s s) in if (subtract s t = []) & (subtract t s = []) then s else cloture t ;;

6. Achage des tapes dune contradiction e


(* "ajoute", "simplifie", "ajoute_consensus", "cloture" sont inchanges *) e let and and and ;; prefix prefix prefix prefix => =>~ ~=> ~=>~ a a a a b b b b = = = = ([b], [a], ([], [a;b], ([a;b],[], ([a], [b], H) H) H) H) (* (* (* (* a => b a => non b non a => b non a => non b *) *) *) *)

let string_of_clause(p,n,_) = (if n = [] then "" else (concat "." n)^" => ") ^ (if p = [] then "Faux" else concat "+" p) ;; let print_clause(c) = format__print_string(string_of_clause c);; install_printer "print_clause";; (* compare deux clauses *) let implique (p1,n1,_) (p2,n2,_) = (subtract p1 p2 = []) & (subtract n1 n2 = []);;

Modlisation dun tableur e

289

(* ajoute au syst`me le consensus eventuel de deux clauses *) e let ajoute_cons (p1,n1,_ as c1) (p2,n2,_ as c2) syst = match (intersect p1 n2, intersect p2 n1) with | ([x],[]) -> ajoute (union (except x p1) p2, union n1 (except x n2), D(c1,c2)) syst | ([],[x]) -> ajoute (union p1 (except x p2), union (except x n1) n2, D(c1,c2)) syst | _ -> syst ;; (* explique les etapes dune dduction *) e let explique clause = let vus = ref [] in let rec expl (p,n,r as c) = if not(mem c !vus) then match r with | H -> print_string "Jai lhypoth`se : "; e print_string (string_of_clause c); print_newline(); vus := c :: !vus | D((p1,n1,r1 as c1),(p2,n2,r2 as c2)) -> if r1 = H then (expl c2; expl c1) else (expl c1; expl c2); print_string "De "; print_string(string_of_clause c1); print_string " et "; print_string(string_of_clause c2); print_string " je dduis : "; print_string(string_of_clause c); e print_newline(); vus := c :: !vus in expl clause ;;

Modlisation dun tableur e


1. Tri topologique
let dpendances(t) = e for i = 0 to t.n-1 do for j = 0 to t.p-1 do t.suc.(i).(j) <- [] done done; for i = 0 to t.n-1 do for j = 0 to t.p-1 do match t.f.(i).(j) with | Rien -> t.dep.(i).(j) <- 0 | Somme(liste) -> t.dep.(i).(j) <- list_length(liste); do_list (fun (k,l) -> t.suc.(k).(l) <- (i,j)::t.suc.(k).(l)) liste done done ;;

290 let and | |

Solutions des travaux pratiques rec place t (i,j) = t.lt <- (i,j)::t.lt; dcompte t t.suc.(i).(j) e dcompte t liste = match liste with e [] -> () (i,j)::suite -> t.dep.(i).(j) <- t.dep.(i).(j) - 1; if t.dep.(i).(j) = 0 then place t (i,j); dcompte t suite e

;; let tri_topo(t) = dpendances(t); e t.lt <- []; for i = 0 to t.n-1 do for j = 0 to t.p-1 do if t.f.(i).(j) = Rien then place t (i,j) done done; t.lt <- rev(t.lt); if list_length(t.lt) < t.n*t.p then failwith "tri impossible" ;;

2. Calcul du tableau
let calc t (i,j) = match t.f.(i).(j) with | Rien -> () | Somme(liste) -> t.v.(i).(j) <- 0; do_list (fun (k,l) -> t.v.(i).(j) <- t.v.(i).(j) + t.v.(k).(l)) liste ;; let calcule t = do_list (calc t) t.lt;;

3. Complment e On ajoute dans la structure tableau une nouvelle matrice contenant pour chaque cellule la liste des cellules qui en dpendent, liste trie par ordre topologique. e e Cette liste sobtient par fusion des listes des cellules dpendant des successeurs de e la cellule considre. On est ainsi ramen au problme du calcul dun tableau en ee e e ordre topologique inverse, il sut de conduire les calculs dans lordre donn par e rev(t.lt).

Analyse syntaxique
2. Analyse lexicale
(* dcoupe une chaine en lex`mes *) e e let lex`mes s = e let i = ref 0 (* indice pour s *) and res = ref [] (* liste des lex`mes trouvs *) e e and l = string_length s in

Analyse syntaxique while !i < l do match s.[!i] with (* chiffre -> Nombre *) | 0..9 -> let x = ref 0 in while (!i < l) & (s.[!i] >= 0) & (s.[!i] <= 9) do x := !x*10 + int_of_char s.[!i] - int_of_char 0; i := !i + 1 done; res := Nombre(!x) :: !res (* caract`re alphabtique -> Ident *) e e | a..z -> let i0 = !i in while (!i < l) & (s.[!i] >= a) & (s.[!i] <= z) do i := !i+1 done; res := (match sub_string s i0 (!i - i0) with | "let" -> Let | "in" -> In | "fun" -> Fun | "if" -> If | "then" -> Then | "else" -> Else | x -> Ident(x)) :: !res (* oprateurs, parenth`ses et e e | % -> res := Opr(1,%) :: | + -> res := Opr(2,+) :: | * -> res := Opr(3,*) :: | / -> res := Opr(3,/) :: | ( -> res := ParO :: !res; | ) -> res := ParF :: !res; | = -> res := Egal :: !res; symboles *) !res; i := !i+1 !res; i := !i+1 !res; i := !i+1 !res; i := !i+1 i := !i+1 i := !i+1 i := !i+1

291

(* reconna^t - et -> *) | - -> if (!i+1 < l) & (s.[!i+1] = >) then begin res := Fl`che :: !res; e i := !i+2 end else begin res := Opr(2,-) :: !res; i := !i+1 end (* ignore les espaces *) | | \t | \n -> i := !i+1 (* refuse les autres caract`res *) e | _ -> failwith ("caract`re illgal : " ^ (make_string 1 s.[!i])) e e done; rev !res ;;

292

Solutions des travaux pratiques

3. Analyse syntaxique
(* empile un lex`me ou une expression et *) e (* simplifie la pile autant que possible *) let rec empile e pile = (* priorit de e *) e let p = match e with | L(In) | L(Then) | L(Else) | L(ParF) -> 0 | L(Opr(p,_)) -> p | _ -> 5 (* > priorit maximum *) e in (* conversion des nombres et identificateurs *) let e = match e with | L(Nombre x) -> E(Const x) | L(Ident x) -> E(Var x) | _ -> e in match e, pile with (* application de fonction *) | (E x), (E f)::suite -> empile (E(Appl(f,x))) suite (* parenth`ses *) e | (L ParF), (E a)::(L ParO)::suite -> empile (E a) suite (* opration prioritaire en instance *) e | _, (E b)::(L(Opr(q,o)))::(E a)::suite when p <= q -> empile e (empile (E(Bin(a,o,b))) suite) (* dfinition de fonction *) e | _, (E a)::(L Fl`che)::(E(Var x))::(L Fun)::suite e when p = 0 -> empile e (empile (E(Fct(x,a))) suite) (* liaison locale *) | _, (E b)::(L In)::(E a)::(L Egal)::(E(Var x))::(L Let)::suite when p = 0 -> empile e (empile (E(Letin(x,a,b))) suite) (* test *) | _, (E c)::(L Else)::(E b)::(L Then)::(E a)::(L If)::suite when p = 0 -> empile e (empile (E(Test(a,b,c))) suite) (* pas de simplification possible *) | _, _ -> e::pile ;;

Analyse syntaxique

293

4. Evaluation
(* evaluation *) let rec valeur env expr = match expr with | Const c -> Int c | Var x -> assoc x env | Fct(x,e) -> Cloture(env,expr) | Bin(e1,op,e2) -> let v1 = match valeur env e1 with | Int x -> x | _ -> failwith "valeur non enti`re" in e let v2 = match valeur env e2 with | Int x -> x | _ -> failwith "valeur non enti`re" in e let v = match op with | + -> v1 + v2 | - -> v1 - v2 | * -> v1 * v2 | / -> v1 / v2 | % -> v1 mod v2 | _ -> failwith "oprateur inconnu" e in Int v | Appl(f,e) -> let env1,x,code = match valeur env f with | Cloture(env1,Fct(x,code)) -> env1,x,code | _ -> failwith "valeur non fontionnelle" in valeur ((x,valeur env e) :: env1) code | Test(e1,e2,e3) -> let v = match valeur env e1 with | Int x -> x | _ -> failwith "valeur non enti`re" e in valeur env (if v = 0 then e2 else e3) | Letin(x,e1,e2) -> (* attention : si e1 svalue en une fonction, il faut e *) (* introduire une liaison pour x dans la cloture de cette *) (* fonction pour le cas o` la fonction serait rcursive *) u e let v = match valeur env e1 with | Int(c) -> Int(c) | Cloture(env2,code) -> let rec y = Cloture((x,y)::env2,code) in y in valeur ((x, v) :: env) e2 ;;

Annexes

Bibliographie

295

Bibliographie
[Aho] Aho, Ullman Concepts fondamentaux de linformatique Dunod, 1993

[Albert] Ouvrage collectif, coordination L. Albert Cours et exercices dinformatique Vuibert, 1998 [Corm] Cormen, Leiserson, Rivest Introduction a lalgorithmique Dunod, 1993 Froidevaux, Gaudel, Soria Types de donnes et algorithmes e Ediscience, 1994

[Froid]

[Knuth] Knuth The art of computer programming Addison-Wesley, 1973 [Leroy] Leroy, Weis Le langage Caml InterEditions, 1993 Mehlhorn Data Structures and Algorithms Springer-Verlag, 1984 Sedgewick Algorithmes en langage C Interditions, 1991 e Stern Fondements mathmatiques de linformatique e Ediscience, 1994

[Mehl]

[Sedg]

[Stern]

296

Annexes

Aide mmoire de caml e


Dclarations et instructions e commentaires . . . . . . . . . . . . . . . . . . . . dnition dune valeur . . . . . . . . . . . . e rcursive . . . . . . . . . . . . . . . e locale . . . . . . . . . . . . . . . . . . . dnitions parallles . . . . . . . . . . . . . . e e successives . . . . . . . . . . . . variable modiable . . . . . . . . . . . . . . . valeur dune rfrence . . . . . . . . . . . . ee modication dune rfrence . . . . . . ee fonction sans argument . . . . . . . . . . . fonction a un argument . . . . . . . . . . . fonction a n arguments . . . . . . . . . . . expression conditionnelle . . . . . . . . . choix multiple . . . . . . . . . . . . . . . . . . . .

ne rien faire . . . . . . . . . . . . . . . . . . . . . . calculs en squence . . . . . . . . . . . . . . . e boucle croissante . . . . . . . . . . . . . . . . . boucle dcroissante . . . . . . . . . . . . . . . e boucle conditionnelle . . . . . . . . . . . . . dclencher une erreur . . . . . . . . . . . . . e Expressions boolennes e vrai, faux . . . . . . . . . . . . . . . . . . . . . . . . . et, ou, non . . . . . . . . . . . . . . . . . . . . . . . comparaison . . . . . . . . . . . . . . . . . . . . . . boolen cha^ e ne . . . . . . . . . . . . . . cha^ ne boolen . . . . . . . . . . . . . e Expressions enti`res e oprations arithmtiques . . . . . . . . . . e e modulo . . . . . . . . . . . . . . . . . . . . . . . . . . .

(* ... *) let v = expression let rec v = ... let v = ... in expression expression where v = ... let v = ... and w = ... let v = ... in let w = ... let v = ref(expression) !v v := ... let f() = ... let f x = ... let f x1 .. xn = ... if ... then expr-vrai else expr-faux match valeur with | motif-1 -> expression-1 | motif-2 -> expression-2 ... | motif-n -> expression-n -> expression-par-dfaut e | () begin ... end for i = dbut to e fin do ... done for i = dbut downto fin do ... done e while condition do ... done failwith "message"

true false & or not < <= = <> >= string of bool bool of string

>

+ mod

Aide mmoire de caml e

297

valeur absolue . . . . . . . . . . . . . . . . . . . . entier prcdent, suivant . . . . . . . . . . e e minimum et maximum . . . . . . . . . . . oprations bit a bit . . . . . . . . . . . . . . . e dcalage de bits . . . . . . . . . . . . . . . . . . e entier cha^ ne . . . . . . . . . . . . . . . . cha^ entier . . . . . . . . . . . . . . . . ne entier alatoire entre 0 et n 1 . . . e Expressions relles e oprations arithmtiques . . . . . . . . . . e e puissance . . . . . . . . . . . . . . . . . . . . . . . . . minimum et maximum . . . . . . . . . . . fonctions mathmatiques . . . . . . . . . e rel e cha^ ne . . . . . . . . . . . . . . . . rel e entier . . . . . . . . . . . . . . . . cha^ rel . . . . . . . . . . . . . . . . . . ne e entier rel . . . . . . . . . . . . . . . . . . e rel alatoire entre 0 et a . . . . . . . . . e e Expressions rationnelles utiliser les rationnels . . . . . . . . . . . . . oprations arithmtiques . . . . . . . . . . e e comparaison . . . . . . . . . . . . . . . . . . . . . . minimum et maximum . . . . . . . . . . . valeur absolue . . . . . . . . . . . . . . . . . . . . numrateur, dnominateur . . . . . . . . e e simplier une fraction . . . . . . . . . . . . simplication automatique . . . . . . . . partie entire . . . . . . . . . . . . . . . . . . . . . e rationnel cha^ ne . . . . . . . . . . . . . rationnel entier . . . . . . . . . . . . . . rationnel rel . . . . . . . . . . . . . . . . e cha^ ne rationnel . . . . . . . . . . . entier rationnel . . . . . . . . . . . rel e rationnel . . . . . . . . . . . Listes liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . liste vide . . . . . . . . . . . . . . . . . . . . . . . . . t^te et queue . . . . . . . . . . . . . . . . . . . . . e longueur dune liste . . . . . . . . . . . . . . concatnation . . . . . . . . . . . . . . . . . . . . e

abs pred succ min a b, max a b land lor lxor lnot lsl lsr asr string of int int of string random int(n)

+. -. *. /. ** ou **. min a b, max a b abs float exp log sqrt sin cos tan sinh cosh tanh asin acos atan atan2 string of float int of float float of string float of int random float(a)

#open "num" +/ -/ */ // **/ minus num quo num mod num square num </ <=/ =/ <>/ >=/ >/ min num a b, max num a b abs num numerator num denominator num normalize num arith status set normalize ratio true floor num round num ceiling num string of num int of num float of num num of string num of int num of float

[x; y; z; ... ] [ ] hd tl, x :: suite list length @

298

Annexes

image miroir . . . . . . . . . . . . . . . . . . . . . appliquer une fonction . . . . . . . . . . . . itrer un traitement . . . . . . . . . . . . . . e test dappartenance . . . . . . . . . . . . . . . test de prsence . . . . . . . . . . . . . . . . . . e recherche dun lment . . . . . . . . . . . ee oprations ensemblistes . . . . . . . . . . . e tri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . association . . . . . . . . . . . . . . . . . . . . . . . itrer une opration . . . . . . . . . . . . . . e e

rev map fonction liste do list traitement liste mem elment liste e exists prdicat liste e for all prdicat liste e index elment liste e union intersect subtract sort sort ordre liste assoc b [(a,x); (b,y); (c,z); ... ] = y it list op a [x; y; z] = op (op (op a x) y) z list it op [x; y; z] a = op x (op y (op z a)) [|x; y; z; ... |] [| |] v.(i) v.(i) <- qqch vect length make vect longueur valeur make matrix n p valeur sub vect vecteur dbut longueur e concat vect copy vect map vect fonction vecteur do vect traitement vecteur list of vect vect of list

Vecteurs vecteur . . . . . . . . . . . . . . . . . . . . . . . . . . . vecteur vide . . . . . . . . . . . . . . . . . . . . . . i-me lement . . . . . . . . . . . . . . . . . . . . e e modication . . . . . . . . . . . . . . . . . . . . . . longueur dun vecteur . . . . . . . . . . . . cration . . . . . . . . . . . . . . . . . . . . . . . . . . e cration dune matrice . . . . . . . . . . . . e extraction . . . . . . . . . . . . . . . . . . . . . . . . concatnation . . . . . . . . . . . . . . . . . . . . e copie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . appliquer une fonction . . . . . . . . . . . . itrer un traitement . . . . . . . . . . . . . . e vecteur liste . . . . . . . . . . . . . . . . . liste vecteur . . . . . . . . . . . . . . Cha nes de caract`res e caractre . . . . . . . . . . . . . . . . . . . . . . . . . e cha^ de caractres . . . . . . . . . . . . . . ne e i-me caractre . . . . . . . . . . . . . . . . . . . e e modication . . . . . . . . . . . . . . . . . . . . . . longueur dune cha^ ne . . . . . . . . . . . . cration . . . . . . . . . . . . . . . . . . . . . . . . . . e caractre cha^ e ne . . . . . . . . . . . . . extraction . . . . . . . . . . . . . . . . . . . . . . . . concatnation . . . . . . . . . . . . . . . . . . . . e Graphisme utiliser le graphisme . . . . . . . . . . . . . . initialiser la fen^tre graphique . . . . e refermer la fen^tre . . . . . . . . . . . . . . . . e

x "xyz... " cha^ne.[i] cha^ne.[i] <- qqch string length make string longueur caract`re e make string 1 caract`re e sub string cha^ne dbut longueur e ch1 ^ ch2, concat [ch1; ch2; ch3; ... ]

#open "graphics" open graph "" close graph()

Aide mmoire de caml e

299

eacer la fen^tre . . . . . . . . . . . . . . . . . . e position du crayon . . . . . . . . . . . . . . . . changer la couleur du crayon . . . . . couleurs . . . . . . . . . . . . . . . . . . . . . . . . . . changer lpaisseur du crayon . . . . . e tracer un point . . . . . . . . . . . . . . . . . . . dplacer, crayon lev . . . . . . . . . . . . . e e crayon baiss . . . . . . . . . . . e tracer un cercle . . . . . . . . . . . . . . . . . . . crire un texte . . . . . . . . . . . . . . . . . . . . e peindre un rectangle . . . . . . . . . . . . . . un polygone . . . . . . . . . . . . . . un disque . . . . . . . . . . . . . . . . attendre un vnement . . . . . . . . . . . e e

clear graph() current point() set color couleur black white red green blue yellow cyan magenta, rgb r g b set line width epaisseur plot x y moveto x y lineto x y draw circle x y rayon draw string "texte" fill rect x y largeur hauteur fill poly [| (x0,y0); (x1,y1); ... |] fill circle x y rayon read key() wait next event [ev1; ev2; ... ]

Entres-sorties au terminal e impression de valeurs . . . . . . . . . . . . . changer de ligne . . . . . . . . . . . . . . . . . . impression formatte . . . . . . . . . . . . . e lecture de valeurs . . . . . . . . . . . . . . . . . Entres-sorties dans un chier e ouverture en lecture . . . . . . . . . . . . . . en criture . . . . . . . . . . . . . e lecture . . . . . . . . . . . . . . . . . . . . . . . . . . . criture . . . . . . . . . . . . . . . . . . . . . . . . . . e fermeture ........................

print int print float num print num print char print string print endline print newline() printf printf format valeurs read int read float read line

let canal = open in "nom" let canal = open out "nom" input char input line input byte input value output char output string output byte output value flush close in close out

Commande de linterprteur e tracer une fonction . . . . . . . . . . . . . . . ne plus tracer . . . . . . . . . . . . . . . . utiliser une fonction dimpression . ne plus lutiliser . . . . . . . . . . . . . . charger un chier source . . . . . . . . . . charger un module compil . . . . . . . . e nom compltement quali . . . . . . . e e utiliser les noms courts dun module ne plus les utiliser . . . . . . . . . . . . ajouter un rpertoire de recherche e quitter linterprteur . . . . . . . . . . . . . e

trace "fonction" untrace "fonction" install printer "fonction" remove printer "fonction" load "nom", include "nom" load object "nom" module nom #open "module" #close "module" directory "chemin" quit()

300

Annexes

Index

+ :: @ =

133 27,30 31 133 61 61 56,186 18 18 133 81 132

{ { { { { { {

quivalent 140 e ni 138 index par des expressions rgulires 149 e e e produit 154 reconnaisseur 139 squentiel 154 e simulation 141

B
B noeud 90 B vide 90

A
additionneur 1-bit 65,68,74 { modulo 3 224 { n-bits 65,74 Aitken 160 algorithme 9 { rcursif 14 e algorithmique 10 alphabet 132 ambigut 58,59 e analyse syntaxique 184 anc^tre 87 e arbre { binaire 88,90 { binaire de recherche 109 { binaire parfait 91,104 { construit alatoirement 103,111 e { de dcision 88,99,108,110 e { de priorit 163 e { dnombrement 101,107 e { dynastique 88,105 { quilibr en hauteur 100,107 e e { quilibr en poids 107 e e { gnral 87,92 e e { hauteur 87,99 { largeur 95 { ordonn 88 e { reprsentation ascendante 93 e { syntaxique 70 { taille 87,99 ascendant 87 ascenseur 138,154 automate { complet 138 { dterminisation 146 e { dterministe 138 e

bascule RS 64 branche dun arbre 88 { droite, gauche, vide 90

C
Carroll 180 Catalan 102 Csaro 81 e champ 54 circuit { combinatoire 63 { logique 63 { squentiel 63 e CL 118 coecients du bin^me 15,21,89 o combinaison linaire 118 e comparaison { dalgorithmes 76,85,86 { relation 34 { temps moyen 85 compilateur 131 compilation { dune expression 166 { dune formule inxe 59 complexit e { asymptotique 77 { dans le pire des cas 77 { en moyenne 77,108 { quation de rcurrence 79,82,84 e e { intrinsque 99 e { spatiale 76 { temporelle 76 concat vect 31 concatnation e { de langages 133 { de listes 31 { de mots 132 conjonction 61

Index
connecteur logique 60,65,69 { ternaire 73 consensus 176 constructeur 90,120,246 contradiction 176 { droit, gauche 88 { gauche - frre droit 94,104 e fonction 9 { boolenne 61,65,68,73 e { de transition 138 for^t 88 e forme normale { normale conjonctive 69,72,73 { normale disjonctive 68 { normale exclusive 74 formule { drivation 120 e { inxe 55,59 { logique 69,74 { mathmatique 55 e { postxe 55,56,59 { prxe 55,59 e { reprsentation 116 e { simplication 124 { valeur 55 Fourier 266 frre 87 e fusion { darbres de recherche 114 { de listes cha^ ees 39 n { de vecteurs 38 { multiple 50 { sans rptition 50 e e

301

D
Davis et Putnam 72 de Morgan 62,73 dcision e { algorithmes 151 { arbre 88,99,108,110 degr dun nud 87 e dpiler 53 e drcursication 52 ee drivation dune expression 120 e descendant 87 dterminant 84 e dterminisation 146,154 e dichotomie 36 dirence densembles 50 e disjonction 61 distribution de vrit 71 e e diviser pour rgner 17,78,82 e do list 27,32 do vect 27

E
lments quivalents 34 ee e empiler 53 quation de degr deux 9,89 e e EQUIV 34 et 61 tat accessible 155 e { coaccessible 155 { rebut 151,155 tiquette 88 e toile dun langage 133 e { lemme 153 valuation e { dun arbre 97 { dun polyn^me 12 o { dune formule inxe 59 { dune formule logique 71 { dune formule postxe 56 exponentiation 11,14,17,22 expression { arithmtique 115,141 e { conditionnelle 58 { normalise 118 e { rgulire 134 e e

G
G noeud 92

graphe 122

H
Hamming 174 Hanoi 80 hauteur dun arbre 87,99 hd 26 Horner 13,20

I
image miroir 32,133 implication 61 indice de boucle 11 inxe { formule 55,59 { ordre 95,104,109 insertion { la racine 112,114 a { aux feuilles 103,111,114 { dans un arbre de priorit 164 e { dans un arbre de recherche 111 { dans une liste 30 { dans une liste trie 34 e { sans rptition 50 e e interpolation de Lagrange 159,197 interprteur 131 e intersection densembles 50 invariant de boucle 13

F
facteur dun mot 133 faux 60 feuille 87 Fibonacci 22,79,101 le dattente 174 ls 87

302
inversion 41 itration 11 e { interne 87 { terminal 87 nombre de Catalan 102 { parfait 20 non 61

Annexes

K
Karatsuba 20,23,266 Kleene 147 Knuth 18,266

O
oprations e { sur les ensembles 50 { sur les langages 133 ordre { inxe 95,104,109 { lexicographique 61,120,191,218,220 { postxe 95,104 { prxe 95,104 e { sur les expressions 119 { symtrique 95 e ou 61 oubien 61

L
Lagrange 160,197 langage 132 { des parenthses 134,137,152,155 e { non rgulier 152 e { reconnaissable 145 { rgulier 134 e { rsiduel 152 e largeur dun arbre 95 Lazard 133 lemme de ltoile 153,156 e lettre 132 Levi 136 lexme 55,130 e lexical 131 lexicographique 61,120,191,218,220 liste 24 { double entre 33 a e { cha^ ee 26 n { parenthse 105 ee { presque trie 51 e { trie 34 e littral 67 e logique ternaire 73 longueur du chemin externe 103,108 { du chemin interne 103,240

P
parcours { dun arbre 94,104 { dune formule 70 { dune liste 27 { de graphe 144,243 { en largeur dabord 95,98,144 { en profondeur dabord 95,144 partage 124,129 pre 87,93 e PG 118 pile 53,56,59,166 { dexcution 54 e PLUSGRAND 34 PLUSPETIT 34 pointeur 11 polyn^me creux 50 o porte logique 63 postxe { formule 55,59 { ordre 95,104 prdicat 33 e prxe e { facteur 133 { formule 55,59 { ordre 95,104 priorit 59 e produit booleen 61 e { gnralis 118 e e e profondeur { dun circuit 64 { dun nud 87,102,103 programme 9 { dun automate 138 proposition 60 { identique 60

M
machine parallle 78 e { squentielle 78 e maple 244 matrice de transition 141 merge 51 minterme 67 mon^me 67 o mot 132 multiplication { de Karatsuba 20 { de Knuth 18 { de polyn^mes 18 o { matricielle 84 { par transformation de Fourier rapide 266 { rapide 23,159 mutable 54 Myers 272

N
n-uplet 25 Newton 160 nud 87

Q
queue dune liste 24 quicksort 46

Index

303
taille dun arbre 87,99 tautologie 60,69,71,74 temps { de propagation 64 { de sparation-recombinaison 80 e { moyen dune comparaison 85 terminaison 11 t^te dune liste 24 e Thompson 147 tl 26 tours de Hanoi 80 transition gnralise 139 e e e transitions dun automate 138 tri { bulles 41,50,51 a { complexit en moyenne 108 e { complexit intrinsque 99 e e { dune liste 39 { en arbre 165 { par comparaisons 40,99,108 { par distribution 158 { par fusion 42 { par fusion naturelle 52 { par slection 80 e { rapide 46,52,114 { stable 40 { topologique 182 Turbo-Pascal 137

R
racine carre 21 e { carre dun langage 155 e { dun arbre 87 recherche { dune cha^ de caractres 167 ne e { dune sous-liste 33 { dans un arbre binaire de recherche 110 { dans une liste 28 { dans une liste trie 35 e { par dichotomie 36 record 54 rcursivit e e { mutuelle 16,143 { simple 14 { terminale 110,199,231,232 rduction 56,58,186 e rfrence 11 ee rgulier 134 e relation de comparaison 34 rev 32 rotation dune liste 32

S
satisabilit 69,71 e segmentation 46 smantique 130,151 e srie gnratrice 101,102 e e e simplication { dun automate 155 { dune formule 124,129 { dune formule logique 74 somme boolenne 61 e { de langages 133 sommet de pile 53 sort 51 sortance 64 Strassen 84 structure FIFO 175 { LIFO 53 substitution 129 suxe 133 suppression { dans un arbre 113 { dans une liste 30 syntaxique 131

U
Ukkonen 272 union densembles 50

V
valeur dune formule 55 { de vrit 60 e e variable propositionnelle 61 vect length 26 vecteur 26 { circulaire 33 { dindexation 49 vrai 60

T
table de vrit 61,71 e e

W
Wallis 102 Warshall 251

Vous aimerez peut-être aussi