Algorithmique Et Programmation

of 80 /80
collection Informat

Embed Size (px)

Transcript of Algorithmique Et Programmation

  • collection Informat

  • @ Hermbs, Paris, 1992

    ditions Herms34, rue Eugne Plachat75017 Paris

    ISBN 2-86601-323-g

    Table des matires

    1 . Introduction.. ..............................................................................1 .l. Quelques mots sur lenvironnement ...............................................

    1 . 2 . Notes bibliographiques sommaires.. ..............................................

    1 . 3 . Remerciements.. ........................................................................

    1.4. Le choix de programmes .............................................................

    2 . Des programmes pour commencer. . ...........................................

    2.1. Le mode dun vecteur ..................................................................

    2.1.1. Construction de la premire version du programme ..................

    2.1.2. Remarques mthodologiques ...............................................

    2.2. Recherche dun objet.. ................................................................2.2.1. Recherche linaire.. ...........................................................2.2.2. Un pige.. .......................................................................2.2.3. La dichotomie.. ................................................................

    2.3. De la complexit des algorithmes.. ................................................2.4. Rsum des principes introduits.. ..................................................

    2.4.1. Un apparte sur les preuves de programmes.. ...........................

    2.4.2. Le style dcriture .............................................................2.5. Adressage dispers......................................................................

    2.5.1. Algorithme avec chanage.. .................................................2.5.2. Autant de cl& que de cases.. ................................................2.5.3. Choix de cl et efficacit ....................................................

    2.6. Exercices..................................................................................

    3 . Les tris ....................................................................................... 45

    3.1. Recherche du plus petit lment.. .................................................. 46

    1 31 61 71 71 8

    2121212324252829343536373738404243

  • ALGO~Q~IE m PROGRAmION

    3.2. Tri par insertion ........................................................................ 48

    3.3. Tri par bulles.. .......................................................................... 51

    3.4. Diviser pour &gner .................................................................... 54

    3.4.1. Diviser pour rkgner avec partition ........................................ 54

    3.4.2. Solution sans appel r&rsif.. .............................................. 57

    3.4.3. Quelques commentaires sur la nkursivit ............................... 59

    3.4.4. Deux pivots.. ................................................................... 61

    3.4.5. Tri par fusion.. ................................................................. 63

    3.5. F&um de la complexite des algorithmes ....................................... 66

    3.6. Exercices.. ................................................................................ 66

    Des structures de donnes . . ........................................................ 67

    4.1. Les piles.. ................................................................................ 67

    4.2. Les files ................................................................................... 68

    4.3. Les arbres.. ............................................................................... 70

    4.3.1. Arbres binaires et arbres n-aires ........................................... 714.3.2. Reprsentation des arbres.................................................... 72

    4.3.3. Parcours darbres ............................................................... 734.3.4. Parcours prfix et post-fix.. .............................................. 74

    4.4. Les treillis.. .............................................................................. 784.5. Les graphes .............................................................................. 79

    4.5.1. Algorithme de Schorr-Waite ................................................ 804.5.2. Amlioration de lalgorithme de Schorr-Waite.. ....................... 844.5.3. Reprsentation dun graphe sur une matrice boolenne.. ............ 874.5.4. Fermeture transitive .......................................................... 88

    4.6. Ordres partiels et totaux .............................................................. 894.7. Exercices.. ................................................................................ 90

    5. Rcurrence et rcursivit ........................................................... 935.1. Lexemple type . Les tours dHanoi ............................................... 93

    5.1.1. Cot de lalgorithme .......................................................... 965.1.2. Une analyse plus pousse.. ................................................. 97

    5.2. Des permutations....................................................................... 995.2.1. Permutations par changes de voisins ................................... 1005.2.2. Le programme.................................................................. 1 0 15.2.3. Relation avec les tours dHanoi ............................................ 1 0 55.2.4. Une variante .................................................................... 1 0 55.2.5. Une version rcursive ........................................................ 108

    5.3. Exercices .................................................................................. 1 0 9

    6. La marche arrire ........................................................................ 1 1 16.1. La souris et le fromage ............................................................... 1 1 1

    6.1.1. Version t+cursive .............................................................. 114

    6

    7.

    8 .

    6.1.2. Marche arriere, arbres et graphes .......................................... 1156.2. Les huits reines ......................................................................... 116

    6.2.1. Une version amliore ....................................................... 1186.2.2. Une deuxieme approche ...................................................... 119

    6.3. Exercices .................................................................................. 122

    lkansformation de programmes. . ................................................ 1 2 5

    7.1. Revenons sur le mode vecteur ...................................................... 126

    7.2. La multiplication des gitans ......................................................... 128

    7.3. Exercices.................................................................................. 1 3 1

    Quelques structures de donnes particulires.. .......................... 1 3 3

    8.1. Les arbres ordonns.. .................................................................. 1 3 3

    8.2. Les arbres quilibrs ................................................................... 1 3 5

    8.2.1. Algorithmes de manipulation darbres quilibrs.. .................... 1 3 7

    8.3. Les B-arbres.. ............................................................................ 138

    8.4. Exercices.................................................................................. 1 4 3

    I

    7

    Bibliographie e t rfrences.. ........................................................... 145

    Glossaire ......................................................................................... 1 4 8

    Solutions de certains exercices.. .................................................... 151

  • Tables et figures

    2.1. Comparaison entre la recherche I&%re et la dichotomie (02.3)2.2. Table pour ladressage dispers avec chanage ($25.1)2.3. Table sans zone de dbordement ($2.52)3.1. Appels aprs parution (83.4.3)3.2. Vecteur en cours de partition (93.4.4)4.1. Arbre du tri diviser pour rgner (94.3)4.2. Transformation darbre n-aire en arbre binaire (4.3.1)4.3. Reprsentation de larbre de la figure 4.2 ($4.3.2)4.4. Parcours en profondeur dabord (ordre prefix) ($4.3.4)4.5. Parcours en largeur dabord ($4.3.4)4.6. Triple visite des nuds dun arbre ($4.3.4)4.7. Parcours en ordre infix ($4.3.4)4.8. Parcours en ordre post-fix ($4.3.4)4.9. Un treillis (94.4)4.10. Etats dans Schorr-Waite ($4.52)4.11. Etats dans Schorr-Waite amlior ($4.5.2)4.12. Un graphe ($4.5.3)4.13. Reprsentation sur une matrice binaire ($4.5.3)4.14. Fermeture transitive du graphe de la figure 4.13 ($4.5.4)4.15. Fermeture transitive, une ligne (94.5.4)4.16. Arbre binaire simple ($4.6)5.1. Position de dpart des tours dHanoi ($5.1)5.2. Arbre dappels pour trois disques (5.1)5.3. Permutations de quatre entiers ($5.2.1)5.4. Valeurs de i et du pivot dans permutations(4) ($5.2.2)5.5. Nouvelles permutations de quatre objets ($5.2.4)

  • A L G O R I T H M I Q U E JZ P R O G R A M M A T I O N

    6.1. Arbre de possibilites pour la souris ($6.1.2)7.1. Multiplication de deux entiers ($7.2)8.1. Un arbre binaire ordonne ($8.1)8.2. Arbre ordonn inefficace ($8.2)8.3. Equilibrage de larbre de la figure 8.1 ($8.2)8.4. Avec deux nuds en plus ($8.2)8.5. Rquilibrage de larbre de la figure 8.4 ($8.2)8.6. Un B-arbre complet avec d=l ($8.3)8.7. Apres lecture de 1 et 2 ($8.3)8.8. Apres lecture du 3 ($8.3)8.9. Apres lecture du 5 ($8.3)8.10. Apres lecture du 7 ($8.3)8.11. Reorganisation pour viter dintroduire un niveau ($8.3)

    Les programmes

    2.1. Le mode dun vecteur ($2.1.1)2.2. Recherche dun objet dans un vecteur ($2.2.1)2.3. Recherche par dichotomie (82.2.3)2.4. Dichotomie, version 2 ($2.2.3)2.5. Dichotomie, version 3 ($2.2.3)2.6. Adressage dispers ($2.5.1)2.7. Adressage dispers, version 2 ($2.5.2)3.1. Schma du tri par recherche du plus petit lement (93.1)3.2. Boucle interne (83.1)3.3. Programme complet ($3.1)3.4. Tri par insertion ($3.2)3.5. Version avec ETPUIS ($3.2)3.6. Tri par bulles primitif ($3.3)3.7. Tri par bulles normal ($3.3)3.8. Partition dun vecteur ($3.4.1)3.9. Insertion dans une proc&lure nkursive (93.4.1)3.10. Version avec pile ($3.4.2)3.11. Diviser pour rgner avec deux pivots ($3.4.4)3.12. Tri par fusion ($3.4.5)4.1. Miseen uvre dunepile ($4.1)

    (y 4.2. Une file discutable ($4.2)g 4.3. Une file circulaire (84.2)

    4.4. Parcours dun arbre binaire ($4.3.3)4.5. Utilisation dune bute ($4.3.3)

    J- 4.6. Parcours avec pife ($4.3.3)4.7. Triple visite dun nud (44.3.4)

    1 0

  • ALGORITHMIQIJE ET ~m~bmmf.mo~

    4.8. Visite dun graphe ($4.5)4.9. Marquage avec trois valeurs (94.51)4.10. Version sans rcursivit ($4.51)4.11. Mise en uvre du prdcesseur (4.5.1)4.12. Schorr-Waite amliore ($4.5.2)4.13. Version condense ($4.5.2)5.1. Tours dHanoi, version de base ($5.1)5.2. Calcul du pivot (5.2.2)5.3. Permutations par changes (95.2.2)5.4. Permutations par changes, version 2 (55.2.2)5.5. Encore les tours dHanoi ($5.2.3)5.6. Traverse unidirectionnelle ($5.2.4)5.7. Version rkursive (45.2.5)6.1. La souris et le fromage ($6.1)6.2. Forme rcursive (96.1.1)6.3. Les huit reines ($6.2)6.4. Les huit reines, version 2 ($6.2)

    ~6.5. Suppression dune pile ($6.2.1)6.6. Avec un compteur octal ($6.2.2)6.7. Avec des permutations ($6.2.2)6.8. Avec permutations et marche arrire ($6.2.2)7.1. Encore le mode dun vecteur (97.1)7.2. Le mode amlior ($7.1)7.3. Multiplication avec n%.trsivit ($7.2)7.4. Suppression de la rcursivit ($7.2)7.5. Version avec dcalages ($7.2)8.1. Arbre ordonn ($8.1)8.2. Arbre Cquilibr (48.2.1)8.3. B-arbres ($8.3)

    1 2

    Chapitre 1

    Introduction

    Depuis de nombreuses annes, dans diffrents pays, les informaticiens ayantquelques prtentions acadmiques ont lutt pour tablir leur discipline de manireindpendante. Sans vouloir dire que la lutte est termine (certains nayant pas encoreaccept que la terre nest pas plate), on peut constater que, dans les universitsrespectes, il existe des laboratoires dinformatique independants, des diplmesspkialiss, et *les enseignants et/ou chercheurs en informatique sont dsormaisconsidr& comme des scientifiques a part entire.

    Pourquoi cette lutte ? Et pourquoi en parler dans un livre sur lalgorithmique ?Le fait est que les informaticiens ont reprsent - et reprsentent toujours - unenjeu conomique. Comme cet enjeu a t concrtis par des moyens matriels etfinanciers mis a la disposition des enseignants et des chercheurs en informatique,tout un chacun a prouv le besoin de rclamer letiquette. Le tri entre les vrais etfaux informaticiens nest pas termin. Dailleurs, notre avis il ne le sera jamais,et cest peut-tre heureux ainsi.

    Malheureusement, en voulant affirmer leur indpendance par rapport aux autresdisciplines, les informaticiens ont perdu une partie de lessentiel. En se concentrantsur les techniques non-numriques (importantes et indispensables), ils ont perdujusqu la notion de lexistence des nombret rels. De mme, un peu en singeant lesmathmaticiens, qui ont montr la voie vers la tour divoire, le besoin scientifiquemais aussi psychologique de la construction dune (ou de plusieurs) thorie(s) a faitperdre la vraie justification de notre existence : lcriture de programmes qui sontutiles. On est donc en prsence de plusieurs guerres, numrique contre non-numerique, thorie contre application, utilisateurs contre spcialistes, vendeurs devent contre professionnels srieux. Si certaines guerres peuvent tre utiles etsalutaires, dautres resteront toujours striles.

  • Ce livre ne saurait bien sr en corriger les carts. Mais nous voulonstmoigner de notre foi dans lexistence de linformatique en tant que disciplineindpendante, mais surtout utile. Linformaticien comme le mathmaticien - mmesi ce dernier la peut-tre oubli - est un esclave des autres. Sa raison dtre est derendre service, cest--dire rsoudre des problbmes dapplication. Il ny a pasdinformatique acadmique diffrente de celle de lapplication numrique ou degestion. Il ny a pas une micro-informatique diffrente de linformatique classique.Il y a une seule discipline, appele intervenir dans un trs grand nombre dedomaines de lactivit humaine.

    &GORllMMIQUEEl-PROG?bU&MIlON

    Cest en respectant lide que tous nos lbves savent un minimum sur laprogrammation qua disparu le chapitre de ce livre destins aux d6butants. Ainsi, lestypes de donnes de base (entiers, tiels, caractres), leurs reprkwnations en machineet les instructions simples (affectations, boucles, conditions) ne sont pas dfinis dansce volume.

    Dans cette optique, la formation des informaticiens dans les universits et lescoles dingnieurs doit se faire de manire quilibre. Un de nos critres est quesi nous ne traitions pas tel sujet, nous pourrions par la suite avoir honte de nos&ves ?. Le monde du travail sattend ce que nos lves sachent programmer (dansle langage quutilise la compagnie concerne), quils connaissent un minimum demthodes de rsolution de problmes numriques, et que probabilits etstatistiques ne soient pas des mots sotkiques rechercher dans le dictionnaire. Lecours dcrit dans ce livre essaie de prendre en compte ces considrations. Nouslenseignons, dans des variantes appropries, depuis vingt-cinq ans, des Bves depremier et de deuxime cycle, en formation permanente, dans des diplmessptkialiss ou non. Lexprience a montr que lenseignement de ce cours de base delinformatique est difficile, que personne ne possbde une recette miracle, mais quetout le monde (surtout ceux qui nont jamais crit un logiciel utilise par dautrespersonnes) pense lenseigner mieux que les autres.

    Nous prsentons donc ici, humblement (ce nest pas notre tendance profonde),quelques ides dun cours dalgorithmique et de programmation dont le niveaucorrespond a la premire anne dun deuxibme cycle pour spcialistes eninformatique, en supposant que les lves concerns nont pas ncessairement subiune formation pralable dans la matire, mais quils sachent tous un peuprogrammer Cela pose dailleurs un probleme particulier. Nous avons lhabitude demlanger des tudiants dorigines divers. Les uns peuvent avoir obtenu de bonsrt%ultats dans un IUT dinformatique, tandis que dautres nont que peu touch unclavier (situation de plus en plus rare, mais ltkiture dun programme de 10 lignes enBASIC peut tre considre comme une exprience vide, voire ngative, eninformatique). A la fin de la premire anne de deuxime cycle, il reste unecorrlation entre les tudes prealables et les rsultats acadmiques. Cette corrlationdisparat au cours de la deuxime anne, provoquant quelques remontesspectaculaires au classement. La seule solution que nous avons trouv ce problemede non-homognit est de lignorer en ce qui concerne le cours, mais damnager desbinmes mixtes en TP. Lexprience jusqualors est positive.

    Dans sa forme actuelle, le cours dure une anne scolaire, au rythme de deuxheures par semaine. Il est ncessairement accompagn de travaux diriges et de travauxpratiques. Chez nous, il y a trois heures de travaux dirigs et quatre heures de travauxpratiques par semaine. De plus, la salle informatique est ouverte en libre service auxCtudiants autant de temps que possible en respectant les rgles lCmentaires descurid. Ce nest quau prix de la mise disposition dun mat&iel suffisant que les&udiants peuvent rellement apprendre.

    Nous proposons de nombreux exercices et problbmes. Le sujet que nousattaquons ncessite un investissement personnel important. Le cours doit servir stimuler des efforts individuels et la ralisation de projets de toutes sortes. Il doitobligatoirement se terminer par la cration dun logiciel en grandeur nature, depr6fkence produit par un petit groupe dleves (deux quatre).

    Les exemples dans ce livre sont rkligs dans un langage de programmationfictif qui ressemble a PASCAL. Comme boutade bien connue des quelquesuniversits layant subi, le langage dans lequel nous rdigeons nos algorithmes a prisle nom GRIFFGOL, qui rsulte de rflexions de lpoque de MEFIA [Cunin 19781.Cest un style de programmation relativement indpendant dun langage deprogrammation particulier, cest--dire que nous utilisons les concepts fondamentauxdans la forme qui nous semble la plus approprie. La construction des algorithmes sepasse mieux quand on se permet une certaine libert dexpression. Leur mise enuvre dans un ordinateur ncessite une simple mise en forme en fonction du langageet du compilateur disponibles.

    Un corollaire est que nous disons nos tudiants quils doivent toujoursr+ondre oui a la question connaissez-vous le langage X ?, quelle que soit lavaleur de X. En effet, sous condition que le langage soit de style algorithmiqueclassique, lapprentissage dun langage et/ou dun compilateur inconnu ne devraitdurer que quelques jours. Dailleurs, un exercice classique que nous pratiquons est defaire recoder un travail pratique dans lun ou lautre des langages grande diffusionque nos tudiants ne connaissent pas. Cest ainsi quils absorbent, par exemple,FORTRAN. En pratique, a lheure actuelle, ils programment dans une version dePASCAL, avec des prolongements en C. Le choix est remis en cause chaquerentre universitaire, car nous ne sommes pas des missionnaires dun langagequelconque.

    14 1 5

  • &GORlTHMIQUEETPROGR4MMATION &CiORITHMIQUFi I?I PROGRAMMMION

    1.1. Quelques mots sur lenvironnement

    Une petite phrase ci-dessus merite quon sy attarde un peu plus longtemps.Nous avons parl de la disponibilit de matriels, essentielle lapprentissage de laprogrammation, qui est une activit constructive. On ne peut apprendre quensexerant. Or pour sexercer de manire satisfaisante, lidal, si nous pouvons nouspermettre le parallele, est que les ordinateurs doivent tre comme les WC : il y en atoujours un de libre quand on en a besoin, voire mme quand on en a envie. (Cettephrase a t prononce pour la premire fois, notre connaissance, par P.M.Woodward, du Royal Radar Establishment MaIvern, Angleterre. Cest un plaisir derendre cet amical hommage a un matre mal connu, en se rappelant quen 1964 ilfallait une vision tr&s large pour sexprimer ainsi.).

    Certains de nos collgues restreignent volontairement le ct exprimental dela programmation, dans le but dimposer, ds le dbut de lapprentissage, toute larigueur ncessaire. Cest une reaction saine par rapport une situation historiquedatant de lpoque o la programmation se faisait nimporte comment. Mais nousnallons pas jusqu empcher nos leves de faire leurs btises. Cest en comparantdes versions sauvages de programmes avec dautres qui sont bien faites quilscomprennent rellement lintrt dune mthodologie.

    Ainsi, nous voulons que les lves passent beaucoup de temps dans la salle desmachines. Au dbut, ils travaillent mal, mais deviennent - pour la plupart -raisonnables la fin de la premire anne. Cette approche profite dune certainefascination pour lordinateur (la jouissance de le dominer ?), qui sestompe aprs cettepremire anne. Le fait de vouloir rflchir, plutt que de se lancer immdiatementsur la machine, est un signe majeur de maturit chez llve. Cette tape ne peut trefranchie que parce que le matriel est toujours disponible. Un tudiant ne doit pastre stress par la longueur dune file dattente, ni frustr par des difficultsmatrielles. Nous notons dailleurs que, bien que les programmes crits en deuximeanne soient assez importants, loccupation des postes de travail diminue.

    Lentranement la programmation est une ncessit pour tous lesinformaticiens, quelle que soit leur exprience. Une source de stimulation pour lesleves est de travailler en contact avec des enseignants qui programment bien. Tantquils sentent quil leur reste du chemin a faire pour arriver au niveau de rendement dece modle, ils se piquent au jeu. Cela signifie que lenseignant doit lui-mmecontinuer a programmer rgulirement, comme le musicien qui continue faire desgammes. Mme si nous navons plus le temps de produire de gros logiciels, il fautsastreindre rsoudre rgulirement des petits problmes. Ceux-ci peuvent, par lasuite, contribuer au renouvellement de notre stock dexemples et dexercices.

    1.2. Notes bibliographiques sommaires

    Il existe dj, en franais, un certain nombre de livres [Arsac 19801, [Arsac19831, [Berlioux 19833, [Boussard 19831, [Courtin 1987a,bl, [Gerbier 19771,[Grgoire 1986, 19881, [Lucas 1983a,b], [Meyer 19781, [Scholl 19841 dans ledomaine que nous abordons ici. Un pourcentage lev porte un nom dauteur quinous est familier, car il sagit de collgues et souvent amis. Cela indique que lesreflexions concernant ce sujet sortent, en France au moins, dun nombre limitedcoles qui, en plus, ont pris lhabitude de discuter. Le nombre de livres indiquelimportance que chacun accorde au sujet, et les diffrences dapproche dmontrentquil est loin dtre puise. Comme dans la tradition littraire, il y aura toujours desides differentes sur ce sujet. En continuant le parallble avec lcriture, nousrecommandons aux &udiants de prendre connaissance de plusieurs styles diffrents,puis de dvelopper leur propre style en profitant des apports de chacun.

    Ayant indiqu quelques livres en franais, il serait draisonnable de laisserlimpression que la France poss&le un monopole des ides. Au niveau international,il existe une bibliographie consquente en langue anglaise, dont voici les rferencesqui correspondent une selection personnelle parmi les ouvrages les plus connus :[Aho 1974, 19831, [Dijkstra 19761, [Gries 19811, [Ledgard 19751, I\irirth 1976,1 9 7 7 1 .

    1.3. Remerciements

    Sur un sujet tel que le ntre, il serait impensable de citer tous ceux qui ontinfluenc notre reflexion. Nous nous limitons donc la mention de quelques groupesde personnes, en nous excusant vis--vis de tous les collegues que nous ne citons pasindividuellement.

    Comme premire influence directe, il y a eu le groupe de P.M. WoodwardMalvem au dbut des annes soixante. Lauteur y a fait ses premieres armes, et sespremiers cours, partir de 1962, sous la direction de J.M. Foster et D.P. Jenkins,avec IF. Currie, A.J. Fox et P.R. Wetherall comme compagnons de travail. Lefoisonnement clidees Grenoble entre 1967 et 1975 a te dune grande importance.Signalons seulement une collaboration directe avec P.Y. Cunin, P.C. Scholl et J.Voiron [Cunin 1978, 19801, bien que la liste aurait pu tre nettement plus longue.LCcole de C. Pair Nancy a montre la rigueur et a donn des opportunits decomparaison de styles. Finalement, la cr&tion du diplme dingnierie informatiquea Marseille en 1985 a provoqu un effort de synthese dont le r&sultat est ce volume.De nouvelles versions du polycopi ont vu le jour Nantes en 1990 et 1991.

    16 17

  • Des rencontres ponctuelles ont aussi eu leur importance, en particulier a traversles t5coles organiss par F.L.Bauer [Bauer 1974, 1975, 1976, 19791. Celles-ci ontpermis de travailler avec son quipe et de rencontrer et de se confronter avecE.W.Dijkstra, G.Goos, D.Gries, J.J.Horning, P.C.Poole et W.M.Waite, parmi denombreux autres collegues.

    Le feedback de gnrations dtudiants nous a permis de constater quelapprentissage de linformatique nest pas toujours aise si lon veut atteindre un bonniveau. Nous remercions ces jeunes (certains ne le sont plus) pour leur apport, dontils ne se sont pas toujours rendu compte (nous aussi, nous apprenons !). EmmanuelGaston du DU-II et un groupe du mastere dintelligence artificielle de Marseille,promotion 198889, ont corrige un certain nombre derreurs de franais. NathalieWurbel a aide en signahtnt des erreurs de franais et de programmation. ChristianPaul et Annie Ttiier ont galement apport des corrections au niveau du franais. Aucours dun projet du DU-II, Vita Maria Giangrasso et Thierry Guzzi [Giangrasso19891 ont men bien une tude comparative de certains algorithmes. Le journalJeux et Stratgie, source de problmes intressants, nous a aimablement permis denutiliser dans certains exemples.

    Ce livre a t prpar sur des micro-ordinateurs mis a notre disposition pardifferents organismes, dont feu le Centre mondial dinformatique et ressourceshumaines, le CNRS, luniversit dAix-Marseille III, linstitut mditerranen detechnologie et luniversit de Nantes, que nous remercions.

    Un dernier mot sera pour mon collgue, et surtout ami, Jacek Gilewicz,professeur a luniversit de Toulon. Au dbut, nous avions envie de prparer un livrecombinant lalgorithmique numrique et non numrique. Pour diffrentes raisons, ceprojet na pas vu le jour. Lutilisation du nous dans cette introduction reprsente cepluriel. Je lai laiss dans cette version definitive, en esprant que Jacek redigera levolume numrique dont nous avons besoin, en mme temps que je lui tmoigne mareconnaissance pour son soutien et son amiti sans faille. Ce livre lui est ddi.

    1.4. Le choix de programmes

    On apprend crire des programmes en pratiquant. Cest pour cette raison quenous travaillons partir dexemples. Ceux-ci sont de plusieurs types :

    - les classiques, qui se trouvent dj dans dautres ouvrages, mais qui sontessentiels a la culture dun informaticien,

    - les pdagogiques, que nous avons cres ou repris comme matriel de base. Ici,on attrait pu en choisir dautres, mais chaque enseignant a sa liste dexercices,souvent partage avec des collegues,

    - les amusements, qui sont la parce quils nous ont fait plaisir, mais quiprsentent nanmoins un intrt pour Itudiant.

    18

    ftWORIIUMlQUE FX PROGRAMWUTON

    Libre a chacun dapprcier notre choix. De toute faon, il est entendu que chaqueenseignant mettra la matire a sa sauce.

    Dans la mesure du possible (ou en fonction de nos connaissances), nous avonsessay dattribuer la paternit des exemples, mais beaucoup dentre eux ont desorigines dj inconnues. Toute information supplementaire sera le bienvenue.

    1 9

  • Chapitre 2

    Des programmes pour commencer

    2.1. Le mode dun vecteur

    Ce problme nous est venu de D. Gries, qui lutilise depuis longtemps dans sescours dintroduction linformatique. 11 a t repris par diffrents auteurs dans le cadrede lanalyse dalgorithmes [Arsac 19841, [Griffiths 19761.

    On considre un vecteur, disons dentiers, dont les lments sont ordonns. Sonmode est la valeur de llment qui y figure le plus grand nombre de fois. Ainsi,prenons le vecteur suivant :

    (1 3 3 6 7 7 7 11 13 13)

    Le mode de ce vecteur est la valeur 7, qui figure trois fois. Nous allons crire unprogmmme qui prend en entre un vecteur ordonn et qui livre le mode du vecteur ensortie.

    2.1.1. Construction de la premire version du programme

    Commenons par une premire ide dalgorithme. On note quelordonnancement du vecteur fait que les diffrentes occurrences dun lment qui serpkte sont contigus. II sagit donc de trouver la plus longue chane dlmentsidentiques. On va considrer les lments tour de rle, en se rappelant de la pluslongue chane vue jusqu prsent. Pour chaque nouvel lment, on se posera laquestion de savoir si sa lecture mne une chane qui est plus longue que lapr&dente. Dans ce cas, cest la chane courante qui devient lachane la plus longue.

  • hOORlTHMQUE J.?T PROGRAMhUTlON

    Pour garder les informations ncessaires, il faut disposer des valeurs suivantes :- n est le nombre dlments dans le vecteur v,- i est le nombre dlements qui ont dj t considrs,- lmaj, est la longueur de la plus longue chane en v[l..il,- m est lindex en v dun lment dans la chane de longueur lmax :

    v[m] = mode(v[l ..i]),

    - lc est la longueur de la chane courante (a laquelle appartient V[il).On appellera cet ensemble de definitions ltat du monde (state of the world).

    Le programme 2.1, qui met en uvre ces ides, est une application du schmasuivant :

    InitialiserTANTQUE NON finiFAIRE avancerFAIT

    Le programme est comment par la suite.

    DEBUT DONNEES n: entier;v: TABLEAU [1 ..n] DE entier;

    VAR i, max, m, lc: entier;i:=l ; Imax:=l ; m:=l ; Ic:=i ;TANTQUE knFAIRE i:=i+l ;

    SI V[i] = V[i-l ]ALORS IC:=I~+~;

    SI blmaxALORS Imax:=lc; m:=iFINSI

    SINON Ic:= 1FINSI

    FAITFIN

    Programme 2.1. Le mode dun vecteur

    Les donnes du problme sont n, la longueur du vecteur, et le vecteur ordonn,v Les deux sont initialiss par ailleurs. Aprs les dclarations des objets de ltat du

    2 2

    liLOORllHMlQUE W PROGRAMMKCION

    monde (i, lmax, m, lc), la phase dinitialisation sert leur donner des valeurspermettant de dmarrer. Cette ligne correspond au traitement du premier lment : lachane maximum est la chane courante, de longueur 1. Dans le TANTQUE, commei est le nombre dlments dja traits, le test de la fin est bien icn (autrement dit, ilreste des ellments a considrer). Pour avancer, on prend le prochain element (i:=i+l),en se demandant si lexamen de cet Blment met en cause ltat du monde. Il y a deuxCaS : soit on allonge la chane courante (V[i] = V[i-l]), soit on commence unenouvelle chane. La nouvelle chane, dcrite dans la partie SINON, est de longueur 1(1~~1) et ne met pas en cause lmax ou m (qui ne sont donc pas modifis). Si lachane courante a t allonge (partie ALORS), on augmente lc (lc:=lc+l) avant detester si la chane courante est devenue la chane maximale (SI lolmax). Dans cecas, hnax et m sont mis a jour (hnax:=lc; m:=i).

    Nous prtendons que cette construction dmontre la justesse du programmedonn. La dmonstration depend de lacceptation de la rcurrence ( partir du cas i-lon cr6e le cas i, le cas 1 tant trait dans linitialisation) et de la validit de ltat dumonde. En particulier, dans la boucle, avancer est fait par i:=i+l et les autresinstructions remettent les ClCments de ltat du monde jour en fonction de ce queIon y trouve.

    Pour tre complet, revenons sur la confirmation du nouvel tat du monde.i a avanc de 1, ce qui est correct. lc a pris une valeur de 1 (nouvelle chane) ou delc+l (allongement de la chane en cours). La chane courante devient la chane laplus longue si lolmax. Dans ce cas, lmax et m reoivent des valeurs appropries.Comme tous les lments de ltat du monde ont des valeurs correctes, le programmeentier est juste.

    2.1.2. Remarques mthodologiques

    La construction dun programme correct dpend de la logique employee par sonc&teur. Cette logique ne peut sexercer que si les bases dclaratives sont saines.Cest ici quune bonne formalisation de letat du monde est fondamentale. Cet tat dumonde peut tre dcrit en franais (ou en anglais ou en polonais, nous ne sommespas racistes) ou en style mathmatique. Le choix entre les deux (ou les quatre) stylesest une question de got et de type dapplication.

    Mais, que ltat du monde soit crit en franais ou en formules mathmatiques,il se doit dtre prcis. De nombreux programmeurs agrmentent leurs programmesavec des commentaires du type Y est lindex de llment de Y. Ils font souventlerreur classique de confondre le dernier lment traite avec son suivant (celui qui vatre mit).

    2 3

  • .&GORlTHMIQUEETPROGRAhM4TION &GORITHMIQUE ET PROGRAhthUTlON

    rien du tableau, cest--dire quil faut en examiner tous les lements pour dmontrerlabsence eventuelle de lobjet recherche. Bien sr, le programme sarr&era ds quelobjet est trouv6. Par la suite, nous montrerons comment rendre lalgorithme plusefficace en introduisant des connaissances concernant la forme des donnes.

    Lutilisation de tableaux et de boucles impose dautres contraintes. Enparticulier, il faut dmontrer la terminaison de chaque boucle et confirmer que lindexde chaque rc?f&ence a un lment de tableau est entre les bornes (i doit tre contenu en[ l..nl).

    Pour la terminaison de la boucle, il ny a pas de probleme ici. La variable decontrle i est augmentee de 1 chaque tour de la boucle, et arrivera donc n pourarrtfx le massacre.

    Les seules n5ferences a des lements de tableaux sont dans le test SI v[i]=v[i-11.i commence a un et la boucle sarrte quand i=n. Avant laffectation i:=i+l lintkieur de la boucle, on a donc lingalite suivante :

    I~i43

    Apres laugmentation de i, ceci devient :

    1 ODEBUT VAR i: entier, trouv: bool;

    i:=O; trouv:=FAUX;TANTQUE kn ET NON trouvFAIRE i:=i+l ; trouv := t[i]=objetFAIT

    POSTCOND (trouv ET objet=t[i]) OU (NON trouv ET i=n)FIN

    Programme 2.2. Recherche dun objet dans un vecteur

    Le programme est encore une application du schma suivant :

    InitialisationTANTQUE NON finiFAIRE avancerF A I T

    24 25

  • hOORITHMIQUE! GT PROGRA~ION fiLGORITHhtIQUEETPROGRA-ION

    Que sait-on sur ce programme ? Une premiere dduction, vidente, est que,comme le programme a quitte la boucle, la condition de continuation de la boucle estmaintenant fausse. Ainsi, apres FAIT, on peut dduire :

    Linitialisation de ltat du monde dit que, le programme nayant rien vu (i:=O),lobjet na pas encore t trouv (trouv6:=FAUX). Pour avancer, on augmente i de 1et on remet trouv a jout Le processus peut terminer soit par la russite (trouvedevient VRAI), soit par linspection du dernier lment (i=n). Notons que les deuxconditions peuvent tre vrifies en mme temps, car lobjet peut se trouver en t[nl.La boucle termine, car i augmente chaque tour. Lindex de la seule rfrence tri]est juste, car linitialisation et la condition de la boucle font que k-icn a lentredans la boucle. Avec laugmentation de la valeur de i, ceci devient CkiO;DEBUT VAR i: entier, trouv: bool;

    i:=O; trouv:=FAUX;TANTQUE kn ET NON trouvFAIRE i:=i+l ; trouv := objet=t[i]F A I T

    FIN

    NON (icn ET NON trouv).

    Par application de la loi de Morgan, ceci devient :

    irn OU trouv.

    Comme i navance que dun pas la fois, on peut dduire :

    i=n OU trouv.

    Les OU de linformatique tant inclusifs, les deux clauses peuvent tre vraiesen mme temps (cas de t[n] = objet). Les post-conditions du programme donnsuivent logiquement, en considrant laffectation la variable trouv dans lintrieurde la boucle.

    En gnral, on peut souhaiter que la post-condition se retrouve partir de lapr-condition, de dductions du type donn ci-dessus et des dfinitions de ltat dumonde. Mais la post-condition que nous avons jusquici est incomplte. Quandlobjet a t trouv, i indique bien son emplacement, mais la non-russite est maldcrite. Nous navons pas encore expliqu que NON trouv veut dire que lobjet estabsent.

    Lerreur, classique, a t de construire les pr- et post-conditions aprbs coup. Ilaurait fallu spcifier le programme avant de lcrire, les conditions servant despcification. Dans notre cas, on aurait :

    PRECONDSoient un objet et un vecteur t de longueur n, n>O;

    POSTCONDOu t[i]=objet,ou il nexiste pas i, O&n, tel que t[i]=objet.

    Notons que la variable trouv ne figure plus dans la post-condition. Elle sert distinguer les deux cas de solution. Il faut maintenant dmontrer la vrit de cettenouvelle post-condition. Quand lobjet a t trouv, la logique prcdente estsuffisante. Pour montrer labsence de lobjet, il nous faut une clause de plus.Reprenons le texte avec de nouvelles dcorations :

    26 27

  • DONNEES objet, n: entier; t: TABLEAU [l ..n] DE entier;PRECOND n>O;DEBUT VAR i: entier, trouv: bool;

    i:=O; trouv:=FAUX;TANTQUE kn ET NON trouvFAIRE INVARIANT O t[j] f objet;

    i:= i+l; trouv := t[i]=objetF A I T

    POSTCOND t[i]=objet OU i (O&n => t[i]#objet)F I N

    Linvariant dit que la boucle nest excute que si lobjet na pas encore ttrouv. La post-condition peut maintenant tre dmontre. En effet, Zi la terminaisonde la boucle, si trouvb est FAUX, alors i=n ET t[i] nest pas lobjet. Mais avantdexcuter linstruction i:=i+l, aucun tu], On, cest--dire que le premier oprande est FAUX, on nvalue pas ledeuxikme. Cela dpend du fait que (FAUX ET b) est toujours FAUX, quelle que soitla valeur de b. Il existe galement loprateur OUALORS (COR). Les dfinitionsde ces oprateurs sont les suivantes :

    a ETPUIS b J SI a ALORS b SINON FAUX FINSIa OUALORS b J SI a ALORS VRAI SINON b FINSINotons que ces deux dfinitions sont celles qui se trouvent dans beaucoup de

    livres de logique pour ET et OU, mais ces oprateurs ne sont pas mis en uvre decette faon dans tous les compilateurs.

    2.2.3. La dichotomie

    Quand on ne sait rien sur les lments dun tableau, pour tablir quune valeurdonne ne sy trouve pas, il faut inspecter tous les lments, car la valeur peutfigurer nimporte quelle place. Maintenant, nous allons considrer un cas plusintressant, o les lments du tableau sont ordonns. Cest comme laccs unannuaire tlphonique. Pour trouver le numro de M.Dupont, on ne regarde pastoutes les entres de A DUPONT, On procde par des approximations.

    Pour nous faciliter la programmation, nous allons procder par desapproximations simples. Dans un annuaire de 1000 pages, on regarde la page 500.

    28 29

  • ALOORIlNh4IQUE ET PROGRAMMtUlON &GORIITMQUE I ? I - PROGRAMMtWON

    La pr-condition exprime le fait que nous disposons dun vecteur ordonn daumoins deux lments. Linitialisation indique que le domaine de recherches estt[l..n], lobjet ntant pas encore trouv. La condition apres TANTQUE mrite desexplications. La proposition NON trouv est vidente, mais la partie avant le ETlest moins. Pour considrer une valeur intermdiaire, nous imposons quelle soitdiffrente des deux extrmes, cest--dire que linegalit suivante soit vraie :

    Si llment recherch est alphabtiquement plus petit, on a restreint la recherche auxpages 1 499, ou, sil est plus grand, aux pages 501 a 1000. Chaque regard coupe ledomaine de recherches en deux. Les recherches sarrtent si llment examine est lebon, ou si le domaine de recherches est devenu nul (lobjet est absent).

    Considrons une Premiere version de ce programme, avec ltat du mondesuivant :

    bas, haut: entier, SI t[iJ=objet ALORS bas s ii hautcentre: entier, t[centre] est Ielment examinertrouv: boolen, trouv j t[centre]=objet

    Appliquons comme dhabitude le schma :

    InitialisationTAfiTQUE NON finiFAIRE avancerFAIT

    Le programme 2.3 est une solution possible.

    DONNEES n: entier, t: TABLEAU [l ..n] DE entier;PRECOND n>l ET (O&jg => t[i]s[i])DEBUT VAR bas, haut, centre: entier, trouv: bool;

    bas:=1 ; haut:=n; trouv:=FAUX;TANTQUE haut-bas>1 ET NON trouvFAIRE centre:=entier((haut+bas)/2);

    CHOIX t[centre]cobjet: bas:=centre,t[centre]=objet: trouv:=VRAI,t[centre]>objet: haut:=centre

    FINCHOIXFAIT;SI NON trouvALORS SI t[bas]=objet

    ALORS centre:=bas; trouv:=VRAlSINON SI t[haut]=objet

    ALORS centre:=haut; trouv:=VRAlFINSI

    FINSIFINSI

    FINPOSTCOND trouve => t[centre]=objet,

    NON trouv => i, O&n, t[i]#objet

    Programme 2.3. Recherche par dichotomie

    Proposition A. bas < centre e haut

    Cette inegalit ncessitant lexistence dau moins une valeur entre bas et haut,on retrouve :

    Proposition B. haut - bas > 1

    Dans la boucle, le calcul de la valeur de centre ncessite une conversion, par lafonction entier, du rsultat de la division, qui est un nombre rel, en un nombreentier. On confirme facilement que centre est bien entre haut et bas en appliquant laproposition B ci-dessus. Quand la somme (haut + bas) est impaire, la division pardeux donne un nombre relle de la forme n,5. Que larrondi vers un entier donne n oun+l na aucun effet sur lalgorithme (les deux possibilits respectent la propositionA). Par la suite, la clause CHOIX force un choix entre les trois possibilits ouvertesaprs comparaison de lobjet avec t[centre]. Ou lobjet a t trouv (tkentre] = objet),ou le domaine de recherches est coupe en deux (bas:=centre ou haut:=centre, suivantla condition).

    Si lobjet est trouv, tout va bien. Si la boucle se termine sans trouver lobjet,haut et bas sont maintenant deux indices successifs :

    haut = bas + 1

    La derniere partie du programme teste si lobjet se trouve en t[haut] ou [email protected]]. Ce test est irritant pour le programmeur. Il nest utile que si t[l]=objet out[n]=objet, car ds que haut ou bas change de valeur, ils prennent celle de centre,t[centre] ntant pas lobjet. Donc le test ne sert que si lune des variables haut ou basa garde sa valeur initiale.

    En fait, le test est d a une faiblesse de spcification. Il faut dcider si oui ounon t[haut] ou t[bas] peuvent contenir lobjet, et cela de maniere permanente.Essayons deux nouvelles versions du programme. La Premiere respecte lesinitialisations de loriginal, ce qui veut dire que t[haut] ou t[bas] peut toujourscontenir lobjet :

    30 31

  • hGORlTHMIQUEETPRWRAhtMTION

    DONNEES n: entier, t: TABLEAU (1 ..n] DE entier;PRECOND n>l ET O&jg => t[ikt[i]DEBUT VAR bas, haut, centre: entier, trouv: bool;

    bas:=1 ; haut:=n; trouv:=FAUX;TANTQUE haukbas ET NON trouvFAIRE centre:=entier((haut+bas)/2);

    CHOIX t[centre]objet: haut:= centre - 1

    FINCHOIXFAIT

    FINPOSTCOND trouv => t[centre]=objet,

    NON trouv => i, O&n, t[i]+objet

    Programme 2.4. Dichotomie, version 2

    Trois changements figurent dans cette version du programme par rapport loriginal. Dans le choix, quand t[centre] nest pas lobjet, la nouvelle valeur de bas(ou haut) ne doit pas se situer sur le centre, mais un pas plus loin, sur le premiercandidat possible (centre est le dernier lment rejet). En plus, dans le TANTQUE,au lieu de proposition B, nous avons simplement :

    haut 2 bas

    Quand la proposition B est vraie, la situation na pas change par rapport laversion originale. Quand haut=bas, centre prend cette mme valeur et lon teste ledernier candidat. Si ce nest pas le bon, on ajuste haut ou bas, avec le rsultat :

    bas > haut

    Quand haut suit immdiatement bas, centre va prendre une valeur qui est soitcelle de haut, soit celle de bas (il ny a pas despace entre les deux). Mais, grce aufait que bas, OU haut, prend sa nouvelle valeur un cran plus loin que le centre, anprochain tour de la boucle, on aura :

    bas = haut ou bas > haut

    La boucle termine toujours. La preuve de la correction de ce programme peutse faire partir des assertions suivantes :

    32

    Al. O&bas => t[i].cobjetA2. haut&n => t[i]>objet

    hCiORIll+MIQUE ET PROGRAMMMION

    La condition de terminaison bas > haut montre alors labsence de lobjet dans t.Cela correspond la deduction que lon peut faire la sortie de la boucle :

    NON (haut 2 bas ET NON trouv)

    Cest--dire :

    bas > haut OU trouv

    bas > haut est la condition dabsence, trouv implique t[centre] = objet.

    La deuxime bonne solution notre problme est de faire en sorte que ni t[bas]ni t[haut] ne peut tre lobjet. Considrons la version du programme 2.5.

    DONNEES n: entier, t: TABLEAU [i ..n] DE entier;PRECOND n>l ET O&jg => t[ikt[i]DEBUT VAR bas, haut, centre: entier, trouv: bool;

    bas:=O; haut:=n+l ; trouv:=FAUX;TANTQUE haut-bas>1 ET NON trouvFAIRE centre:=entier((haut+bas)/2);

    CHOIX t[centre]objet: haut:=centre

    FINCHOIXF A I T

    FINPOSTCOND trouv => t[centre]=objet,

    NON trouv => i (O&n => t[i]#objet)

    Programme 2.5. Dichotomie, version 3

    Dans cette version, seules les initialisations de bas et haut ont t modifies.Ces variables prennent des valeurs dindices inexistantes. Mais ce nest pas grave, carles Kments correspondants ne seront jamais rfrencs. La preuve de cette versiondu programme est facile. Elle est la mme que celle de la version originale, sauf pourItive a la situation :

    haut = bas + 1

    33

  • kOORIlWMIQUE F?I- PROGRAMMATION

    Dans ce cas, comme ni t[haut], ni t[bas] nest lobjet, celui-ci nest pas dans t,car il ny a pas dlment entre t[haut] et @as].

    La technique consistant a utiliser comme bute une valeur inexistante (ici enconsidrant [O..n+l] au lieu de [l..n]) est utilise frquemment par de bonsprogrammeurs. Notons quil na pas t ncessaire de crer rellement les lmentsfictifs introduits.

    2.3. De la complexit des algorithmes

    Le parallle avec lannuaire tlphonique montre que les performances de cesdeux algorithmes (recherche lin6aire et recherche dichotomique) sont trs diffrentes.Leur complexit est facile tablir.

    Pour la recherche linaire :- Si lobjet est prsent dans le tableau, il peut tre nimporte o. En moyenne,

    le programme examine n/2 lments avant de trouver le bon.Si lobjet est absent, on examine tous les n lments.

    La complexit de lalgorithme est donc de o(n). Cela veut dire que si lon doublait lenombre dl6ments, les recherches dureraient en moyenne deux fois plus longtemps.

    La dichotomie est tout autre. Ici, un doublement de la taille du tableauncessite un seul pas supplmentaire (chaque examen dun lment divise la taille dudomaine de recherche par deux). Considrons le cas dun tableau de 2k lments.Apres un pas, on a 2k-1 lments a considrer, aprs deux pas, 2k-2, . . . . aprs k pas,un seul lment (20). La dichotomie a donc une complexit de o(log2 (n)).

    La diffrence entre ces deux courbes est trs importante, surtout quand lenombre dlments est grand. La table 2.1 compare le nombre maximum de pas (n)dans le cas de recherche linaire avec le nombre maximum de pas avec la dichotomie.

    n dichotomie

    10 4 (24= 16)100 7 (2= 128)1000 1 0 (2O= 1024= lk )1 000 000 2 0 (2O = 1024k = 1 048 576)

    Table 2.1. Comparaison entre la recherche linaire et la dichotomie

    3 4

    /UOO-QUE ET PROGRAhGfA-MON

    Dans le jargon de linformatique, on parle de la r6duction dun problme en nvers un problme en n-l (recherche linaire), ou vers un problme en n/2(dichotomie). Par la suite, dans le chapitre 3 sur les tris, nous verrons que danscertains cas, on rduit un problme en n vers deux problbmes en n/2. On appellecette demiete technique lart de diviser pour rgner (divide and conquer).

    Nous tirons deux conclusions de cette brve discussion. La premire est que desconnaissances minimales sur le calcul de la complexit des algorithmes sontnecessaires si lon veut pratiquer de linformatique B un bon niveau. Le sujet, assezdifficile, est trs tudi par des chercheurs. Ces recherches demandent surtout descomptences leves en mathmatiques. Mais on peut faire des estimations utilesavec un bagage limite. La deuxieme conclusion concerne lefficacit des programmes.On voit souvent des programmeurs schiner sur leurs programmes pour gagner uneinstruction ici ou l. Evidemment, dans certains cas prcis, cela peut devenirncessaire, mais cest rare. Le gain defficacit est limit. Mais le probleme nest pasle mme au niveau des algorithmes, comme lattestent les chiffres de la table 2.1.Des gains defficacit travers lalgorithmique peuvent tre importants. Il nest pastres sens doptimiser un mauvais algorithme - mieux vaut commencer avec unbon. Loptimisation locale peut se faire par la suite en cas de besoin.

    2.4. Rsum des principes introduits

    Au cours de ce chapitre, nous avons introduit plusieurs principes importants,qui forment la base de notre technique de programmation.

    Nous travaillons souvent B partir dun schma de programme (pro-scheme). Cest une maquette qui indique la structure gnrale. Le seul schmautilise jusquici est celui dun processus linaire :

    InitialiserTANTQUE NON finiFAIRE avancerFAIT

    On complte le schma linaire en utilisant un tat du monde, qui est unedfinition prcise des variables. Cet tat permet de confirmer la justesse duprogramme en lexploitant comme une liste a cocher en @onse des questions dutype suivant :

    - Est ce que ltat du monde est completement initialis avant la boucle ?- Quel est leffet de lopration avancer sur chaque lment de ltat du monde ?

    Lexistence dune definition prcise des variables facilite la dfinition de la

    3 5

  • &OORITEIMIQUFi ET PROGRAMMtWION &GORITlMQUE EI- PROGRAMMtWION

    condition de terminaison. De mme, expliciter la notion davancer diminue laprobabilit de lcriture de boucles infinies. Nanmoins, pour viter cettemsaventure, on dmontre consciemment (et consciencieusement) la terminaison dechaque boucle. Le r6flexe de dmonstration de validit doit aussi jouer chaque foisque lon repre un lment de tableau. On dmontre que les indices sontn&essairement entre les bornes.

    Nous avons utilis les notions de pr-condition et post-condition. La pr-condition indique les limitations du programme, cest-a-dire les caractristiques desdonnes en entre. Elle sert pour des dmonstrations de correction, mais aussi pour ladocumentation dun programme. Avec la pr-condition, un utilisateur eventuel peutconfirmer quil a le droit dappeler le programme avec les donnes dont il dispose,

    La post-condition indique ce que le monde extrieur sait aprs lexcution duprogramme. On doit pouvoir remplacer tout programme par nimporte quel autre quirespecte les mmes pr-condition et post-condition, sans que Iutilisateur ventuelsen rende compte.

    Une partie difficile du processus de la mise en uvre est la spcification duprogramme. Mais le travail fait a ce niveau est payant. En effet, le cot dune erreuraugmente avec le temps quelle reste prsente. Mieux vaut passer un peu plus detemps en dbut du processus que de payer trs cher, plus tard, llimination deserreurs.

    Pour dmontrer la correction dun programme, on utilise des assertions et desinvuriants. Les assertions sont des formules logiques qui sont vraies aux endroits oelles figurent dans le programme. Un invariant est une assertion qui est vraie chaque tour dune boucle. Une boucle est compltement dfinie par son tat dumonde et son invariant. Certains auteurs incluent ltat du monde dans linvariant.Les deux techniques sont quivalentes.

    2.4.1. Un apart! sur les preuves de programmes

    Les techniques rsumes ci-dessus reprennent des notions manant des travauxsur la preuve de programmes. Le but est dimprgner les cerveaux des tudiants dem&nismes mentaux allant dans cette direction, sans passer a une approche troprigoureuse pour tre soutenue dans la pratique. On doit savoir pourquoi leprogramme marche, sans avoir explicit tout le dveloppement mathmatique.

    Pour le puriste, ou le mathmaticien, cette approche nest pas satisfaisante. Ilserait normal - dans leur monde idal - que tout programme soit accompagn dunepreuve formelle. Ce sont les impratifs conomiques qui font que le monde nest pasidal, surtout en acceptant les capacits et les motivations des programmeurs.

    Le style present est donc un effort de compromis, matrisable par les etudiantsdont nous disposons tout en les guidant. Au cours de leurs travaux dirigs, ilsmenent a bien au moins une preuve formelle complte afin de comprendre les outilssous-jacents.

    2.4.2. Le styLe dcriture

    Cet ouvrage sadresse aux problmes algorithmiques. Aucun des programmesprsents ne dpasse la taille dun module dans un programme complet. La miseensemble dunits de programme pour la construction dun produit industriel est unproblme aborde ailleurs (cours de gnie logiciel, projets).

    Mais il ne faut pas perdre de vue cette question de modularit. Lutilisation dela clause DONNEES, avec les pr-conditions et post-conditions, vise, parmi dautresbuts, prparer la dfinition de modules, avec leurs spcifications, interfaces etcorps. En pratique, dans le cours enseign, ces notions forment la matibre dediscussions, prparant ainsi le travail en profondeur venir.

    2.5. Adressage dispers

    Les premiers programmes dans ce chapitre sont des exemples simples,introduits pour des raisons pdagogiques. Mais, en mme temps, nous avonsexamin des mthodes de recherche dun lment dans un vecteur. Dans une premireliste dalgorithmes de ce type, il faut introduire celui de ladressage dispers (hashcode), qui est frquemment utilis dans la gestion, dans les compilateurs ou danslintelligence artificielle. La mthode a t invente pour acclrer des recherches depositions joues dans le jeu de dames [Samuels 19591.

    Supposons que nous voulons crker un annuaire tlphonique au fur et mesurede larrive de numeros connus, sans faim de tri chaque arrive. Cest ce que lon faithabituellement dans un carnet dadresses. Dans un tel carnet, pour viter davoir examiner tous les noms de personnes, on les divise en 26 classes, en fonction de lapremire lettre du nom. Dans le carnet, on commence une nouvelle page pour chaquelettre. Les recherches vont plus vite parce que les comparaisons ne sont faites quavecles noms ayant la mme premire lettre. La premire lettre sert ici de clk (key).Une clC est une fonction des caractres constituant le mot qui sert diviserlensemble de mots possibles dans des classes. Si les noms Ctaient distribus demanire gale entre les classes, on divise le nombre de comparaisons par le nombrede classes. Pour un carnet, on ne regarde quun nom sur 26. Notons que ce rendementnest pas atteint en pratique, parce que, par exemple, les pages K, X, Y, . . .contiennent moins de noms que certaines autres.

    36 37

  • .&3ORlTHMIQUE El- PROGRAMhHMON hGORlTRMIQLJE El PRoGRAhftWDON

    Ladressage dispers est une mise en uvre du principe du carnet, avec quelqueschangements en raison des caractristiques des ordinateurs. En particulier, un carnetcomporte beaucoup de lignes vides sur les pages moins remplies. Nous dcrivonsdeux versions de lalgorithme dadressage dispersk, une premihre avec un nombre de~16s plus petit que la taille de la mmoire disponible, et une deuxime o le nombrede cl& est le mme que le nombre de cases disponibles.

    Dans ce tableau, les 26 premires cases sont r&ervCes pour le premier nomreu de chaque classe (en supposant que la cl est la premikre lettre). La colonne dedroite contient lindex de lentrt5e contenant le prochain nom de mme cl. Unsuccesseur (suivant) dindex -1 indique que le nom dans cette entre est le dernierrencontr dans sa classe (il na pas de successeur). Une case vide a galement -1comme successeur. Les noms comportent 8 caractres, tant compltks par desespaces. Une case vide comporte 8 espaces. La figure montre ltat de la table aprsla lecture des noms suivants :

    2.51. Algorithme avec chanageX, DUPONT, TOTO, Y, DURAND, TINTIN, DUPOND.

    Dans cet algorithme, le nombre de cl& est plus petit que le nombre de casesdisponibles en mmoire. Considrons le carnet, o il y a 26 cls. On cre un tableaudu type dond dans la figure 2.2.

    A la rception dun nom, on calcule sa cl i, ici la premire lettre. Diffrentscas se pdsentent :

    - Le nom est la premier occurrence dun nom avec cette cl. Alors, la casedindex i est vide. Le nom sinsre a cette place et le processus est termin.

    - Un nom de cl i a dj t rencontr. On compare le nouveau nom avec celuidindex i dans la table. Si les deux sont identiques, le nom est trouv et le processusse termine.

    Index12345678910111213141516171819

    fi2223CM

    fi272829. . .

    N o m

    DUPONT

    TOT0

    XY

    DURANDTINTINDUPOND

    Suivant-1-1-127-1-1-1-1-1-111

    - 11-11

    12811-1-1-1-129-1-1

    Figure 2.2 . Table pour l adressage dispers avec chanage

    38

    - Si les deux noms sont diffrents, il faut examiner les successeurs ventuelscomportant la mme cl. Un successeur de valeur - 1 indique que la liste est termine.On ajoute le nouveau nom la premire place disponible et le processus est termin.

    - Si le successeur existe, son index est donn dans la colonne correspondante.Oncomparelenouveaunomavecle successeur,enseramenantaucaspr&&nt.

    Cela donne lalgorithme du programme 2.6, page ci-aprs, appel larrive dechaque occurrence dun nom.

    A la fin de cet algorithme, la variable adresse contient lindex du nom dans latabIe. La variable pl indique la premire case de dbordement libre dans la table (avecla valeur de 27 au dpart de lalgorithme). Lalgorithme ne traite pas le problme dundbordement ventuel du tableau.

    39

  • hGORITHMIQUE ET PROGRAMMMION

    DONNEES cl: PROC(chane) -> entier;nom: chane(8);cars: TAB [l ..taille] DE chane(8);SU~C: TAB [l ..taille] DE entier;

    DEBUT VAR i, adresse: entier;trouv: bool;pl: entier INIT 27;

    i:=cl(nom);S I carqJ= ALORS cars[i]:=nom; % complt par des espaces %

    adresse:=i; trouv:=VRAISINON trouv:=FAUX;

    TANTQUE NON trouvFAIRE SI nom = cars[ij

    ALORS adresse:=i; trouv:=VRAISINON SI SUC~[~ = -1

    ALORS cars[pl]:=nom; % avec des espaces %succ[i]:=pl; succ[pl]:= - 1; adresse:=pl;trouvb:=VRAI; pl:=pl+l

    SINON i:=succ[i]FINSI

    FINSIF A I T

    FINSIFIN

    Programme 2.6. Adressage dispers

    2.5.2. Autant de cls que de cases

    Ltablissement dun chanage entre les diffrents noms dune mme cl gaspillede la mmoire. Pour viter cette dpense, on peut choisir une fonction qui donneautant de cls que de cases dans le tableau. En restant avec notre cl (peu raliste) dela premibre lettre, on peut refaire la table de la figure 2.2 pour obtenir celle de lafigure 2.3.

    Index123456789101 112131415161 718192 02 12 22 32 42 52 6

    N o m

    DUPONTDURANDDUPOND

    TOT0TINTIN

    XY

    Figure 2.3. Table sans zone de dbordement

    Cette figure reprend la situation de la figure 2.2. On note que les nomssupplmentaires commenant par D ont pris les places des noms commenant par Eet F. Que se passe-t-il alors si lon rencontre le nom ESSAI ? On comparera ESSAIavec DURAND (case 5), puis avec DUPOND (case 6), avant de dcouvrir que la case7 est vide. ESSAI rentrera dans la case 7. La cl sert tablir un point de dpart desrecherches, donnant ainsi lalgorithme du programme 2.7.

    4 0 4 1

  • fiLGORITHhtIQUJ2 I?I PROGRAMMUYON A L G O R I T H M I Q U E ET PROGRAhSIbGWON

    garde ses qualits jusquau remplissage du tableau, au prix dune occupation demmoire suprieure.

    Rappelons que les deux algorithmes ncessitent une fonction qui distribuentbien les noms parmi les cls. Si cette distribution est mauvaise, les deuxalgorithmes se rapprochent de lalgorithme de recherche linaire.

    Notons finalement que les algorithmes dadressage dispers ne diminuent pas lacomplexit thorique des recherches par rapport celle des recherches linaires.Lamlioration de cette mthode rside dans la diminution de la constante dans leformule. Toute la famille est dordre o(n) pour la recherche dun nom.

    DONNEES cl: PROC(chane) -> entier;nom: chane(8);tab: TAB [ 1 ..taille] DE chane(8);

    DEBUT VAR i, adresse: entier;trouv: bool;

    i:=cl(nom); trouv:=FAUX;TANTQUE NON trouvFAIRE SI tab[fl = % Case vide %

    ALORS trouv:=VRAI; tab[i]:=nomSINON SI tab[i]=nom

    ALORS trouv:=VRAISINON SI i=taille % Dernire case du tableau %

    ALORS i:=l % Recommencer en haut %SINON i:=i+lFINSI;SI i=cl(nom) ALORS table pleine FINSI

    FINSIFINSI

    FAITFIN

    Programme 2.7. Adressage dispers, version 2

    La table doit tre circulaire (on recommence regarder en haut si lon arrive B lafin). Si la table est pleine, la recherche dun nouveau nom fait tout le tour dutableau. Sauf si la table est pleine et le nom est absent, la fin du programme, icontient lindex du nom dans le tableau.

    2.5.3. Choix de cl et efficacit

    Jusqualors, nous avons utilis comme cl la premire lettre du nom. Cette clnest pas la meilleure dans la plupart des cas. Le choix de la bonne cl dpend descaractristiques des noms que lon va rencontrer. Dans les compilateurs, on utilisesouvent comme cl la somme des reprsentations internes des caractres (code ASCIIou EBCDIC) modulo la taille de la table. La taille choisie est habituellement unepuissance de deux afin de calculer le modulus par dcalage sur les bits. Ce choix estassez bon pour les identificateurs dans des programmes. Il permet dutiliser ledeuxi&me algorithme, sans chanage.

    Le deuxime algorithme est assez efficace tant que la table ne se remplit pas.Son rendement devient mauvais si la table est presque pleine. Le premier algorithme

    2.6. Exercices

    1. Avant de passer au chapitre qui donne la solution, chercher lamlioration duprogramme de recherche dun mode de vecteur. Ce nouveau programme est plus courtet plus efficace que lancien. En particulier, il comporte une variable de moins et untest (SI ALORS . . . ) de moins.

    2. Considrons une nouvelle version du programme de dichotomie, crit dans le stylesans boolens :

    DEBUT VAR bas, haut, centre: entier;bas:=1 ; haut:=n; centre:=entier((n+l)/2);TANTQUE haut>bas ET t[centre]+objetFAIRE SI t[centre]cobjet

    ALORS bas:=centreSINON haut:=centreFINSI;centre:=entier((haut+bas)/2)

    FAIT;SI t[centre]=objetALORS . . . % cest trouv %SINON . . . % absent %FINSI

    FIN

    Cette version, qui est souvent propose par des lbves, contient un pige.Lequel ? Comme mise sur la voie, on considrera le problkme de la terminaison de laboucle.

    42 43

  • &GORlTHMIQUEJTPROGR4MMPUION

    3. Mise en uvre dans lordinateur des algorithmes dadressage disperse. On prendrades textes de programmes afin de disposer de suites de noms (identificateurs). Enprenant des programmes de grande taille, on peut mesurer lefficacit des diffrentsalgorithmes de recherche dobjets (linaire, dichotomie, adressage dispers) endressant des graphiques du temps dexcution contre le nombre de noms lus. Onexaminera aussi linfluence du choix de la fonction de calcul des cls sur lesalgorithmes dadressage dispers. Chapitre 3

    Les tris

    Ce nest pas la premire fois quun livre sur lalgorithmique et laprogrammation aborde le sujet des tris (sorting), loin de l. Mais le sujet estessentiel - on ne peut pas sappeler informaticien sans avoir quelques connaissancesdes algorithmes de base. En plus, la matire est un excellent terrain dentranement.Cest donc sans honte que nous abordons ce chapitre, mme si dillustrespr&lecesseurs ont trac la route. Parmi ceux-ci, accordons une mention particuliere [Knuth 19731, pour un volume tout entier consacr aux recherches et aux tris.

    Trier un vecteur, cest lordonner. On peut trier des entiers, des rels, deschanes de caractres, . . . Il suffit quil existe une relation dordre entre chaque pairedlements, cest--dire que, si a et b sont des lments, une et une seule des relationssuivantes est vraie :

    ad3 a = b aA

    Les axiomes habituels sont vrifiCs :

    acb bsa(a

  • itLGORITHMIQUE ET PROGRAhhWIlON fkGORITlIMIQUEETPROGR4hfMATION

    3.1. Recherche du plus petit lment

    Un premier algorithme, que nous ne recommandons pas pour des applicationspratiques, consiste en la recherche du plus petit lment restant. Ainsi, au premiertour, on recherche t[min], le plus petit lment en t[l..n]. 11 devient t[l] dans levecteur tri. Le plus simple est dchanger t[ l] avec t[min], ce dernier arrivant ainsi sa place dfinitive. Le probl8me en n est rduit un problme en n-l, car il reste trier le vecteur t[2..n]. Au deuxibme tour on recherche le plus petit lment en t[2..n]pour lchanger avec t[2], et ainsi de suite. On aurait pu prendre llment le plusgrand, en lchangeant avec t[n] . . .

    Le programme 3.1 montre un schma dalgorithme appliqu a un vecteurdentiers :

    DONNEES n: entier;t: TABLEAU [l ..n] DE entier;

    PRECOND n>O;DEBUT MONDE i: entier, t[l ..i] est tri;

    i:=O;TANTQUE i < n-lFAIRE i:=i+l ;

    trouver j tel que t[j] est le plus petit lment dans t[i..n]changer(t[i], t[i])

    FAITFINPOSTCOND t[l ..n] est tri, cd i,j (O

  • &OORITHMIQUE FI PROGRAMh4ATION

    Lchange a t programm de maniere vidente, avec une variable temporaire.La complexit de cet algorithme est simple calculer. Au premier tour, n-lcomparaisons sont ncessaires pour trouver le plus petit lment en t(l..n). Audeuxieme tour il en faut n-2, puis n-3, . . . Le nombre de comparaisons est donc :

    1 + 2 + 3 + . . . + (n-l) = n*(n-1)/2

    Comme les autres oprations (il y a n-l changes) se font moins souvent,lalgorithme est dordre o(n2). Le nombre de comparaisons est indpendant ducontenu du vecteur.

    3.2. IX par insertion

    Dans le programme du paragraphe prcdent, aprs i tours, le vecteur t[l..i] esttri, mais en plus, ses i premiers lments sont dj leur place, cest--dire :

    O

  • hOORlTHMIQlJE ET PROGRAMMtUlON

    La preuve de ce programme est faite en dmontrant que le nouvel tlmentretrouve bien sa place, ce qui revient a demontrer qu la fm de la boucle interne ona :

    O t[k]stempj tempO;DEBUT VAR i, j, temp: entier;

    MONDE i: t[l ..i] est tri;i:=l ;TANTQUE il ETPUIS tjj-l]>tempFAIRE tjj]:=tjj-11; j:=j-1FAIT;tjj]:=temp

    FAITFINPOSTCOND t[ 1 ..n] est tri

    Programme 3.5. Version avec ETPUIS

    On peut aussi faire la mme chose avec une bute (voir exercice la fin duchapitre). La complexit de cet algorithme dpend du nombre dlments quidescendent B chaque tour. Avec une distribution alatoire, la place de llmentconsidere va tre en moyenne au milieu des autres. Ainsi, le nombre dlments dplacer est :

    On est toujours en ordre O(n*), mais cet algorithme est moins mauvais que leprtktdent (sans pour autant tre recommande dans le cas gn&al). En effet, si le .tableau est deja tri ou presque, le premier algorithme fait le mme nombre decomparaisons que dans le cas dune distribution alatoire, tandis que dans le second,on constate n fois de suite quaucun mouvement nest ncessaire, descendant ainsi lordre o(n). Cet algorithme est donc bon pour des vecteurs que lon sait dj tries, oupresque.

    3.3. hi par bulles

    Bien connu aussi, ce tri a une mauvaise rputation du point de vue delefficacid, reputation qui nest pas tout a fait justifie. A chaque parcours du vecteur,on compare successivement chaque paire de voisins. Si leur ordre nest pas le bon,on les echange. Une des raisons de la mauvaise rputation de lalgorithme est quecertains enseignants montrent la version du programme 3.6, qui est effectivementpartkuli&rement inefficace.

    DONNEES n: entier;t: TABLEAU [l ..n] DE entier;

    PRECOND n>O;DEBUT VAR fin, i: entier;

    MONDE fin: t[l ..fin] reste trier,fin:=n;TANTQUE fin>1FAIRE MONDE i: on va comparer t[i] et t[i+l];

    i:=l ;TANTQUE icfinFAIRE ASSERTION O

  • &GORITHMIQIJE ET PRoGRAMhUTION

    Cette version de lalgorithme est dmontrable partir des assertions donnesdans le texte. A la fin de chaque tour, 18ment le plus lourd est passe la fin de lazone considree. Cest une version moins efficace de lalgorithme du $3.1, entrouvant le plus grand lment au lieu du plus petit.

    iiLL3ORlTHMIQUE ET PROGRAMMATION

    Il y a deux faons damCliorer cette version :

    - Considrons le vecteur suivant :

    (23456789101)

    A chaque passage dans le vecteur, le seul change se fera entre la valeur 1 et sonpredcesseur immdiat. Nous proposons de faire des passages alternativement degauche droite, puis de droite gauche. Dans ce cas, le deuxieme passage ramneraitle 1 au dbut du vecteur, qui serait donc trie aprs deux passages.

    - Mais cela ne suffit pas, car lalgorithme ne se rend pas compte que le vecteurest trie. Considrons le vecteur suivant :

    (21345678910)

    On voit quil sera trie la fin du premier passage. Ce quil faut ajouter au programmeest la ralisation du fait que, tant donn quaucun change na eu lieu, pendant cepremier passage, a partir de la valeur 3, t[2..10] est tri et les ellments sont dj aleurs places dfinitives. La preuve de cette affirmation vient du fait que le testdmontre que ces lements sont ordonns deux deux. Lordonnancement tanttransitif (aSb ET bic => tic), ils sont donc tous ordonns. En plus, lassertionmontre que le dernier objet prendre sa place (ici t[2]) est le plus grand de tous ceuxvu jusqualors. Il en rsulte que lon peut rkduire lespace trier plus rapidement.

    Ces amliorations, qui prennent en compte le travail accompli en route,cest--dire les changes intermdiaires, donnent lieu lalgorithme du programme3.7,

    DONNEES n: entier,t: TABLEAU [l ..n] DE entier;

    PRECOND n>O;DEBUT VAR bas, haut, i: entier;

    MONDE bas, haut: t[bas..haut] reste trier;INVARIANT t[l ..bas], t[haut..n] sont ordonns,

    t[l ..bas-11, t[haut+l ..n] sont placs;bas:=1 ; haut:=n;TANTQUE baschautFAIRE MONDE i: t[i..haut] comparer deux deux,

    der: dernier objet boug;INVARIANT t[der..i] est ordonn;i:=bas; der:=i;TANTQUE khautFAIRE SI t[i+l]

  • fiLWRI-lHUIQUEETPROORAMMATION

    yi..jj est ordonn (i&&j => t[k]4[1])yi..jJ est plac6 (t[i..j] est ordonn ET

    (O-ck.4, i&j => t[k]5t[l]) ET(i%j, jemsn => t[l]n[m]))

    Les invariants permettent la dmonstration directe de la justesse duprogramme.

    On peut comparer la complexit de cet algorithme avec celle de lalgorithmepar insertion. Les deux mnent un mme nombre dchanges, que lon calcule de lamani& suivante : en prenant les l6ments deux deux, le nombre dkchanges est lenombre de fois o une paire dlments nest pas ordonne. Mais le nombre decomparaisons nest pas le mme pour les deux algorithmes. Malheureusement, nilun, ni lautre nest le meilleur dans tous les cas. Les deux algorithmes sont dumme ordre de complexiti, et ils partagent les proprits dtre bons dans le cas dunvecteur bien conditionn et dtre mauvais pour un vecteur mal conditionn.

    3.4. Diviser pour rgner

    Les trois algorithmes de tri tudis jusquici sont tous dune complexit dordreo(n2). Dans chaque cas, un passage du vecteur rduit un probEme en n unprobkme en (n-l). Comme pour la dichotomie par rapport la recherche linaire, ilest possible de faire mieux en tiuisant un probEme en n deux problkmes en nf2.Le terme gnt%alement employ dans ces cas est celui de diviser pour rgner. Ondivise le vecteur en deux moitis, on trie chaque moiti4 et on remet les deux moitisensemble.

    Il existe deux groupes dalgorithmes dans cette catgorie : les tris par partitionet les tris par fusion. Le tri par partition permet de travailler sur place, cest--direen gardant les t%ments dans le vecteur en vitant de copier le vecteur entier dans unnouvel emplacement dans la mmoire. Le hi par fusion, utilis du temps hroquedes programmes de gestion sur support de bandes magnCtiques, ncessite la cr6ationdun deuxime vecteur dans la mmoire (ventuellement secondaire), vecteur quireoit les 616ments dans le nouvel ordre.

    Pour des raisons videntes, nous accordons plus dimportance, dans cetouvrage, au tri par partition. Le tri par fusion est souvent pris comme exemple danshz cours de programmation avec le langage PROLOG.

    3.41. Diviser pour rgner avec partition

    Dans le cas dune distribution alatoire de valeurs, surtout si n est grand,lalgorithme de diviser pour rgner avec partition est le meilleur de ceux prsent&

    54

    dans cet ouvrage. Le principe est de partitionner les lments en deux classes en lescomparant avec un lment dit pivot. Tous les Blments plus petits que le pivot vontse trouver sa gauche, les autres se trouvant sa droite. Considrons le programme3.8, qui met en uvre cette classification par rapport au pivot t[ 11.

    DONNEES n: entier,t: TABLEAU [l ..n] DE entier;

    PRECOND n>O;DEBUT VAR pivot, camp, bas, haut: entier;

    MONDE pivot: base de la comparaison,camp: valeur comparer au pivot,bas: index du trou gauche,haut: index du trou droit;

    pivot:=t[l]; comp:=t[n]; bas:=l; haut:=n;TANTQUE baschautFAIRE SI comp t[i]ct[bas]

  • hOORITHMIQUE ET PROGRA~ION

    Pour mener bien cette opration r&rsive, nous avons besoin de paramtrerle programme ci-dessus, qui va devenir une procdure dans le programme 3.9.

    hGORITHhfIQUE ET PROGRAMMATION

    PROC M(i, j);GLOBAL n: entier, t: TABLEAU [l ..n] DE entier;SPEC i, j: entier;

    trier t[i..j] par la mthode de diviser pour rgner;PRECOND 04,jln;DEBUT VAR pivot, camp, bas, haut: entier;

    SI j>iALORS pivot:=t[i]; comp:=tjj]; bas:+ haut:=j;

    TANTQUE bas-zhautFAIRE SI compepivot

    ALORS t[bas]:=comp; bas:=bas+l; comp:=t[bas]SINON t[haut]:=comp; haut:=haut-1 ; comp:=t[haut]FINSI

    FAIT;t[bas]:=pivot; M(i, bas-l); tri(bas+l, j)

    FINSIFINPROC

    Programme 3.9. Insertion dans une procdure rcursive

    Le terme GLOBAL indique que la variable n est dclare lextrieur de laprocdure (dans le programme englobant). Ainsi, la valeur de n est la mme pourchaque appel de la procdure, tandis quil existe un nouvel exemplaire de i et de jpour chaque appel (chacun possde le sien). Le tableau t existe galement en un seulexemplaire, manipule par chacun des appels de la procdure.

    Cette procdure mne a bien le tri complet. Elle comporte le programme critprecdemment, avec les changements ncessaires pour trier t[i..j] au lieu de t[l..n].Une fois que la division en deux zones a eu lieu, il reste les trier, lune apreslautre, par deux nouveaux appels de tri avec des pammtres appropris :

    M(i, bas-l) ET tti(bas+l , j)

    La procdure teste par i

  • &OORIIHMIQUE ET PROGRAMMXION fiLGO-QUEmPROGRAMMPIIION

    On reviendra sur les piles au cours du chapitre 4, en les utilisant souvent par lasuite.

    t[l ..p-1] est triert[p] est placet[p+l ..n] est trier.

    Les bornes 1 et p-l sont mises sur la pile et le prochain tour redmarre avec :

    i-p+1 ET j = n

    Aprs chaque partition, une paire de bornes est mise sur la pile, lautre tanttraite de suite. Aprs un certain nombre de partitions, la taille de la zone traiter est1 (ou 0), cest--dire quelle est termine. Dans ce cas, on recommence avec lapremikre paire de bornes sur la pile, et ainsi de suite. Cette technique donne lieu auprogramme 3.10.

    DONNEES n: entier,t: TABLEAU [ 1 ..n] DE entier,

    PRECOND OiFAIRE pivot:=t[i]; comp:=t[]; bas:=i; haut:=j;

    TANTQUE basehaut \

    FAIRE SI compcpivotALORS t[bas]:=comp; bas:=bas+l ; comp:=t[bas]SINON t[haut]:=comp; haut:=haut-1; comp:=t[haut]FINSI

    FAIT;t[bas]:=pivot; pile[pl]:=i; pile[pl+l]:=bas-1 ; PI:=PI+~; i:=bas+l

    FAIT;fini:= Pl=i;SI NON finiALORS PI:=PI-2; i:=pile[pl]; j:=pile[pl+l]FINSI

    FAITFIN

    3.4.3. Quelques commentaires sur la rcursivit

    Dans le programme de recherche linaire, ou dans les tris primitifs, la base desalgorithmes a t la rduction dun problbme en n vers un problme en (n- 1). Cettetiduction est triviale a mettre en uvre; chaque tour dune boucle, on excutelaffectation :

    n:=n-1

    et le tour est jou.

    En passant la recherche dichotomique, il sagit de rduire un problme en nvers un probl8me en n/2. On cherche un objet dans le domaine dindices [g..d]. Parrapport un ClCment mdiane dindex c on rduit le domaine soit [g..c], soit [c..d]. La mise en uvre est galement triviale, sagissant de lune des deuxaffectations suivantes :

    d:=c OU g:=c

    Notons nanmoins que ces utilisations de laffectation nexistent que pour desraisons de mise en uvre dans un ordinateur. Le raisonnement sous-jacent est de typerkurrent. Par exemple, pour la recherche linaire, on aurait pu crire la fonctionsuivante :

    chercher(objet, t[l ..n]):SI t[n] = objetALORS trouveSINON chercher(objet, t[l ..n-11)FINSI

    Cette criture fonctionnelle peut sexprimer par lutilisation dune procdurerkcursive ou par une boucle avec affectation. Toute boucle peut se rcrire en formede procdure rikursive de manikre directe.

    Considrons maintenant le tri par diviser pour rkgner avec partition. Ici, onr6duit un problbme en n vers deux problmes en n/2. Une forme rduite de lafonction de tri est la suivante :

    Programme 3.10. Version avec pile

    5 8 5 9

  • kCiORITHMIQUE ET PROGRAMMMION hOORKHMIQUE JiT PROGRAMMMION

    contient, a chaque instant, les paires dindices correspondant aux appels laisss ensuspens. Notons que le programme du paragraphe pr6cdent trie la partie droite duvecteur, en mettant les indices de la partie gauche en suspens sur la pile. Dans lafigure 3.1, lordre est invers. En fait, lordre est indiffrent; a la rigueur, on pourraitlancer les deux appels 16cursifs en parallle sur deux processeurs ind6pendants dans lecadre dun matt5riel multiprocesseur.

    tri(t[g..d]):SI d>gALORS partition(t[g..d], c); tri(t[g..c-11); tri(t[c+l ..d])FINSI

    Une simple affectation ? chaque tour dune boucle ne suffit plus, car, silaffectation relance le premier des appels de tri rsultant, les param&es du deuxibmeappel doivent tre stocks quelque part afin de revenir dessus la fin du premierappel. Notons que chaque appel provoque, , son tour, deux nouveaux appels, jusqularriv& de vecteurs de longueur 1 (ou 0).

    On peut envisager la cascade dappels dans la forme dun arbre (figure 3.1).

    tri(g..d)

    tr i(g..cl) tri(cl..d)

    Atri(g..c2) tri(c2..cl)

    Atri(g..c3) tri(c3..c2)

    Figure 3.1. Appels aprspartition

    Cette figure montre les appels en cours aprs trois partitions, les indices ayantt6 simplifis pour allger le dessin (suppression des +l et -1). Apr&s chaquepartition, on reprend la branche gauche, en laissant la branche droite en suspens. Lesuccesseur gauche est de nouveau partitionn, et ainsi de suite.

    La modlisation par procdure n5cursive est donc une mise en uvre directe etsimple de lalgorithme. Par la suite, nous avons montr une mise en uvre avec unepile. La pile a servi se rappeler ce qui reste faire un moment donn. Elle

    Lutilisation dune pile est un moyen gnral pour mettre en uvre larcursivit. Si la pile est programme explicitement, comme dans le paragrapheprcdent, on y stocke les informations permettant de savoir o lon en est dans lacascade dappels. On verra dautres exemples dans le chapitre sur la marche arrire.

    En fait, lors de lutilisation dune procdure rcursive, un compilateur engendredes instructions qui g&rent une pile. Y sont gardes les valeurs des paramtres delappel en cours et des variables locales chaque niveau dappel. Ce sujet est couvertavec plus de d&ails dans des cours de compilation tels que [Cunin 19801.

    On peut se demander quels sont les schmas rcurrents qui permettent unetraduction facile vers une boucle avec affectation directe de variables. Un problmequi se rduit de manire rcurrente en deux sous-problmes, ou plus, ne permet pasune telle traduction, car il faut toujours garder la trace des appels en suspens. Dansun schma un seul appel, la traduction vers une boucle est directe dans le cas dunercursivit terminale. Dans ce cas, aucun calcul ne reste excuter aprs la fin delexcution de lappel rcursive, comme dans le cas de la recherche linaire. Leproblbme sera reconsidr dans le chapitre 7, qui traite de la transformation deprogrammes.

    3.4.4. Deux pivots

    Comme la division dun problbme en deux sous-problmes - chacun de lamoiti du cot du premier - reprt%ente un grand gain defficacit, on peut sedemander si lide de diviser un probl&me en trois reprsente encore une amlioration.Cest purement au titre dune spculation intellectuelle que la question se pose pourle tri par diviser pour rgner avec partition. Lauteur ne connat pas de publication nidapplication de I?d&.

    La mise en uvre dun tel algorithme (programme 3.11) ncessite donc deuxpivots, avec un lment de comparqson. Avec les deux pivots, on partage les&ments en trois ensembles : ceux qui sont plus petits que le plus petit des pivots,ceux qui sont plus grands que le plus grand des pivots et ceux qui sont entre lesdeux. On trie par la suite les trois ensembles par trois appels r6cursifs.

    6 0 6 1

  • Auio-QUE IT PROGRAMMtWION hOORITHMlQUE I?I PROGRAmION

    DEBUT DONNEES n: entier;t: TAB [1 ..n] DE entier;

    PROC tri(min, max: entier):VAR tg, td, pl, p2, tl, t2, t3: entier; \SI max>minALORS pl :=t[min]; t2:=min+l; p2:=t[t2]; tl :=min;

    test:=t[max]; t3:=max;TANTQUE t243FAIRE SI tesbt2

    ALORS t[t3]:=test; t3:=t3-1; test:=t[t3]SINON SI test.4

    ALORS t[tl]:=test; tl :=tl+l; t[t2]:=t[tl]SINON t[t2]:=test

    \ FINSI;t2:=t2+1; test:=t[t2]

    FINSIFAIT;t[t l]:=pl ; t[t2]:=p2;tri(min, tg-1); tri(tg+l, td-1); tri(td+l, max)

    FINSIFINPROC;tri(1, n)

    FIN

    Programme 3.ll. Diviser pour rgner avec deux pivots

    La seule difficult dans ce programme rside dans le maniement des trous et lesensembles pendant la partition. Il y a trois trous : deux pivots et un lement decomparaison. Les trois trous dfinissent quatre zones dans le vecteur : troisensembles B trier et une quatribme zone qui contient les lments en attente departition. La figure 3.2 montre la distribution de trous et de zones pendantlopration de partition.

    Pl et[i]

  • .kGORlTHh4lQUFiETPROGRAMMtUlON

    de longueur au plus 1.- On fusionne des zones de longueur 1, par paires, pour crer des zones de

    longueur 2 dans une nouvelle copie t2 du vecteur.- Les zones de longueur 2 sont fusiondes pour crer des zones de longueur 4,

    de nouveau en tl.- On continue de la sorte jusquh la fin du processus.

    Prenons comme exemple un vecteur de 8 lments, tri ?I lenvers. Les tatssuccessifs de fusion sont les suivants :

    t1:t2:t1:t2:

    (87654321) Vecteur de dpart l(78563412) Fusion dlments crant des paires(56781234) Fusion par paires(12343678) Fusion par groupes de quatre

    Le programme 3.12 montre une mise en uvre correspondante.

    fiLGORlWMIQUE ET PROGRAMMAITON

    DONNEES n: entier, t: TAB [l ..n] DE entier;DEBUTVAR 1, pl, p2, p3, il, i2, i: entier;

    MONDE on fusionne des paires de zones de longueur I en zones delongueur 21;

    pl est lindex du premier Mment da la premire zone, p2 lindexdu debut de la seconde zone, p3 ds la zone suivante (n+l silny en a pas);

    i &ments ont 15th recopi& vers le nouvel exemplaire duvecteur, il est lindex du premier lment non recopi8 da lapremire zone, i2 de la deuxime;

    I:=l;WNTQUE la-~FAIRE i:=O; pl :=l;

    ANTQUE i

  • AI.,OOmQUE ET PROC3RAMMKTION

    3.5. Rsum de la complexit des algorithmes

    En fonction des discussions prcdentes, on peut dgager des raisons menant un choix sens dalgorithme de tri pour une situation donne. On aboutit auxconclusions suivantes :

    - La mthode de recherche du plus petit lment nest jamais bonne. On neIutilisera pas.

    - Pour de grands vecteurs dont les lments sont distribus alatoirement, lamthode de diviser pour rgner avec partition est la meilleure. Elle est mauvaise dansle cas dun vecteur dej tri, ou presque tri. Pour limiter les dgts dans ce cas, ilvaut mieux prendre le pivot au milieu de la zone, ce qui complique lgerement leprogramme (voir exercice).

    - Pour des vecteurs presque tris, les deux methodes dinsertion ou par bullessont de bonnes candidates, condition dutiliser la version optimise pour ladeuxitme. Lune ou lautre peut tre la meilleure, en fonction des proprietsparticuli&es de lordonnancement approximatif dj existant.

    3.6. Exercices

    1. Dans le tri par insertion, lutilisation de ETPUIS permet de supprimer la variablearrt. Dans un langage sans ETPUIS, comment arriver au mme rsultat parlintroduction dune bute ?

    2. Donner une rgle permettant de calculer le nombre de comparaisons ncessairesdanslecas:

    - dun tri par insertion,- dun tri par bulles.

    3. Dans la dernire version du tri par diviser pour rgner, on fera la modificationconsistant a prendre comme pivot lelment au milieu de la zone trier.

    4. Un bon exercice au niveau dune classe est de comparer les diffrents tris, mis enmachine par diffrents lves. On mesurera, par lhorloge et en comptant lesoprations, le cot de lexcution de chaque tri, en essayant une srie de vecteursdiffrents. On variera la distribution dlments (tris, presque tris, alatoire, tris Ienvers , . ..) et la longueur du vecteur. Ltablissement de courbes pour chaquemthode permet den confirmer la complexit thorique.

    Chapitre 4

    Des structures de donnes

    Les langages de programmation classiques permettent lutilisation de variablessimples (entiers, rels, . . .) et de tableaux, voire, ventuellement dautres types dedonnes composes (records, . ..). D ans le dernier exemple du chapitre 3 (tri pardiviser pour rgner), nous avons eu besoin dune structure de donnes particulire, lapile, qui nexiste pas directement dans ces langages. En effet, dans la plupart deslangages de programmation, on ne dispose pas dun type pile.

    Un certain nombre de structures de donnes de ce type reviennent constamment wdans les programmes. Dans ce chapitre, nous allons dcrire les principales structures,avec les moyens de les reprsenter dans des langages existants. Avec ledveloppement de nouveaux langages, on peut sattendre voir ces objets devenir destypes standards. En premier lieu, nous allons considrer les piles, les jles (queueou FIFO - First In, First Out), les arbres (tree), les treillis (lattice) et lesgraphes (graph).

    4.1. Les piles

    Une pile est un ensemble ordonn dobjets de mme type (entiers, rels, . ..).Cest comme si lon gardait une pile de livres sur son bureau. On peut poser unnouveau livre sur la pile, ou reprendre le livre qui est en haut de la pile. Extraire unlivre du milieu est tellement difficile que nous renonons a cet exercice.

    On dispose dun vecteur dont les lments sont du type appropri. Il existe deuxoprations fondamentales : poser un objet (empiler, ou push) et en retirer un

    l (dpiler, ou pull). Le vecteur sert a stocker les objets poss. Pour savoir combien

    ldobjets sont dans la pile a un moment donn, on utilise un pointeur de niveau. Lepointeur sert aussi retrouver, dans le vecteur, le dernier objet dpos.

    66

  • ALGORITHMIQUE ET PROGRAhShfMION fiLOORIlTIMIQUE ET PROGRAMMHION

    Le programme 4.1 utilise lindex de la premire case libre (pl) dans une piledentiers.

    PROGRAMME DISCUTABLEDONNEES taille: entier; file: TABLEAU [l ..taille] DE entier;VAR ancien: entier INIT 1; libre: entier INIT 1;PROCEDURE mettre(x: entier);PRECOND librestaille;

    file[libre]:=x; libre:=libre+lFINPROC;PROCEDURE enlever(x: entier);PRECOND anciewlibre;

    x:=file[ancien]; ancien:=ancien+lF INPROC

    DONNEES taille: entier,pile: TABLEAU [l ..taille] DE entier;

    VAR pl: entier INIT 1;PROCEDURE empiler(x: entier);PRECOND pIstaille;

    pile[pl]:=x; pl:=pl+lFINPROC;PROCEDURE dp\iler(x:entier);PRECONQ pl>l ;

    pl:=pl-1 ; x:=pile[pl]F INPROC

    Programme 4.1. Mise en uvre dune pile

    On voit que le nombre dobjets dans la pile un moment donn est ~1-1. Lesprocdures supposent que la pile ne dborde pas (PRECOND plltaille) et que lappelde dpiler na pas lieu avec une pile vide (PRECOND pl>l). En pratique, on testeces conditions par des SI ALORS spcifiques en dbut de procdure.

    Dans le chapitre prcdent, nous avons programm directement la pile sansutiliser les procdures empiler et dpiler. La taille de la pile tait suppose suffisante.Une pile vide tait le signe de terminaison de lalgorithme.

    La pile donne ici est une pile dentiers. Le mme schma de programme peutservir pour la construction dune pile de rels, de boolens, . . . (il suffit