Vous êtes sur la page 1sur 80

collection Informat

Table des matires

1 . Introduction.. .............................................................................. 13
1 .l. Quelques mots sur lenvironnement ............................................... 16
1.2. Notes bibliographiques sommaires.. .............................................. 17
1.3. Remerciements.. ........................................................................ 17
1.4. Le choix de programmes ............................................................. 18

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


2.1. Le mode dun vecteur .................................................................. 21
2.1.1. Construction de la premire version du programme .................. 21
2.1.2. Remarques mthodologiques ............................................... 23
2.2. Recherche dun objet.. ................................................................ 24
2.2.1. Recherche linaire.. ........................................................... 25
2.2.2. Un pige.. ....................................................................... 28
2.2.3. La dichotomie.. ................................................................ 29
2.3. De la complexit des algorithmes.. ................................................ 34
2.4. Rsum des principes introduits.. .................................................. 35
2.4.1. Un apparte sur les preuves de programmes.. ........................... 36
2.4.2. Le style dcriture ............................................................. 37
2.5. Adressage dispers...................................................................... 37
2.5.1. Algorithme avec chanage.. ................................................. 38
@ Hermbs, Paris, 1992
2.5.2. Autant de cl& que de cases.. ................................................ 40
ditions Herms 42
2.5.3. Choix de cl et efficacit ....................................................
34, rue Eugne Plachat 43
2.6. Exercices ..................................................................................
75017 Paris
3. Les tris ....................................................................................... 45
ISBN 2-86601-323-g 46
3.1. Recherche du plus petit lment.. ..................................................
ALGO~Q~IE m PROGRAmION

3.2. Tri par insertion ........................................................................ 48 6.1.2. Marche arriere, arbres et graphes .......................................... 115
3.3. Tri par bulles.. .......................................................................... 51 6.2. Les huits reines ......................................................................... 116
3.4. Diviser pour &gner .................................................................... 54 6.2.1. Une version amliore ....................................................... 118
3.4.1. Diviser pour rkgner avec partition ........................................ 54 6.2.2. Une deuxieme approche ...................................................... 119
3.4.2. Solution sans appel r&rsif.. .............................................. 57 6.3. Exercices .................................................................................. 122
3.4.3. Quelques commentaires sur la nkursivit ............................... 59
3.4.4. Deux pivots.. ................................................................... 61 7. lkansformation de programmes.. ................................................ 125
3.4.5. Tri par fusion.. ................................................................. 63 7.1. Revenons sur le mode vecteur ...................................................... 126
3.5. F&um de la complexite des algorithmes ....................................... 66 7.2. La multiplication des gitans ......................................................... 128
3.6. Exercices.. ................................................................................ 66 7.3. Exercices .................................................................................. 131

Des structures de donnes.. ........................................................ 67 8 . Quelques structures de donnes particulires.. .......................... 133
4.1. Les piles.. ................................................................................ 67 8.1. Les arbres ordonns.. .................................................................. 133
4.2. Les files ................................................................................... 68 8.2. Les arbres quilibrs ................................................................... 135
4.3. Les arbres.. ............................................................................... 70 8.2.1. Algorithmes de manipulation darbres quilibrs.. .................... 137
4.3.1. Arbres binaires et arbres n-aires ........................................... 71 8.3. Les B-arbres.. ............................................................................ 138
4.3.2. Reprsentation des arbres .................................................... 72 8.4. Exercices .................................................................................. 143
4.3.3. Parcours darbres ............................................................... 73
4.3.4. Parcours prfix et post-fix................................................ 74 Bibliographie e t rfrences.. ........................................................... 145
4.4. Les treillis.. .............................................................................. 78
4.5. Les graphes .............................................................................. 79 Glossaire ......................................................................................... 148
4.5.1. Algorithme de Schorr-Waite ................................................ 80
4.5.2. Amlioration de lalgorithme de Schorr-Waite.. ....................... 84 Solutions de certains exercices.. .................................................... 151
4.5.3. Reprsentation dun graphe sur une matrice boolenne.. ............ 87
4.5.4. Fermeture transitive .......................................................... 88
4.6. Ordres partiels et totaux .............................................................. 89
4.7. Exercices.. ................................................................................ 90

5. Rcurrence et rcursivit ........................................................... 93


5.1. Lexemple type . Les tours dHanoi ............................................... 93
5.1.1. Cot de lalgorithme .......................................................... 96
5.1.2. Une analyse plus pousse.. ................................................. 97
5.2. Des permutations....................................................................... 99
5.2.1. Permutations par changes de voisins ................................... 100
5.2.2. Le programme .................................................................. 101
5.2.3. Relation avec les tours dHanoi ............................................ 105
5.2.4. Une variante .................................................................... 105 I
5.2.5. Une version rcursive ........................................................ 108
5.3. Exercices .................................................................................. 109

6. La marche arrire ........................................................................ 111


6.1. La souris et le fromage ............................................................... 111
6.1.1. Version t+cursive .............................................................. 114

6 7
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)
ALGORITHMIQUE 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) Les programmes
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)

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)

10
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) Chapitre 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) Introduction
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) Depuis de nombreuses annes, dans diffrents pays, les informaticiens ayant
6.6. Avec un compteur octal ($6.2.2) quelques prtentions acadmiques ont lutt pour tablir leur discipline de manire
6.7. Avec des permutations ($6.2.2) indpendante. Sans vouloir dire que la lutte est termine (certains nayant pas encore
6.8. Avec permutations et marche arrire ($6.2.2) accept que la terre nest pas plate), on peut constater que, dans les universits
7.1. Encore le mode dun vecteur (97.1) respectes, il existe des laboratoires dinformatique independants, des diplmes
7.2. Le mode amlior ($7.1) spkialiss, et *les enseignants et/ou chercheurs en informatique sont dsormais
7.3. Multiplication avec n%.trsivit ($7.2) considr& comme des scientifiques a part entire.
7.4. Suppression de la rcursivit ($7.2)
7.5. Version avec dcalages ($7.2) Pourquoi cette lutte ? Et pourquoi en parler dans un livre sur lalgorithmique ?
8.1. Arbre ordonn ($8.1) Le fait est que les informaticiens ont reprsent - et reprsentent toujours - un
8.2. Arbre Cquilibr (48.2.1) enjeu conomique. Comme cet enjeu a t concrtis par des moyens matriels et
8.3. B-arbres ($8.3) financiers 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 et
faux 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 autres
disciplines, les informaticiens ont perdu une partie de lessentiel. En se concentrant
sur les techniques non-numriques (importantes et indispensables), ils ont perdu
jusqu la notion de lexistence des nombret rels. De mme, un peu en singeant les
mathmaticiens, qui ont montr la voie vers la tour divoire, le besoin scientifique
mais aussi psychologique de la construction dune (ou de plusieurs) thorie(s) a fait
perdre la vraie justification de notre existence : lcriture de programmes qui sont
utiles. On est donc en prsence de plusieurs guerres, numrique contre non-
numerique, thorie contre application, utilisateurs contre spcialistes, vendeurs de
vent contre professionnels srieux. Si certaines guerres peuvent tre utiles et
salutaires, dautres resteront toujours striles.

12
&GORllMMIQUEEl-PROG?bU&MIlON

Ce livre ne saurait bien sr en corriger les carts. Mais nous voulons Cest en respectant lide que tous nos lbves savent un minimum sur la
tmoigner de notre foi dans lexistence de linformatique en tant que discipline programmation qua disparu le chapitre de ce livre destins aux d6butants. Ainsi, les
indpendante, mais surtout utile. Linformaticien comme le mathmaticien - mme types de donnes de base (entiers, tiels, caractres), leurs reprkwnations en machine
si ce dernier la peut-tre oubli - est un esclave des autres. Sa raison dtre est de et les instructions simples (affectations, boucles, conditions) ne sont pas dfinis dans
rendre service, cest--dire rsoudre des problbmes dapplication. Il ny a pas ce volume.
dinformatique acadmique diffrente de celle de lapplication numrique ou de
gestion. Il ny a pas une micro-informatique diffrente de linformatique classique. Dans sa forme actuelle, le cours dure une anne scolaire, au rythme de deux
Il y a une seule discipline, appele intervenir dans un trs grand nombre de heures par semaine. Il est ncessairement accompagn de travaux diriges et de travaux
domaines de lactivit humaine. pratiques. Chez nous, il y a trois heures de travaux dirigs et quatre heures de travaux
pratiques par semaine. De plus, la salle informatique est ouverte en libre service aux
Dans cette optique, la formation des informaticiens dans les universits et les Ctudiants autant de temps que possible en respectant les rgles lCmentaires de
coles dingnieurs doit se faire de manire quilibre. Un de nos critres est que scurid. Ce nest quau prix de la mise disposition dun mat&iel suffisant que les
si nous ne traitions pas tel sujet, nous pourrions par la suite avoir honte de nos &udiants peuvent rellement apprendre.
&ves ?. Le monde du travail sattend ce que nos lves sachent programmer (dans
le langage quutilise la compagnie concerne), quils connaissent un minimum de Nous proposons de nombreux exercices et problbmes. Le sujet que nous
mthodes de rsolution de problmes numriques, et que probabilits et attaquons ncessite un investissement personnel important. Le cours doit servir
statistiques ne soient pas des mots sotkiques rechercher dans le dictionnaire. Le stimuler des efforts individuels et la ralisation de projets de toutes sortes. Il doit
cours dcrit dans ce livre essaie de prendre en compte ces considrations. Nous obligatoirement se terminer par la cration dun logiciel en grandeur nature, de
lenseignons, dans des variantes appropries, depuis vingt-cinq ans, des Bves de pr6fkence produit par un petit groupe dleves (deux quatre).
premier et de deuxime cycle, en formation permanente, dans des diplmes
sptkialiss ou non. Lexprience a montr que lenseignement de ce cours de base de Les exemples dans ce livre sont rkligs dans un langage de programmation
linformatique est difficile, que personne ne possbde une recette miracle, mais que fictif qui ressemble a PASCAL. Comme boutade bien connue des quelques
tout le monde (surtout ceux qui nont jamais crit un logiciel utilise par dautres universits layant subi, le langage dans lequel nous rdigeons nos algorithmes a pris
personnes) pense lenseigner mieux que les autres. le nom GRIFFGOL, qui rsulte de rflexions de lpoque de MEFIA [Cunin 19781.
Cest un style de programmation relativement indpendant dun langage de
Nous prsentons donc ici, humblement (ce nest pas notre tendance profonde), programmation particulier, cest--dire que nous utilisons les concepts fondamentaux
quelques ides dun cours dalgorithmique et de programmation dont le niveau dans la forme qui nous semble la plus approprie. La construction des algorithmes se
correspond a la premire anne dun deuxibme cycle pour spcialistes en passe mieux quand on se permet une certaine libert dexpression. Leur mise en
informatique, en supposant que les lves concerns nont pas ncessairement subi uvre dans un ordinateur ncessite une simple mise en forme en fonction du langage
une formation pralable dans la matire, mais quils sachent tous un peu et du compilateur disponibles.
programmer Cela pose dailleurs un probleme particulier. Nous avons lhabitude de
mlanger des tudiants dorigines divers. Les uns peuvent avoir obtenu de bons Un corollaire est que nous disons nos tudiants quils doivent toujours
rt%ultats dans un IUT dinformatique, tandis que dautres nont que peu touch un r+ondre oui a la question connaissez-vous le langage X ?, quelle que soit la
clavier (situation de plus en plus rare, mais ltkiture dun programme de 10 lignes en valeur de X. En effet, sous condition que le langage soit de style algorithmique
BASIC peut tre considre comme une exprience vide, voire ngative, en classique, lapprentissage dun langage et/ou dun compilateur inconnu ne devrait
informatique). A la fin de la premire anne de deuxime cycle, il reste une durer que quelques jours. Dailleurs, un exercice classique que nous pratiquons est de
corrlation entre les tudes prealables et les rsultats acadmiques. Cette corrlation faire recoder un travail pratique dans lun ou lautre des langages grande diffusion
disparat au cours de la deuxime anne, provoquant quelques remontes que nos tudiants ne connaissent pas. Cest ainsi quils absorbent, par exemple,
spectaculaires au classement. La seule solution que nous avons trouv ce probleme FORTRAN. En pratique, a lheure actuelle, ils programment dans une version de
de non-homognit est de lignorer en ce qui concerne le cours, mais damnager des PASCAL, avec des prolongements en C. Le choix est remis en cause chaque
binmes mixtes en TP. Lexprience jusqualors est positive. rentre universitaire, car nous ne sommes pas des missionnaires dun langage
quelconque.

14 15
&GORlTHMIQUEETPROGR4MMATION &CiORITHMIQUFi I?I PROGRAMMMION

1.1. Quelques mots sur lenvironnement 1.2. Notes bibliographiques sommaires

Une petite phrase ci-dessus merite quon sy attarde un peu plus longtemps. Il existe dj, en franais, un certain nombre de livres [Arsac 19801, [Arsac
Nous avons parl de la disponibilit de matriels, essentielle lapprentissage de la 19831, [Berlioux 19833, [Boussard 19831, [Courtin 1987a,bl, [Gerbier 19771,
programmation, qui est une activit constructive. On ne peut apprendre quen [Grgoire 1986, 19881, [Lucas 1983a,b], [Meyer 19781, [Scholl 19841 dans le
sexerant. Or pour sexercer de manire satisfaisante, lidal, si nous pouvons nous domaine que nous abordons ici. Un pourcentage lev porte un nom dauteur qui
permettre le parallele, est que les ordinateurs doivent tre comme les WC : il y en a nous est familier, car il sagit de collgues et souvent amis. Cela indique que les
toujours un de libre quand on en a besoin, voire mme quand on en a envie. (Cette reflexions concernant ce sujet sortent, en France au moins, dun nombre limite
phrase a t prononce pour la premire fois, notre connaissance, par P.M. dcoles qui, en plus, ont pris lhabitude de discuter. Le nombre de livres indique
Woodward, du Royal Radar Establishment MaIvern, Angleterre. Cest un plaisir de limportance que chacun accorde au sujet, et les diffrences dapproche dmontrent
rendre cet amical hommage a un matre mal connu, en se rappelant quen 1964 il quil est loin dtre puise. Comme dans la tradition littraire, il y aura toujours des
fallait une vision tr&s large pour sexprimer ainsi.). ides differentes sur ce sujet. En continuant le parallble avec lcriture, nous
recommandons aux &udiants de prendre connaissance de plusieurs styles diffrents,
Certains de nos collgues restreignent volontairement le ct exprimental de puis de dvelopper leur propre style en profitant des apports de chacun.
la programmation, dans le but dimposer, ds le dbut de lapprentissage, toute la
rigueur ncessaire. Cest une reaction saine par rapport une situation historique Ayant indiqu quelques livres en franais, il serait draisonnable de laisser
datant de lpoque o la programmation se faisait nimporte comment. Mais nous limpression que la France poss&le un monopole des ides. Au niveau international,
nallons pas jusqu empcher nos leves de faire leurs btises. Cest en comparant il existe une bibliographie consquente en langue anglaise, dont voici les rferences
des versions sauvages de programmes avec dautres qui sont bien faites quils qui correspondent une selection personnelle parmi les ouvrages les plus connus :
comprennent rellement lintrt dune mthodologie. [Aho 1974, 19831, [Dijkstra 19761, [Gries 19811, [Ledgard 19751, I\irirth 1976,
19771.
Ainsi, nous voulons que les lves passent beaucoup de temps dans la salle des
machines. Au dbut, ils travaillent mal, mais deviennent - pour la plupart -
raisonnables la fin de la premire anne. Cette approche profite dune certaine 1.3. Remerciements
fascination pour lordinateur (la jouissance de le dominer ?), qui sestompe aprs cette
premire anne. Le fait de vouloir rflchir, plutt que de se lancer immdiatement Sur un sujet tel que le ntre, il serait impensable de citer tous ceux qui ont
sur la machine, est un signe majeur de maturit chez llve. Cette tape ne peut tre influenc notre reflexion. Nous nous limitons donc la mention de quelques groupes
franchie que parce que le matriel est toujours disponible. Un tudiant ne doit pas de personnes, en nous excusant vis--vis de tous les collegues que nous ne citons pas
tre stress par la longueur dune file dattente, ni frustr par des difficults individuellement.
matrielles. Nous notons dailleurs que, bien que les programmes crits en deuxime
anne soient assez importants, loccupation des postes de travail diminue. Comme premire influence directe, il y a eu le groupe de P.M. Woodward
Malvem au dbut des annes soixante. Lauteur y a fait ses premieres armes, et ses
Lentranement la programmation est une ncessit pour tous les premiers cours, partir de 1962, sous la direction de J.M. Foster et D.P. Jenkins,
informaticiens, quelle que soit leur exprience. Une source de stimulation pour les avec IF. Currie, A.J. Fox et P.R. Wetherall comme compagnons de travail. Le
leves est de travailler en contact avec des enseignants qui programment bien. Tant foisonnement clidees Grenoble entre 1967 et 1975 a te dune grande importance.
quils sentent quil leur reste du chemin a faire pour arriver au niveau de rendement de Signalons seulement une collaboration directe avec P.Y. Cunin, P.C. Scholl et J.
ce modle, ils se piquent au jeu. Cela signifie que lenseignant doit lui-mme Voiron [Cunin 1978, 19801, bien que la liste aurait pu tre nettement plus longue.
continuer a programmer rgulirement, comme le musicien qui continue faire des LCcole de C. Pair Nancy a montre la rigueur et a donn des opportunits de
gammes. Mme si nous navons plus le temps de produire de gros logiciels, il faut comparaison de styles. Finalement, la cr&tion du diplme dingnierie informatique
sastreindre rsoudre rgulirement des petits problmes. Ceux-ci peuvent, par la
a Marseille en 1985 a provoqu un effort de synthese dont le r&sultat est ce volume.
suite, contribuer au renouvellement de notre stock dexemples et dexercices.
De nouvelles versions du polycopi ont vu le jour Nantes en 1990 et 1991.

16 17
ftWORIIUMlQUE FX PROGRAMWUTON

Des rencontres ponctuelles ont aussi eu leur importance, en particulier a travers Libre a chacun dapprcier notre choix. De toute faon, il est entendu que chaque
les t5coles organiss par F.L.Bauer [Bauer 1974, 1975, 1976, 19791. Celles-ci ont enseignant mettra la matire a sa sauce.
permis de travailler avec son quipe et de rencontrer et de se confronter avec
E.W.Dijkstra, G.Goos, D.Gries, J.J.Horning, P.C.Poole et W.M.Waite, parmi de Dans la mesure du possible (ou en fonction de nos connaissances), nous avons
nombreux autres collegues. essay dattribuer la paternit des exemples, mais beaucoup dentre eux ont des
origines dj inconnues. Toute information supplementaire sera le bienvenue.
Le feedback de gnrations dtudiants nous a permis de constater que
lapprentissage de linformatique nest pas toujours aise si lon veut atteindre un bon
niveau. Nous remercions ces jeunes (certains ne le sont plus) pour leur apport, dont
ils ne se sont pas toujours rendu compte (nous aussi, nous apprenons !). Emmanuel
Gaston du DU-II et un groupe du mastere dintelligence artificielle de Marseille,
promotion 198889, ont corrige un certain nombre derreurs de franais. Nathalie
Wurbel a aide en signahtnt des erreurs de franais et de programmation. Christian
Paul et Annie Ttiier ont galement apport des corrections au niveau du franais. Au
cours dun projet du DU-II, Vita Maria Giangrasso et Thierry Guzzi [Giangrasso
19891 ont men bien une tude comparative de certains algorithmes. Le journal
Jeux et Stratgie, source de problmes intressants, nous a aimablement permis den
utiliser dans certains exemples.

Ce livre a t prpar sur des micro-ordinateurs mis a notre disposition par


differents organismes, dont feu le Centre mondial dinformatique et ressources
humaines, le CNRS, luniversit dAix-Marseille III, linstitut mditerranen de
technologie 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 livre
combinant lalgorithmique numrique et non numrique. Pour diffrentes raisons, ce
projet na pas vu le jour. Lutilisation du nous dans cette introduction reprsente ce
pluriel. Je lai laiss dans cette version definitive, en esprant que Jacek redigera le
volume numrique dont nous avons besoin, en mme temps que je lui tmoigne ma
reconnaissance 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 que
nous travaillons partir dexemples. Ceux-ci sont de plusieurs types :
- les classiques, qui se trouvent dj dans dautres ouvrages, mais qui sont
essentiels 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 qui
prsentent nanmoins un intrt pour Itudiant.

18 19
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 ses
cours dintroduction linformatique. 11 a t repris par diffrents auteurs dans le cadre
de lanalyse dalgorithmes [Arsac 19841, [Griffiths 19761.

On considre un vecteur, disons dentiers, dont les lments sont ordonns. Son
mode 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 un
progmmme qui prend en entre un vecteur ordonn et qui livre le mode du vecteur en
sortie.

2.1.1. Construction de la premire version du programme

Commenons par une premire ide dalgorithme. On note que


lordonnancement du vecteur fait que les diffrentes occurrences dun lment qui se
rpkte sont contigus. II sagit donc de trouver la plus longue chane dlments
identiques. On va considrer les lments tour de rle, en se rappelant de la plus
longue chane vue jusqu prsent. Pour chaque nouvel lment, on se posera la
question de savoir si sa lecture mne une chane qui est plus longue que la
pr&dente. Dans ce cas, cest la chane courante qui devient lachane la plus longue.
hOORlTHMQUE J.?T PROGRAMhUTlON liLOORllHMlQUE W PROGRAMMKCION

Pour garder les informations ncessaires, il faut disposer des valeurs suivantes : monde (i, lmax, m, lc), la phase dinitialisation sert leur donner des valeurs
- n est le nombre dlments dans le vecteur v, permettant de dmarrer. Cette ligne correspond au traitement du premier lment : la
- i est le nombre dlements qui ont dj t considrs, chane maximum est la chane courante, de longueur 1. Dans le TANTQUE, comme
- lmaj, est la longueur de la plus longue chane en v[l..il, i est le nombre dlments dja traits, le test de la fin est bien icn (autrement dit, il
- m est lindex en v dun lment dans la chane de longueur lmax : reste 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 deux
v[m] = mode(v[l ..i]), CaS : soit on allonge la chane courante (V[i] = V[i-l]), soit on commence une
nouvelle chane. La nouvelle chane, dcrite dans la partie SINON, est de longueur 1
- lc est la longueur de la chane courante (a laquelle appartient V[il). (1~~1) et ne met pas en cause lmax ou m (qui ne sont donc pas modifis). Si la
On appellera cet ensemble de definitions ltat du monde (state of the world). chane courante a t allonge (partie ALORS), on augmente lc (lc:=lc+l) avant de
tester si la chane courante est devenue la chane maximale (SI lolmax). Dans ce
Le programme 2.1, qui met en uvre ces ides, est une application du schma cas, hnax et m sont mis a jour (hnax:=lc; m:=i).
suivant :
Nous prtendons que cette construction dmontre la justesse du programme
Initialiser donn. La dmonstration depend de lacceptation de la rcurrence ( partir du cas i-l
TANTQUE NON fini on cr6e le cas i, le cas 1 tant trait dans linitialisation) et de la validit de ltat du
FAIRE avancer monde. En particulier, dans la boucle, avancer est fait par i:=i+l et les autres
FAIT instructions remettent les ClCments de ltat du monde jour en fonction de ce que
Ion y trouve.
Le programme est comment par la suite.
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 de
DEBUT DONNEES n: entier; lc+l (allongement de la chane en cours). La chane courante devient la chane la
v: TABLEAU [1 ..n] DE entier; plus longue si lolmax. Dans ce cas, lmax et m reoivent des valeurs appropries.
VAR i, max, m, lc: entier; Comme tous les lments de ltat du monde ont des valeurs correctes, le programme
i:=l ; Imax:=l ; m:=l ; Ic:=i ; entier est juste.
TANTQUE kn
FAIRE i:=i+l ;
SI V[i] = V[i-l ] 2.1.2. Remarques mthodologiques
ALORS IC:=I~+~;
SI blmax La construction dun programme correct dpend de la logique employee par son
ALORS Imax:=lc; m:=i c&teur. Cette logique ne peut sexercer que si les bases dclaratives sont saines.
FINSI Cest ici quune bonne formalisation de letat du monde est fondamentale. Cet tat du
SINON Ic:= 1 monde peut tre dcrit en franais (ou en anglais ou en polonais, nous ne sommes
FINSI pas racistes) ou en style mathmatique. Le choix entre les deux (ou les quatre) styles
FAIT est une question de got et de type dapplication.
FIN
Mais, que ltat du monde soit crit en franais ou en formules mathmatiques,
Programme 2.1. Le mode dun vecteur il se doit dtre prcis. De nombreux programmeurs agrmentent leurs programmes
avec des commentaires du type Y est lindex de llment de Y. Ils font souvent
lerreur classique de confondre le dernier lment traite avec son suivant (celui qui va
Les donnes du problme sont n, la longueur du vecteur, et le vecteur ordonn, tre mit).
v Les deux sont initialiss par ailleurs. Aprs les dclarations des objets de ltat du

22 23
.&GORlTHMIQUEETPROGRAhM4TION &GORITHMIQUE ET PROGRAhthUTlON

Lutilisation de tableaux et de boucles impose dautres contraintes. En rien du tableau, cest--dire quil faut en examiner tous les lements pour dmontrer
particulier, il faut dmontrer la terminaison de chaque boucle et confirmer que lindex labsence eventuelle de lobjet recherche. Bien sr, le programme sarr&era ds que
de chaque rc?f&ence a un lment de tableau est entre les bornes (i doit tre contenu en lobjet est trouv6. Par la suite, nous montrerons comment rendre lalgorithme plus
[l..nl). efficace en introduisant des connaissances concernant la forme des donnes.

Pour la terminaison de la boucle, il ny a pas de probleme ici. La variable de


contrle i est augmentee de 1 chaque tour de la boucle, et arrivera donc n pour 2.2.1. Recherche linaire
arrtfx le massacre.
Lalgorithme le plus simple examine tour de rle chaque lment jusqu la
Les seules n5ferences a des lements de tableaux sont dans le test SI v[i]=v[i-11. r6ussite de la recherche ou lpuisement des candidats. Il ncessite ltat du monde
i commence a un et la boucle sarrte quand i=n. Avant laffectation i:=i+l suivant :
lintkieur de la boucle, on a donc lingalite suivante :
DONNEES
I~i43 n: entier, le nombre dlments de 1,
i: TABLEAU [l ..n] DE entier, le tableau examiner,
Apres laugmentation de i, ceci devient : objet: entier, lobjet trouver,

1 <isn VARIABLES
i: entier, le nombre dlments dj examins,
On voit facilement que i et i-l sont tous les deux linterieur du domaine l..n. trouv: bool, trouv z t[i]=objet.

Cette solution du problbme, dune grande simplicit, est correcte, mais elle Le programme 2.2 est une mise en uvre possible.
nest pas la meilleure possible. Il existe une variante qui est moins longue, qui
utilise moins de variables, et qui sexcute plus vite. Il est mme surprenant que
lamlioration 6chappe a la quasi-totalit des programmeurs. Nous y reviendrons dans DONNEES n, objet: entier;
un paragraphe ultrieur (cf. 7.1). t: TABLEAU [l ..n] DE entier;
PRECOND n>O
Par ailleurs, la solution donne comporte une faiblesse. En gnral, il y a au DEBUT VAR i: entier, trouv: bool;
moins un Ctudiant, ou une tudiante, dans la classe qui reste suffisamment n%eill(e) i:=O; trouv:=FAUX;
pour poser la question suivante : TANTQUE kn ET NON trouv
Quest ce qui se passe si deux chanes sont de mme longueur, cest--dire si FAIRE i:=i+l ; trouv := t[i]=objet
deux modes se prsentent ?. FAIT
Bonne question ! La rponse peut tre de prendre nimporte lequel des modes POSTCOND (trouv ET objet=t[i]) OU (NON trouv ET i=n)
possibles, mais la faiblesse rside dans le fait que notre spcification du problme ne FIN
parlait pas de cette possibilit. On voit quil nest pas simple de bien spcifier des
algorithmes, surtout quand il faut tre complet. Programme 2.2. Recherche dun objet dans un vecteur

2.2. Recherche dun objet Le programme est encore une application du schma suivant :
Initialisation
Dans ce nouveau programme, il sagit de trouver lemplacement quoccupe un TANTQUE NON fini
objet (disons un entier) dans un tableau. Cest une opration mene frquemment FAIRE avancer
dans des programmes de tous types. Supposons en premier lieu que nous ne savons FAIT

24 25
hOORITHMIQUE! GT PROGRA~ION fiLGORITHhtIQUEETPROGRA-ION

Linitialisation de ltat du monde dit que, le programme nayant rien vu (i:=O), Que sait-on sur ce programme ? Une premiere dduction, vidente, est que,
lobjet na pas encore t trouv (trouv6:=FAUX). Pour avancer, on augmente i de 1 comme le programme a quitte la boucle, la condition de continuation de la boucle est
et on remet trouv a jout Le processus peut terminer soit par la russite (trouve maintenant fausse. Ainsi, apres FAIT, on peut dduire :
devient VRAI), soit par linspection du dernier lment (i=n). Notons que les deux
conditions peuvent tre vrifies en mme temps, car lobjet peut se trouver en t[nl. NON (icn ET NON trouv).
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 lentre Par application de la loi de Morgan, ceci devient :
dans la boucle. Avec laugmentation de la valeur de i, ceci devient Cki<n au moment
de la nSf&ence, cest--dire I&n. irn OU trouv.
Dans ce programme, nous avons introduit deux nouvelles notions : la pr-
Comme i navance que dun pas la fois, on peut dduire :
condition ~ptecondition) et la post-condition Cpostcondition). La prd-condition est
ce qui doit tre vrai pour que le programme soit excutable. Ici, il faut quil y ait au i=n OU trouv.
moins un lment dans le tableau. Notons en fait que, si cette condition ntait pas
vrifiCe, par exemple n=O, le programme dirait que lobjet est absent, mais ceci est Les OU de linformatique tant inclusifs, les deux clauses peuvent tre vraies
un hasard. La post-condition est ce que lon sait la fin du programme. Elle doit en mme temps (cas de t[n] = objet). Les post-conditions du programme donn
servir de spdcification du rsultat. suivent logiquement, en considrant laffectation la variable trouv dans lintrieur
Prenons lexemple dune procdure de calcul dune racine carree. On aurait la de la boucle.
structure suivante :
En gnral, on peut souhaiter que la post-condition se retrouve partir de la
DONNEE x: rel; pr-condition, de dductions du type donn ci-dessus et des dfinitions de ltat du
PRECOND ~20; monde. Mais la post-condition que nous avons jusquici est incomplte. Quand
Procbdure de calcul de y=sqrl(x) lobjet a t trouv, i indique bien son emplacement, mais la non-russite est mal
POSTCOND y y = x (en gnral, epsilon prs)
l
dcrite. Nous navons pas encore expliqu que NON trouv veut dire que lobjet est
On sait calculer les racines carrees des nombres non ngatifs (pr-condition) et absent.
le rt%ultat est un nombre dont le carre est la donne dorigine (post-condition).
Lerreur, classique, a t de construire les pr- et post-conditions aprbs coup. Il
Dans notre programme de recherche linaire, la pr-condition est raisonnable, aurait fallu spcifier le programme avant de lcrire, les conditions servant de
mais la post-condition nest pas entirement satisfaisante. Elle comporte deux spcification. Dans notre cas, on aurait :
lacunes : elle nest pas directement dductible du texte et le sens de la variable trouve
nest pas bien dfini, mme si le programme est juste. Regardons maintenant le PRECOND
processus de dduction. Soient un objet et un vecteur t de longueur n, n>O;

Reprenons le programme avec sa pr-condition, mais sans post-condition pour POSTCOND


le moment : Ou t[i]=objet,
ou il nexiste pas i, O&n, tel que t[i]=objet.
PRECOND n>O;
DEBUT VAR i: entier, trouv: bool; Notons que la variable trouv ne figure plus dans la post-condition. Elle sert
i:=O; trouv:=FAUX; distinguer les deux cas de solution. Il faut maintenant dmontrer la vrit de cette
TANTQUE kn ET NON trouv nouvelle post-condition. Quand lobjet a t trouv, la logique prcdente est
FAIRE i:=i+l ; trouv := objet=t[i] suffisante. Pour montrer labsence de lobjet, il nous faut une clause de plus.
FAIT Reprenons le texte avec de nouvelles dcorations :
FIN

26 27
DONNEES objet, n: entier; t: TABLEAU [l ..n] DE entier; i:=l ;
P R E C O N D n>O; TANTQUE ig ET t[i]+objet
DEBUT VAR i: entier, trouv: bool; FAIRE i:=i+l
i:=O; trouv:=FAUX; FAIT
TANTQUE kn ET NON trouv
FAIRE INVARIANT O<jsi => t[j] f objet; Malheureusement, ces deux programmes comportent une faiblesse qui ne se
i:= i+l; trouv := t[i]=objet montrera quavec certains compilateurs. Supposons, dans la demikre version ci-
FAIT dessus, que lobjet nest pas prsent dans le vecteur. La boucle tourne pour la dernire
POSTCOND t[i]=objet OU i (O&n => t[i]#objet) fois avec i=n. Lexcution de la boucle augmente la valeur de i, donnant i=n+l. On
FIN teste de nouveau avec TANTQUE. La premire partie de la condition (iln) est fausse,
mais on peut quand mme en valuer la deuxime partie afin de disposer des deux
Linvariant dit que la boucle nest excute que si lobjet na pas encore t oprandes de loprateur ET. Cette deuxime partie comporte une rfrence t[i],
trouv. La post-condition peut maintenant tre dmontre. En effet, Zi la terminaison cest--dire a t[n+l]. Or, cet lkment nexistant pas, le programme peut terminer par
de la boucle, si trouvb est FAUX, alors i=n ET t[i] nest pas lobjet. Mais avant lerreur index en dehors des bornes.
dexcuter linstruction i:=i+l, aucun tu], O<jii, ntait lobjet. Aprs laugmentation
de i, si t[i] nest pas lobjet, linvariant reste confirm. Quand i=n, la deuxikme partie Cette faiblesse peut sliminer avec lintroduction de loprateur ETPUIS
de la post-condition est correcte. (CAND), qui ordonne les tests. Ainsi, on pourrait Ccrire :

Lutilisation dassertions telles que les invariants de boucles permet darriver TANTQUE ig ETPUIS t[i]+objet
des preuves formelles de programmes. En pratique, la preuve complkte dun
programme de taille industrielle savre longue et coteuse. Mais ce nest pas une Quand i>n, cest--dire que le premier oprande est FAUX, on nvalue pas le
raison pour ltudiant de ne pas connatre ces techniques. Une familiarit avec les deuxikme. Cela dpend du fait que (FAUX ET b) est toujours FAUX, quelle que soit
bases des preuves de programmes est une des cls de lamlioration de la performance la valeur de b. Il existe galement loprateur OUALORS (COR). Les dfinitions
dun programmeur. Il crke de la sorte des schmas mentaux qui font quil analyse ses de ces oprateurs sont les suivantes :
problmes de manire plus rigoureuse, produisant des programmes de meilleure
qualit en commettant moins derrwrs. a ETPUIS b J SI a ALORS b SINON FAUX FINSI
a OUALORS b J SI a ALORS VRAI SINON b FINSI

2.2.2. Un pige Notons 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 de
Les programmeurs de la gnration prcdente naimaient pas les variables cette faon dans tous les compilateurs.
bool6ennes. Ils prfraient crire le programme ci-dessus dans une forme priori plus
simple :
2.2.3. La dichotomie
i:=O;
TANTQUE kn ET t[i+l ]+objet Quand on ne sait rien sur les lments dun tableau, pour tablir quune valeur
FAIRE i:=i+l donne ne sy trouve pas, il faut inspecter tous les lments, car la valeur peut
FAIT figurer nimporte quelle place. Maintenant, nous allons considrer un cas plus
intressant, o les lments du tableau sont ordonns. Cest comme laccs un
En supprimant la variable trouv, le test de russite se fait sur le prochain annuaire tlphonique. Pour trouver le numro de M.Dupont, on ne regarde pas
lment t[i+l]. Afin dviter le calcul de lindex, on peut redfinir i comme lindex de toutes les entres de A DUPONT, On procde par des approximations.
Glment traiter et non plus llment qui vient dtre trait :
Pour nous faciliter la programmation, nous allons procder par des
approximations simples. Dans un annuaire de 1000 pages, on regarde la page 500.

28 29
ALOORIlNh4IQUE ET PROGRAMMtUlON
&GORIITMQUE I ? I - PROGRAMMtWON

Si llment recherch est alphabtiquement plus petit, on a restreint la recherche aux La pr-condition exprime le fait que nous disposons dun vecteur ordonn dau
pages 1 499, ou, sil est plus grand, aux pages 501 a 1000. Chaque regard coupe le moins deux lments. Linitialisation indique que le domaine de recherches est
domaine de recherches en deux. Les recherches sarrtent si llment examine est le t[l..n], lobjet ntant pas encore trouv. La condition apres TANTQUE mrite des
bon, ou si le domaine de recherches est devenu nul (lobjet est absent). explications. La proposition NON trouv est vidente, mais la partie avant le ET
lest moins. Pour considrer une valeur intermdiaire, nous imposons quelle soit
Considrons une Premiere version de ce programme, avec ltat du monde
diffrente des deux extrmes, cest--dire que linegalit suivante soit vraie :
suivant :
bas, haut: entier, SI t[iJ=objet ALORS bas s ii haut Proposition A. bas < centre e haut
centre: entier, t[centre] est Ielment examiner
trouv: boolen, trouv j t[centre]=objet Cette inegalit ncessitant lexistence dau moins une valeur entre bas et haut,
on retrouve :
Appliquons comme dhabitude le schma :
Initialisation Proposition B. haut - bas > 1
TAfiTQUE NON fini
FAIRE avancer Dans la boucle, le calcul de la valeur de centre ncessite une conversion, par la
FAIT fonction entier, du rsultat de la division, qui est un nombre rel, en un nombre
entier. On confirme facilement que centre est bien entre haut et bas en appliquant la
Le programme 2.3 est une solution possible. proposition B ci-dessus. Quand la somme (haut + bas) est impaire, la division par
deux donne un nombre relle de la forme n,5. Que larrondi vers un entier donne n ou
n+l na aucun effet sur lalgorithme (les deux possibilits respectent la proposition
DONNEES n: entier, t: TABLEAU [l ..n] DE entier;
A). Par la suite, la clause CHOIX force un choix entre les trois possibilits ouvertes
PRECOND n>l ET (O&jg => t[i]s[i])
aprs comparaison de lobjet avec t[centre]. Ou lobjet a t trouv (tkentre] = objet),
DEBUT VAR bas, haut, centre: entier, trouv: bool;
ou le domaine de recherches est coupe en deux (bas:=centre ou haut:=centre, suivant
bas:=1 ; haut:=n; trouv:=FAUX;
la condition).
TANTQUE haut-bas>1 ET NON trouv
FAIRE centre:=entier((haut+bas)/2);
Si lobjet est trouv, tout va bien. Si la boucle se termine sans trouver lobjet,
CHOIX t[centre]cobjet: bas:=centre,
haut et bas sont maintenant deux indices successifs :
t[centre]=objet: trouv:=VRAI,
t[centre]>objet: haut:=centre
haut = bas + 1
FINCHOIX
FAIT;
La derniere partie du programme teste si lobjet se trouve en t[haut] ou en
SI NON trouv
@as]. Ce test est irritant pour le programmeur. Il nest utile que si t[l]=objet ou
ALORS SI t[bas]=objet
t[n]=objet, car ds que haut ou bas change de valeur, ils prennent celle de centre,
ALORS centre:=bas; trouv:=VRAl
t[centre] ntant pas lobjet. Donc le test ne sert que si lune des variables haut ou bas
SINON SI t[haut]=objet
a garde sa valeur initiale.
ALORS centre:=haut; trouv:=VRAl
FINSI
En fait, le test est d a une faiblesse de spcification. Il faut dcider si oui ou
FINSI
non t[haut] ou t[bas] peuvent contenir lobjet, et cela de maniere permanente.
FINSI
FIN Essayons deux nouvelles versions du programme. La Premiere respecte les
initialisations de loriginal, ce qui veut dire que t[haut] ou t[bas] peut toujours
POSTCOND trouve => t[centre]=objet,
contenir lobjet :
NON trouv => i, O&n, t[i]#objet
Programme 2.3. Recherche par dichotomie

30 31
hGORlTHMIQUEETPRWRAhtMTION hCiORIll+MIQUE ET PROGRAMMMION

DONNEES n: entier, t: TABLEAU (1 ..n] DE entier; Al. O&bas => t[i].cobjet


PRECOND n>l ET O&jg => t[ikt[i] A2. haut&n => t[i]>objet
DEBUT VAR bas, haut, centre: entier, trouv: bool;
bas:=1 ; haut:=n; trouv:=FAUX; La condition de terminaison bas > haut montre alors labsence de lobjet dans t.
TANTQUE haukbas ET NON trouv Cela correspond la deduction que lon peut faire la sortie de la boucle :
FAIRE centre:=entier((haut+bas)/2);
CHOIX t[centre]<objet: bas:= centre + 1, NON (haut 2 bas ET NON trouv)
t[centre]=objet: trouv:= VRAI,
t[centre]>objet: haut:= centre - 1 Cest--dire :
FINCHOIX
FAIT bas > haut OU trouv
FIN
POSTCOND trouv => t[centre]=objet, bas > haut est la condition dabsence, trouv implique t[centre] = objet.
NON trouv => i, O&n, t[i]+objet
La deuxime bonne solution notre problme est de faire en sorte que ni t[bas]
Programme 2.4. Dichotomie, version 2 ni t[haut] ne peut tre lobjet. Considrons la version du programme 2.5.

Trois changements figurent dans cette version du programme par rapport DONNEES n: entier, t: TABLEAU [i ..n] DE entier;
loriginal. Dans le choix, quand t[centre] nest pas lobjet, la nouvelle valeur de bas PRECOND n>l ET O&jg => t[ikt[i]
(ou haut) ne doit pas se situer sur le centre, mais un pas plus loin, sur le premier DEBUT VAR bas, haut, centre: entier, trouv: bool;
candidat possible (centre est le dernier lment rejet). En plus, dans le TANTQUE, bas:=O; haut:=n+l ; trouv:=FAUX;
au lieu de proposition B, nous avons simplement : TANTQUE haut-bas>1 ET NON trouv
FAIRE centre:=entier((haut+bas)/2);
haut 2 bas CHOIX t[centre]<objet: bas:=centre,
t[centre]=objet: trouv:=VRAI,
Quand la proposition B est vraie, la situation na pas change par rapport la t[centre]>objet: haut:=centre
version originale. Quand haut=bas, centre prend cette mme valeur et lon teste le FINCHOIX
dernier candidat. Si ce nest pas le bon, on ajuste haut ou bas, avec le rsultat : FAIT
FIN
bas > haut POSTCOND trouv => t[centre]=objet,
NON trouv => i (O&n => t[i]#objet)
Quand haut suit immdiatement bas, centre va prendre une valeur qui est soit
celle de haut, soit celle de bas (il ny a pas despace entre les deux). Mais, grce au Programme 2.5. Dichotomie, version 3
fait que bas, OU haut, prend sa nouvelle valeur un cran plus loin que le centre, an
prochain tour de la boucle, on aura :
Dans cette version, seules les initialisations de bas et haut ont t modifies.
bas = haut ou bas > haut Ces variables prennent des valeurs dindices inexistantes. Mais ce nest pas grave, car
les Kments correspondants ne seront jamais rfrencs. La preuve de cette version
La boucle termine toujours. La preuve de la correction de ce programme peut du programme est facile. Elle est la mme que celle de la version originale, sauf pour
se faire partir des assertions suivantes : Itive a la situation :

haut = bas + 1

32 33
kOORIlWMIQUE F?I- PROGRAMMATION /UOO-QUE ET PROGRAhGfA-MON

Dans ce cas, comme ni t[haut], ni t[bas] nest lobjet, celui-ci nest pas dans t, Dans le jargon de linformatique, on parle de la r6duction dun problme en n
car il ny a pas dlment entre t[haut] et @as]. vers 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 dans
La technique consistant a utiliser comme bute une valeur inexistante (ici en certains cas, on rduit un problme en n vers deux problbmes en n/2. On appelle
considrant [O..n+l] au lieu de [l..n]) est utilise frquemment par de bons cette demiete technique lart de diviser pour rgner (divide and conquer).
programmeurs. Notons quil na pas t ncessaire de crer rellement les lments
fictifs introduits. Nous tirons deux conclusions de cette brve discussion. La premire est que des
connaissances minimales sur le calcul de la complexit des algorithmes sont
necessaires si lon veut pratiquer de linformatique B un bon niveau. Le sujet, assez
2.3. De la complexit des algorithmes difficile, est trs tudi par des chercheurs. Ces recherches demandent surtout des
comptences leves en mathmatiques. Mais on peut faire des estimations utiles
Le parallle avec lannuaire tlphonique montre que les performances de ces avec un bagage limite. La deuxieme conclusion concerne lefficacit des programmes.
deux algorithmes (recherche lin6aire et recherche dichotomique) sont trs diffrentes. On voit souvent des programmeurs schiner sur leurs programmes pour gagner une
Leur complexit est facile tablir. instruction ici ou l. Evidemment, dans certains cas prcis, cela peut devenir
ncessaire, mais cest rare. Le gain defficacit est limit. Mais le probleme nest pas
Pour la recherche linaire : le mme au niveau des algorithmes, comme lattestent les chiffres de la table 2.1.
- Si lobjet est prsent dans le tableau, il peut tre nimporte o. En moyenne, Des gains defficacit travers lalgorithmique peuvent tre importants. Il nest pas
le programme examine n/2 lments avant de trouver le bon. tres sens doptimiser un mauvais algorithme - mieux vaut commencer avec un
Si lobjet est absent, on examine tous les n lments. bon. Loptimisation locale peut se faire par la suite en cas de besoin.
La complexit de lalgorithme est donc de o(n). Cela veut dire que si lon doublait le
nombre dl6ments, les recherches dureraient en moyenne deux fois plus longtemps.
2.4. Rsum des principes introduits
La dichotomie est tout autre. Ici, un doublement de la taille du tableau
ncessite un seul pas supplmentaire (chaque examen dun lment divise la taille du Au cours de ce chapitre, nous avons introduit plusieurs principes importants,
domaine de recherche par deux). Considrons le cas dun tableau de 2k lments. qui forment la base de notre technique de programmation.
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)). Nous travaillons souvent B partir dun schma de programme (pro-
scheme). Cest une maquette qui indique la structure gnrale. Le seul schma
utilise jusquici est celui dun processus linaire :
La diffrence entre ces deux courbes est trs importante, surtout quand le
nombre dlments est grand. La table 2.1 compare le nombre maximum de pas (n)
Initialiser
dans le cas de recherche linaire avec le nombre maximum de pas avec la dichotomie.
TANTQUE NON fini
FAIRE avancer
FAIT
n dichotomie
On complte le schma linaire en utilisant un tat du monde, qui est une
10 4 (24= 16) dfinition prcise des variables. Cet tat permet de confirmer la justesse du
100 7 (2= 128) programme en lexploitant comme une liste a cocher en @onse des questions du
1000 10 (2O= 1024= l k ) type suivant :
1 000 000 20 (2O = 1024k = 1 048 576) - 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 ?
Table 2.1. Comparaison entre la recherche linaire et la dichotomie
Lexistence dune definition prcise des variables facilite la dfinition de la

34 35
&OORITEIMIQUFi ET PROGRAMMtWION &GORITlMQUE EI- PROGRAMMtWION

condition de terminaison. De mme, expliciter la notion davancer diminue la Le style present est donc un effort de compromis, matrisable par les etudiants
probabilit de lcriture de boucles infinies. Nanmoins, pour viter cette dont nous disposons tout en les guidant. Au cours de leurs travaux dirigs, ils
msaventure, on dmontre consciemment (et consciencieusement) la terminaison de menent a bien au moins une preuve formelle complte afin de comprendre les outils
chaque boucle. Le r6flexe de dmonstration de validit doit aussi jouer chaque fois sous-jacents.
que lon repre un lment de tableau. On dmontre que les indices sont
n&essairement entre les bornes.
2.4.2. Le styLe dcriture
Nous avons utilis les notions de pr-condition et post-condition. La pr-
condition indique les limitations du programme, cest-a-dire les caractristiques des Cet ouvrage sadresse aux problmes algorithmiques. Aucun des programmes
donnes en entre. Elle sert pour des dmonstrations de correction, mais aussi pour la prsents ne dpasse la taille dun module dans un programme complet. La mise
documentation dun programme. Avec la pr-condition, un utilisateur eventuel peut ensemble dunits de programme pour la construction dun produit industriel est un
confirmer quil a le droit dappeler le programme avec les donnes dont il dispose, problme aborde ailleurs (cours de gnie logiciel, projets).

La post-condition indique ce que le monde extrieur sait aprs lexcution du Mais il ne faut pas perdre de vue cette question de modularit. Lutilisation de
programme. On doit pouvoir remplacer tout programme par nimporte quel autre qui la clause DONNEES, avec les pr-conditions et post-conditions, vise, parmi dautres
respecte les mmes pr-condition et post-condition, sans que Iutilisateur ventuel buts, prparer la dfinition de modules, avec leurs spcifications, interfaces et
sen rende compte. corps. En pratique, dans le cours enseign, ces notions forment la matibre de
discussions, prparant ainsi le travail en profondeur venir.
Une partie difficile du processus de la mise en uvre est la spcification du
programme. Mais le travail fait a ce niveau est payant. En effet, le cot dune erreur
augmente avec le temps quelle reste prsente. Mieux vaut passer un peu plus de 2.5. Adressage dispers
temps en dbut du processus que de payer trs cher, plus tard, llimination des
erreurs. Les premiers programmes dans ce chapitre sont des exemples simples,
introduits pour des raisons pdagogiques. Mais, en mme temps, nous avons
Pour dmontrer la correction dun programme, on utilise des assertions et des
examin des mthodes de recherche dun lment dans un vecteur. Dans une premire
invuriants. Les assertions sont des formules logiques qui sont vraies aux endroits o
liste dalgorithmes de ce type, il faut introduire celui de ladressage dispers (hash
elles figurent dans le programme. Un invariant est une assertion qui est vraie code), qui est frquemment utilis dans la gestion, dans les compilateurs ou dans
chaque tour dune boucle. Une boucle est compltement dfinie par son tat du
lintelligence artificielle. La mthode a t invente pour acclrer des recherches de
monde et son invariant. Certains auteurs incluent ltat du monde dans linvariant. positions joues dans le jeu de dames [Samuels 19591.
Les deux techniques sont quivalentes.
Supposons que nous voulons crker un annuaire tlphonique au fur et mesure
2.4.1. Un apart! sur les preuves de programmes de larrive de numeros connus, sans faim de tri chaque arrive. Cest ce que lon fait
habituellement dans un carnet dadresses. Dans un tel carnet, pour viter davoir
Les techniques rsumes ci-dessus reprennent des notions manant des travaux examiner tous les noms de personnes, on les divise en 26 classes, en fonction de la
sur la preuve de programmes. Le but est dimprgner les cerveaux des tudiants de premire lettre du nom. Dans le carnet, on commence une nouvelle page pour chaque
m&nismes mentaux allant dans cette direction, sans passer a une approche trop lettre. Les recherches vont plus vite parce que les comparaisons ne sont faites quavec
rigoureuse pour tre soutenue dans la pratique. On doit savoir pourquoi le les noms ayant la mme premire lettre. La premire lettre sert ici de clk (key).
programme marche, sans avoir explicit tout le dveloppement mathmatique. Une clC est une fonction des caractres constituant le mot qui sert diviser
lensemble de mots possibles dans des classes. Si les noms Ctaient distribus de
Pour le puriste, ou le mathmaticien, cette approche nest pas satisfaisante. Il manire gale entre les classes, on divise le nombre de comparaisons par le nombre
serait normal - dans leur monde idal - que tout programme soit accompagn dune de classes. Pour un carnet, on ne regarde quun nom sur 26. Notons que ce rendement
preuve formelle. Ce sont les impratifs conomiques qui font que le monde nest pas nest pas atteint en pratique, parce que, par exemple, les pages K, X, Y, . . .
idal, surtout en acceptant les capacits et les motivations des programmeurs. 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 quelques Dans ce tableau, les 26 premires cases sont r&ervCes pour le premier nom
changements en raison des caractristiques des ordinateurs. En particulier, un carnet reu de chaque classe (en supposant que la cl est la premikre lettre). La colonne de
comporte beaucoup de lignes vides sur les pages moins remplies. Nous dcrivons droite contient lindex de lentrt5e contenant le prochain nom de mme cl. Un
deux versions de lalgorithme dadressage dispersk, une premihre avec un nombre de successeur (suivant) dindex -1 indique que le nom dans cette entre est le dernier
~16s plus petit que la taille de la mmoire disponible, et une deuxime o le nombre rencontr dans sa classe (il na pas de successeur). Une case vide a galement -1
de cl& est le mme que le nombre de cases disponibles. comme successeur. Les noms comportent 8 caractres, tant compltks par des
espaces. Une case vide comporte 8 espaces. La figure montre ltat de la table aprs
la lecture des noms suivants :
2.51. Algorithme avec chanage
X, DUPONT, TOTO, Y, DURAND, TINTIN, DUPOND.
Dans cet algorithme, le nombre de cl& est plus petit que le nombre de cases
disponibles en mmoire. Considrons le carnet, o il y a 26 cls. On cre un tableau A la rception dun nom, on calcule sa cl i, ici la premire lettre. Diffrents
du type dond dans la figure 2.2. cas se pdsentent :
- Le nom est la premier occurrence dun nom avec cette cl. Alors, la case
dindex i est vide. Le nom sinsre a cette place et le processus est termin.
Index Nom Suivant - Un nom de cl i a dj t rencontr. On compare le nouveau nom avec celui
1 -1 dindex i dans la table. Si les deux sont identiques, le nom est trouv et le processus
2 -1 se termine.
3 -1 - Si les deux noms sont diffrents, il faut examiner les successeurs ventuels
4 DUPONT 27
-1 comportant la mme cl. Un successeur de valeur - 1 indique que la liste est termine.
5
6 -1 On ajoute le nouveau nom la premire place disponible et le processus est termin.
7 -1 - Si le successeur existe, son index est donn dans la colonne correspondante.
8 -1 Oncomparelenouveaunomavecle successeur,enseramenantaucaspr&&nt.
9 -1
10 -1
11 1 Cela donne lalgorithme du programme 2.6, page ci-aprs, appel larrive de
12 1 chaque occurrence dun nom.
13
14 -1 A la fin de cet algorithme, la variable adresse contient lindex du nom dans la
15 1
16 -1 tabIe. La variable pl indique la premire case de dbordement libre dans la table (avec
17 1 la valeur de 27 au dpart de lalgorithme). Lalgorithme ne traite pas le problme dun
18 dbordement ventuel du tableau.
19 1
TOT0 28
fi 1
22 1
23 -1
CM X -1
Y -1
fi -1
27 DURAND 29
28 TINTIN -1
29 DUPOND -1
..

Figure 2.2. Table pour ladressage dispers avec chanage

38 39
hGORITHMIQUE ET PROGRAMMMION

DONNEES cl: PROC(chane) -> entier; Index Nom


nom: chane(8); 1
cars: TAB [l ..taille] DE chane(8); 2
SU~C: TAB [l ..taille] DE entier; 3
DEBUT VAR i, adresse: entier; 4 DUPONT
trouv: bool; 5 DURAND
pl: entier INIT 27; 6 DUPOND
i:=cl(nom); 7
S I carqJ= 8
ALORS cars[i]:=nom; % complt par des espaces % 9
adresse:=i; trouv:=VRAI 10
SINON trouv:=FAUX; 11
TANTQUE NON trouv 12
FAIRE SI nom = cars[ij 13
ALORS adresse:=i; trouv:=VRAI 14
SINON SI SUC~[~ = -1 15
ALORS cars[pl]:=nom; % avec des espaces % 16
succ[i]:=pl; succ[pl]:= - 1; adresse:=pl; 17
trouvb:=VRAI; pl:=pl+l 18
SINON i:=succ[i] 19
FINSI 20 TOT0
FINSI 21 TINTIN
FAIT 22
FINSI 23
FIN 24 X
25 Y
Programme 2.6. Adressage dispers 26

Figure 2.3. Table sans zone de dbordement


2.5.2. Autant de cls que de cases

Ltablissement dun chanage entre les diffrents noms dune mme cl gaspille Cette figure reprend la situation de la figure 2.2. On note que les noms
de la mmoire. Pour viter cette dpense, on peut choisir une fonction qui donne supplmentaires commenant par D ont pris les places des noms commenant par E
autant de cls que de cases dans le tableau. En restant avec notre cl (peu raliste) de et F. Que se passe-t-il alors si lon rencontre le nom ESSAI ? On comparera ESSAI
la premibre lettre, on peut refaire la table de la figure 2.2 pour obtenir celle de la avec DURAND (case 5), puis avec DUPOND (case 6), avant de dcouvrir que la case
figure 2.3. 7 est vide. ESSAI rentrera dans la case 7. La cl sert tablir un point de dpart des
recherches, donnant ainsi lalgorithme du programme 2.7.

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

DONNEES cl: PROC(chane) -> entier; garde ses qualits jusquau remplissage du tableau, au prix dune occupation de
nom: chane(8); mmoire suprieure.
tab: TAB [ 1 ..taille] DE chane(8);
DEBUT VAR i, adresse: entier; Rappelons que les deux algorithmes ncessitent une fonction qui distribuent
trouv: bool; bien les noms parmi les cls. Si cette distribution est mauvaise, les deux
i:=cl(nom); trouv:=FAUX; algorithmes se rapprochent de lalgorithme de recherche linaire.
TANTQUE NON trouv
FAIRE SI tab[fl = % Case vide % Notons finalement que les algorithmes dadressage dispers ne diminuent pas la
ALORS trouv:=VRAI; tab[i]:=nom complexit thorique des recherches par rapport celle des recherches linaires.
SINON SI tab[i]=nom Lamlioration de cette mthode rside dans la diminution de la constante dans le
ALORS trouv:=VRAI formule. Toute la famille est dordre o(n) pour la recherche dun nom.
SINON SI i=taille % Dernire case du tableau %
ALORS i:=l % Recommencer en haut %
SINON i:=i+l 2.6. Exercices
FINSI;
SI i=cl(nom) ALORS table pleine FINSI 1. Avant de passer au chapitre qui donne la solution, chercher lamlioration du
FINSI programme de recherche dun mode de vecteur. Ce nouveau programme est plus court
FINSI et plus efficace que lancien. En particulier, il comporte une variable de moins et un
FAIT test (SI ALORS . . . ) de moins.
FIN
2. Considrons une nouvelle version du programme de dichotomie, crit dans le style
Programme 2.7. Adressage dispers, version 2 sans boolens :

DEBUT VAR bas, haut, centre: entier;


La table doit tre circulaire (on recommence regarder en haut si lon arrive B la bas:=1 ; haut:=n; centre:=entier((n+l)/2);
fin). Si la table est pleine, la recherche dun nouveau nom fait tout le tour du TANTQUE haut>bas ET t[centre]+objet
tableau. Sauf si la table est pleine et le nom est absent, la fin du programme, i FAIRE SI t[centre]cobjet
contient lindex du nom dans le tableau. ALORS bas:=centre
SINON haut:=centre
FINSI;
2.5.3. Choix de cl et efficacit centre:=entier((haut+bas)/2)
FAIT;
Jusqualors, nous avons utilis comme cl la premire lettre du nom. Cette cl SI t[centre]=objet
nest pas la meilleure dans la plupart des cas. Le choix de la bonne cl dpend des ALORS . . . % cest trouv %
caractristiques des noms que lon va rencontrer. Dans les compilateurs, on utilise SINON . . . % absent %
souvent comme cl la somme des reprsentations internes des caractres (code ASCII FINSI
ou EBCDIC) modulo la taille de la table. La taille choisie est habituellement une FIN
puissance de deux afin de calculer le modulus par dcalage sur les bits. Ce choix est
assez bon pour les identificateurs dans des programmes. Il permet dutiliser le Cette version, qui est souvent propose par des lbves, contient un pige.
deuxi&me algorithme, sans chanage. Lequel ? Comme mise sur la voie, on considrera le problkme de la terminaison de la
boucle.
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

42 43
&GORlTHMIQUEJTPROGR4MMPUION

3. Mise en uvre dans lordinateur des algorithmes dadressage disperse. On prendra


des textes de programmes afin de disposer de suites de noms (identificateurs). En
prenant des programmes de grande taille, on peut mesurer lefficacit des diffrents
algorithmes de recherche dobjets (linaire, dichotomie, adressage dispers) en
dressant des graphiques du temps dexcution contre le nombre de noms lus. On
examinera aussi linfluence du choix de la fonction de calcul des cls sur les
algorithmes dadressage dispers. Chapitre 3

Les tris

Ce nest pas la premire fois quun livre sur lalgorithmique et la


programmation aborde le sujet des tris (sorting), loin de l. Mais le sujet est
essentiel - on ne peut pas sappeler informaticien sans avoir quelques connaissances
des algorithmes de base. En plus, la matire est un excellent terrain dentranement.
Cest donc sans honte que nous abordons ce chapitre, mme si dillustres
pr&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, des
chanes de caractres, . . . Il suffit quil existe une relation dordre entre chaque paire
dlements, cest--dire que, si a et b sont des lments, une et une seule des relations
suivantes est vraie :

ad3 a=b aA

Les axiomes habituels sont vrifiCs :

acb <=> bsa


(a<b ET b<c) => ad
a=b <=> b=a

On peut galement dcrter que les lments du vecteur sont tous diffrents,
vitant ainsi de considrer 1Cgalit. Cette restriction napporte pas grand-chose pour
la programmation.

44
itLGORITHMIQUE ET PROGRAhhWIlON fkGORITlIMIQUEETPROGR4hfMATION

3.1. Recherche du plus petit lment MONDE k: entier, lindex du dernier lment considr6 dans la
recherche du plus petit;
Un premier algorithme, que nous ne recommandons pas pour des applications min: entier, t[min] est le plus petit lment en t[i..k];
pratiques, consiste en la recherche du plus petit lment restant. Ainsi, au premier k:=i; min:=i;
tour, on recherche t[min], le plus petit lment en t[l..n]. 11 devient t[l] dans le TANTQUE k<n
vecteur tri. Le plus simple est dchanger t[ l] avec t[min], ce dernier arrivant ainsi FAIRE k:=k+l ;
sa place dfinitive. Le probl8me en n est rduit un problme en n-l, car il reste SI t[k]<t[min]
trier le vecteur t[2..n]. Au deuxibme tour on recherche le plus petit lment en t[2..n] ALORS min:=k
pour lchanger avec t[2], et ainsi de suite. On aurait pu prendre llment le plus FINSI
grand, en lchangeant avec t[n] . . . FAIT
change(t[i],t[min])
Le programme 3.1 montre un schma dalgorithme appliqu a un vecteur
dentiers : Programme 3.2. Boucle interne

DONNEES n: entier; Cette boucle ne ncessite pas dexplication. Notons nanmoins que le
t: TABLEAU [l ..n] DE entier; programme accepte lgalit. Si le plus petit lment existe en plusieurs
PRECOND n>O; exemplaires, on prend le premier arriv, le restant (ou les restants) tant considr(s)
DEBUT MONDE i: entier, t[l ..i] est tri; au tour suivant. Le programme 3.3, complet, utilise les mondes dcrits
i:=O; pk%demment.
TANTQUE i < n-l
FAIRE i:=i+l ;
trouver j tel que t[j] est le plus petit lment dans t[i..n] DONNEES n: entier;
changer(t[i], t[i]) t: TABLEAU [l ..n] DE entier;
FAIT PRECOND n>O;
FIN DEBUT VAR i, k, min, temp: entier;
POSTCOND t[l ..n] est tri, cd i,j (O<i<j<n => t[i]<t[i]) i:=O;
TANTQUE icn-1
Programme 3.1. Scht%na du tri par recherche du plus petit lment FAIRE i:=i+l ; k:=i; min:=i;
TANTQUE k<n
FAIRE k:=k+l ;
La seule instruction ncessitant une explication est la condition aprks SI t[k]<t[min]
TANTQUE. 11 est ncessaire de trier n-l lments, le dernier, t[n], tant ALORS min:=k
ncessairement sa place la fin (tous les lments qui le prcdent sont plus petits FINSI
que lui par construction, sauf cas dlments gaux). FAIT;
temp:=t[i]; t[i]:=t[min]; t[min]:=temp
Reste coder le contenu de la boucle dans ce texte. Ce sera une nouvelle FAIT
boucle (programme 3.2). FIN
POSTCOND t[l ..n] est tri

Programme 3.3. Programme complet

46 47
&OORITHMIQUE FI PROGRAMh4ATION ,kGORlTHMIQUE ET PROGRAhiMATION

Lchange a t programm de maniere vidente, avec une variable temporaire. DONNEES n: entier;
La complexit de cet algorithme est simple calculer. Au premier tour, n-l t: TABLEAU [l ..n] DE entier;
comparaisons sont ncessaires pour trouver le plus petit lment en t(l..n). Au PRECOND n>O;
deuxieme tour il en faut n-2, puis n-3, . . . Le nombre de comparaisons est donc : DEBUT VAR i, j, temp: entier;
arrt: bool;
1 + 2 + 3 + . . . + (n-l) = n*(n-1)/2 MONDE i: t[l ..i] est tri;
i:=l ;
Comme les autres oprations (il y a n-l changes) se font moins souvent, TANTQUE i<n
lalgorithme est dordre o(n2). Le nombre de comparaisons est indpendant du FAIRE i:=i+l ;
contenu du vecteur. MONDE j est la position du trou,
temp = t[i],
arrt E t[j-l]ltemp;
3.2. IX par insertion temp:=t[i]; j:=i; arrt:= t[j-l]<temp;
TANTQUE j>l ET NON arrt
Dans le programme du paragraphe prcdent, aprs i tours, le vecteur t[l..i] est FAIRE SI tb-l]>temp
tri, mais en plus, ses i premiers lments sont dj leur place, cest--dire : ALORS t[j]:=t-11; j:=j-1
SINON arrt:=VRAl
O<j<k<i => tfj]<t[k] FINSI
ick<n => t[i]lt[k] FAIT;
t]:=temp
La premiere assertion dit que les i premiers lments sont tris, la deuxime dit FAIT
que les lments apres t[i] sont plus grands ou gaux ceux dj tris, t[i] tant le FIN
plus grand des lments tris. POSTCOND t[l ..n] est tri

Programme 3.4. Tri par insertion


Une nouvelle version du tri ne ncessite pas cette deuxime condition. Aprs i
tours, les i premiers lments sont tris. On considre t[i+l]. Cet lment va &e
insr sa place en t[l..i+l], ce qui implique, en gnral, la recopie un cran Au tour i, ce programme fait remonter t[i] sa place, ou plutt il fait
plus loin de chaque lment de t[l..i] qui est plus grand que t[i+l] (voir le descendre les lments de t[l..i-1] qui sont plus grands que t[i], afin de lui laisser sa
programme 3.4). place. On a donc lide du trou. On enlve llment considrer du vecteur, en le
mettant dans la variable temporaire temp. Cela laisse un trou. On regarde le
predcesseur du trou. Sil est plus grand que temp, il descend, cest--dire le trou
monte. Si le predcesseur nest pas plus grand, ou sil ny a pas de prdcesseur
(llment considr est le plus petit vu jusquici), la recherche sarrte, llment en
temp trouvant sa place dans le trou.

Pour confirmer la validit des indices, notons que la boucle externe impose
icn. Apres i:=i+l, on a iln. Dans la boucle interne, j>l (condition) et jli
(initialisation, avec j:=j-1 dans la boucle). On dduit :

lcjln, donc t[i] et t[j-l] existent.

Les boucles se terminent, car i et j avancent, lun vers n (i:=i+l), lautre vers 1
(i:=j-1).

48 49
hOORlTHMIQlJE ET PROGRAMMtUlON

La preuve de ce programme est faite en dmontrant que le nouvel tlment On est toujours en ordre O(n*), mais cet algorithme est moins mauvais que le
retrouve bien sa place, ce qui revient a demontrer qu la fm de la boucle interne on prtktdent (sans pour autant tre recommande dans le cas gn&al). En effet, si le .
a: tableau est deja tri ou presque, le premier algorithme fait le mme nombre de
comparaisons que dans le cas dune distribution alatoire, tandis que dans le second,
O<kcj => t[k]stemp on constate n fois de suite quaucun mouvement nest ncessaire, descendant ainsi
j<&i => temp<t[k] lordre o(n). Cet algorithme est donc bon pour des vecteurs que lon sait dj tries, ou
presque.
Comme les lments Ctaient dj ordonns, et comme le nouveau est
compatible avec lordonnancement par les deux assertions ci-dessus, linvariant de la
boucle externe (t[ l..i] est tri) reste vrai. 3.3. hi par bulles

On pourrait supprimer la variable boolenne arrt en utilisant loprateur Bien connu aussi, ce tri a une mauvaise rputation du point de vue de
ETPUIS (programme 3.5). lefficacid, 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 que
DONNEES n: entier; certains enseignants montrent la version du programme 3.6, qui est effectivement
t: TABLEAU [1 ..n] DE entier; partkuli&rement inefficace.
PRECOND n>O;
DEBUT VAR i, j, temp: entier;
MONDE i: t[l ..i] est tri; DONNEES n: entier;
i:=l ; t: TABLEAU [l ..n] DE entier;
TANTQUE i<n PRECOND n>O;
FAIRE i:=i+l ; DEBUT VAR fin, i: entier;
MONDE j est la position du trou, MONDE fin: t[l ..fin] reste trier,
temp:=t[i]; j:=i; fin:=n;
TANTQUE j>l ETPUIS tjj-l]>temp TANTQUE fin>1
FAIRE tjj]:=tjj-11; j:=j-1 FAIRE MONDE i: on va comparer t[i] et t[i+l];
FAIT; i:=l ;
tjj]:=temp TANTQUE icfin
FAIT FAIRE ASSERTION O<j<i => tjj]<t[i];
FIN SI t[i+l]ct[i]
POSTCOND t[ 1 ..n] est tri ALORS change(t[i],t[i+l])
FINSI;
Programme 3.5. Version avec ETPUIS i:=i+l
FAIT;
ASSERTION O<j<fin => tjj]<t[fin];
On peut aussi faire la mme chose avec une bute (voir exercice la fin du fin:=fin-1
chapitre). La complexit de cet algorithme dpend du nombre dlments qui FAIT
descendent B chaque tour. Avec une distribution alatoire, la place de llment FIN
considere va tre en moyenne au milieu des autres. Ainsi, le nombre dlments POSTCOND t[l ..n] est tri.
dplacer est :
Programme 3.6. Tri par bullesprimitif
(1 + 2 + 3 + . . . + n-l)/2 = n*(n-1)/4

50 51
&GORITHMIQIJE ET PRoGRAMhUTION iiLL3ORlTHMIQUE ET PROGRAMMATION

Cette version de lalgorithme est dmontrable partir des assertions donnes DONNEES n: entier,
dans le texte. A la fin de chaque tour, 18ment le plus lourd est passe la fin de la t: TABLEAU [l ..n] DE entier;
zone considree. Cest une version moins efficace de lalgorithme du $3.1, en PRECOND n>O;
trouvant le plus grand lment au lieu du plus petit. DEBUT VAR bas, haut, i: entier;
MONDE bas, haut: t[bas..haut] reste trier;
Il y a deux faons damCliorer cette version : INVARIANT t[l ..bas], t[haut..n] sont ordonns,
t[l ..bas-11, t[haut+l ..n] sont placs;
- Considrons le vecteur suivant : bas:=1 ; haut:=n;
TANTQUE baschaut
(23456789101) FAIRE MONDE i: t[i..haut] comparer deux deux,
der: dernier objet boug;
A chaque passage dans le vecteur, le seul change se fera entre la valeur 1 et son INVARIANT t[der..i] est ordonn;
predcesseur immdiat. Nous proposons de faire des passages alternativement de i:=bas; der:=i;
gauche droite, puis de droite gauche. Dans ce cas, le deuxieme passage ramnerait TANTQUE khaut
le 1 au dbut du vecteur, qui serait donc trie aprs deux passages. FAIRE SI t[i+l]<t[i]
ALORS echange(t[i],t[i+l]); der:=i
- Mais cela ne suffit pas, car lalgorithme ne se rend pas compte que le vecteur FINSI;
est trie. Considrons le vecteur suivant : i:=i+l
FAIT;
(21345678910) MONDE i: t[bas..i] comparer,
der: dernier objet boug;
On voit quil sera trie la fin du premier passage. Ce quil faut ajouter au programme INVARIANT t[i..der] est ordonn;
est la ralisation du fait que, tant donn quaucun change na eu lieu, pendant ce haut:=der; i:=haut;
premier passage, a partir de la valeur 3, t[2..10] est tri et les ellments sont dj a TANTQUE basci
leurs places dfinitives. La preuve de cette affirmation vient du fait que le test FAIRE SI t[i]+l]
dmontre que ces lements sont ordonns deux deux. Lordonnancement tant ALORS change(t[i],t[i-11); der:=i
transitif (aSb ET bic => tic), ils sont donc tous ordonns. En plus, lassertion FINSI;
montre que le dernier objet prendre sa place (ici t[2]) est le plus grand de tous ceux i:&l
vu jusqualors. Il en rsulte que lon peut rkduire lespace trier plus rapidement. FAIT;
bas:=der
Ces amliorations, qui prennent en compte le travail accompli en route, FAIT
cest--dire les changes intermdiaires, donnent lieu lalgorithme du programme FIN
3.7, POSTCOND t[l..nJ est tri

Programme 3.7. Tripar bulles normal

Dans ce texte, ordonne veut dire que le vecteur indiqu est trie, cest--dire que
ses lements sont dans lordre, mais quils pourront changer de place dans le vecteur
final en fonction dautres lments a insrer. Un vecteur place est non seulement
ordonn, mais ces lments occupent les places quils auront dans le vecteur final.
Ainsi :

52 53
fiLWRI-lHUIQUEETPROORAMMATION

yi..jj est ordonn <=> (i&&j => t[k]4[1]) dans cet ouvrage. Le principe est de partitionner les lments en deux classes en les
yi..jJ est plac6 <=> (t[i..j] est ordonn ET comparant avec un lment dit pivot. Tous les Blments plus petits que le pivot vont
(O-ck.4, i&j => t[k]5t[l]) ET se trouver sa gauche, les autres se trouvant sa droite. Considrons le programme
(i%j, jemsn => t[l]n[m])) 3.8, qui met en uvre cette classification par rapport au pivot t[ 11.

Les invariants permettent la dmonstration directe de la justesse du DONNEES n: entier,


programme. t: TABLEAU [l ..n] DE entier;
On peut comparer la complexit de cet algorithme avec celle de lalgorithme PRECOND n>O;
par insertion. Les deux mnent un mme nombre dchanges, que lon calcule de la DEBUT VAR pivot, camp, bas, haut: entier;
mani& suivante : en prenant les l6ments deux deux, le nombre dkchanges est le MONDE pivot: base de la comparaison,
nombre de fois o une paire dlments nest pas ordonne. Mais le nombre de camp: valeur comparer au pivot,
comparaisons nest pas le mme pour les deux algorithmes. Malheureusement, ni bas: index du trou gauche,
lun, ni lautre nest le meilleur dans tous les cas. Les deux algorithmes sont du haut: index du trou droit;
mme ordre de complexiti, et ils partagent les proprits dtre bons dans le cas dun pivot:=t[l]; comp:=t[n]; bas:=l; haut:=n;
TANTQUE baschaut
vecteur bien conditionn et dtre mauvais pour un vecteur mal conditionn.
FAIRE SI comp<pivot
ALORS t[bas]:=comp; bas:=bas+l ; comp:=t[bas]
3.4. Diviser pour rgner SINON t[haut]:=comp; haut:=haut-1 ; comp:=t[haut]
Les trois algorithmes de tri tudis jusquici sont tous dune complexit dordre FINSI
FAIT;
o(n2). Dans chaque cas, un passage du vecteur rduit un probEme en n un
probkme en (n-l). Comme pour la dichotomie par rapport la recherche linaire, il t[bas]:=pivot
est possible de faire mieux en tiuisant un probEme en n deux problkmes en nf2. FIN
Le terme gnt%alement employ dans ces cas est celui de diviser pour rgner. On POSTCOND Okbascjln => t[i]ct[bas]<tu], bas=haut, t[bas]=pivot.
divise le vecteur en deux moitis, on trie chaque moiti4 et on remet les deux moitis Programme 3.8. Partition dun vecteur
ensemble.
On crde deux trous dans le vecteur, en extrayant t[l], le pivot, et t[n], un
Il existe deux groupes dalgorithmes dans cette catgorie : les tris par partition
lment de comparaison. Si IClment de comparaison est plus petit que le pivot, il
et les tris par fusion. Le tri par partition permet de travailler sur place, cest--dire
est plac dans le trou gauche, sinon dans le trou droit. Un nouveau trou est cr@
en gardant les t%ments dans le vecteur en vitant de copier le vecteur entier dans un
ct de celui que lon vient de remplir, en extrayant comme lCment de comparaison
nouvel emplacement dans la mmoire. Le hi par fusion, utilis du temps hroque
des programmes de gestion sur support de bandes magnCtiques, ncessite la cr6ation le voisin du trou rempli. Le processus continue jusqua la rencontre des deux trous.
dun deuxime vecteur dans la mmoire (ventuellement secondaire), vecteur qui On inskre le pivot dans le trou (unique) qui rsulte de cette rencontre, sachant que
reoit les 616ments dans le nouvel ordre. tous les lments plus petits que le pivot sont 21 sa gauche, les autres tant & sa
droite. Notons que cette formulation permet lexistence de valeurs Cgales, une valeur
Pour des raisons videntes, nous accordons plus dimportance, dans cet gale au pivot tant mise a sa droite.
ouvrage, au tri par partition. Le tri par fusion est souvent pris comme exemple dans
hz cours de programmation avec le langage PROLOG. La division du vecteur en deux parties a rduit le probkme de hi en deux sous-
problmes. Il nous reste frier les l&ments a gauche du pivot, puis ceux sa droite,
le pivot Ctant a sa place (il ne bougera plus). Lalgorithme est applique
3.41. Diviser pour rgner avec partition rkursivement, cest--dire que chaque moiti du tableau est de nouveau divise en
deux par comparaison avec un pivot lui, et ainsi de suite. Apr&s avoir divis par
Dans le cas dune distribution alatoire de valeurs, surtout si n est grand, deux un certain nombre de fois, il reste au plus un seul l6ment dans chaque classe
lalgorithme de diviser pour rgner avec partition est le meilleur de ceux prsent& (certaines sont vides), qui est automatiquement sa place sil existe.

54 55
hOORITHMIQUE ET PROGRA~ION hGORITHhfIQUE ET PROGRAMMATION

Pour mener bien cette opration r&rsive, nous avons besoin de paramtrer M(l, n)
le programme ci-dessus, qui va devenir une procdure dans le programme 3.9.
La spcification dune procdure (SPEC) prend la place de la clause DONNEES
dun programme. On y trouve la dfinition du jeu de parambtres, avec une indication
PROC M(i, j); de ce que la procdure doit faire. Cette indication est la post-condition de la
GLOBAL n: entier, t: TABLEAU [l ..n] DE entier; procdure-
SPEC i, j: entier;
trier t[i..j] par la mthode de diviser pour rgner; Lalgorithme a une complexit thorique dordre o(n*log2(n)), comme le
PRECOND 04,jln; montre le raisonnement suivant :
DEBUT VAR pivot, camp, bas, haut: entier;
SI j>i Le cas parfait de cet algorithme arrive quand n=2i-l et le pivot divise toujours la
ALORS pivot:=t[i]; comp:=tjj]; bas:+ haut:=j; zone en deux parties de longueurs gales. A la fin du premier tour, on a un pivot
TANTQUE bas-zhaut place et deux zones de taille (2-l-1)/2 = 2- -1. On voit que le nombre de
FAIRE SI compepivot comparaisons dans chaque zone est sa taille moins 1 (le pivot). En remultipliant par
ALORS t[bas]:=comp; bas:=bas+l; comp:=t[bas] le nombre de zones, on dduit que le nombre total de comparaisons par tour est
SINON t[haut]:=comp; haut:=haut-1 ; comp:=t[haut] successivement :
FINSI
FAIT; n-l, n-3, n-7, n-15, . . .
t[bas]:=pivot; M(i, bas-l); tri(bas+l, j)
FINSI Le nombre de tours est i, cest--dire log2(n+1). On obtient, pour des donnes
FINPROC bien conditionnes, la complexit thorique annonce.

Programme 3.9. Insertion dans une procdure rcursive Ce calcul suppose que le pivot divise chaque fois son monde en deux parties de
tailles comparables. Considrons maintenant un vecteur dj ordonne. Comme nous
prenons le premier lment pour pivot, un tour va reduire le problme en n dans un
Le terme GLOBAL indique que la variable n est dclare lextrieur de la
problme en 0 et un autre en n-l. Le processus est de nouveau dordre o(n2). Ce
procdure (dans le programme englobant). Ainsi, la valeur de n est la mme pour rt%ultat, surprenant, montre que diviser pour rgner, tout en tant le meilleur
chaque appel de la procdure, tandis quil existe un nouvel exemplaire de i et de j
algorithme dans le cas dune distribution alatoire avec une grande valeur de n, est le
pour chaque appel (chacun possde le sien). Le tableau t existe galement en un seul
plus mauvais pour un vecteur dj tri (ou presque tri). On peut toujours prendre le
exemplaire, manipule par chacun des appels de la procdure.
pivot au centre du vecteur pour amliorer quelque peu lalgorithme dans ce cas.
Cette procdure mne a bien le tri complet. Elle comporte le programme crit
precdemment, avec les changements ncessaires pour trier t[i..j] au lieu de t[l..n].
3.42. Solution sans appel rbcursif
Une fois que la division en deux zones a eu lieu, il reste les trier, lune apres
lautre, par deux nouveaux appels de tri avec des pammtres appropris : Le dernier programme ci-dessus comporte deux appels rcursifs de la proc&lure.
Si, pour une raison quelconque, on voulait enlever la r&ursivit, on utiliserait une
M(i, bas-l) ET tti(bas+l , j) pile (stack ou LIFO - Last In, First Out). Cette dernire sert mmoriser,
pendant le tri dune zone, les limites des zones restant trier. Ainsi, on trie t[i..j],
La procdure teste par i<j quil y a au moins deux lments a trier. Ce test avec, au dbut :
confiie que les appels rcursifs ne peuvent pas constituer un ensemble infini, car le
nombre dlments a trier diminue avec chaque appel. Evidemment, on trie le vecteur i=l ET j=n
complet par un appel de la procdure de la forme suivante : Apres un tour, avec p lindex de la position finale du pivot, on a la situation
suivante :

56 57
&OORIIHMIQUE ET PROGRAMMXION fiLGO-QUEmPROGRAMMPIIION

t[l ..p-1] est trier On reviendra sur les piles au cours du chapitre 4, en les utilisant souvent par la
t[p] est place suite.
t[p+l ..n] est trier.
Les bornes 1 et p-l sont mises sur la pile et le prochain tour redmarre avec : 3.4.3. Quelques commentaires sur la rcursivit
i-p+1 ET j = n
Dans le programme de recherche linaire, ou dans les tris primitifs, la base des
Aprs chaque partition, une paire de bornes est mise sur la pile, lautre tant algorithmes a t la rduction dun problbme en n vers un problme en (n- 1). Cette
traite de suite. Aprs un certain nombre de partitions, la taille de la zone traiter est tiduction est triviale a mettre en uvre; chaque tour dune boucle, on excute
1 (ou 0), cest--dire quelle est termine. Dans ce cas, on recommence avec la laffectation :
premikre paire de bornes sur la pile, et ainsi de suite. Cette technique donne lieu au
programme 3.10. n:=n-1
DONNEES n: entier,
et le tour est jou.
t: TABLEAU [ 1 ..n] DE entier,
PRECOND O<i,j% En passant la recherche dichotomique, il sagit de rduire un problme en n
DEBUT VAR i, j, pivot, camp, bas, haut, pl: entier, vers un probl8me en n/2. On cherche un objet dans le domaine dindices [g..d]. Par
fini: bool, rapport un ClCment mdiane dindex c on rduit le domaine soit [g..c], soit
pile: TABLEAU [l ..taille] DE entier; [c..d]. La mise en uvre est galement triviale, sagissant de lune des deux
i:=l ; j:=n; fini:=FAUX; pl:=l ; affectations suivantes :
MONDE fini: t[l ..n] est tri6
pl: index de la premire case libre dans la pile d:=c OU g:=c
t[i..j] est trier
les zones indiques dans la pile sont trier Notons nanmoins que ces utilisations de laffectation nexistent que pour des
TANTQUE NON fini raisons de mise en uvre dans un ordinateur. Le raisonnement sous-jacent est de type
FAIRE MONDE comme dhabitude rkurrent. Par exemple, pour la recherche linaire, on aurait pu crire la fonction
TANTQUE j>i
suivante :
FAIRE pivot:=t[i]; comp:=t[]; bas:=i; haut:=j;
TANTQUE basehaut \
chercher(objet, t[l ..n]):
FAIRE SI compcpivot SI t[n] = objet
ALORS t[bas]:=comp; bas:=bas+l ; comp:=t[bas] ALORS trouve
SINON t[haut]:=comp; haut:=haut-1; comp:=t[haut] SINON chercher(objet, t[l ..n-11)
FINSI FINSI
FAIT;
t[bas]:=pivot; pile[pl]:=i; pile[pl+l]:=bas-1 ; PI:=PI+~; i:=bas+l Cette criture fonctionnelle peut sexprimer par lutilisation dune procdure
FAIT; rkcursive ou par une boucle avec affectation. Toute boucle peut se rcrire en forme
fini:= Pl=i;
de procdure rikursive de manikre directe.
SI NON fini
ALORS PI:=PI-2; i:=pile[pl]; j:=pile[pl+l] Considrons maintenant le tri par diviser pour rkgner avec partition. Ici, on
FINSI r6duit un problbme en n vers deux problmes en n/2. Une forme rduite de la
FAIT
fonction de tri est la suivante :
FIN
Programme 3.10. Version avec pile

58 59
kCiORITHMIQUE ET PROGRAMMMION hOORKHMIQUE JiT PROGRAMMMION

tri(t[g..d]): contient, a chaque instant, les paires dindices correspondant aux appels laisss en
SI d>g suspens. Notons que le programme du paragraphe pr6cdent trie la partie droite du
ALORS partition(t[g..d], c); tri(t[g..c-11); tri(t[c+l ..d]) vecteur, en mettant les indices de la partie gauche en suspens sur la pile. Dans la
FINSI figure 3.1, lordre est invers. En fait, lordre est indiffrent; a la rigueur, on pourrait
lancer les deux appels 16cursifs en parallle sur deux processeurs ind6pendants dans le
Une simple affectation ? chaque tour dune boucle ne suffit plus, car, si cadre dun matt5riel multiprocesseur.
laffectation relance le premier des appels de tri rsultant, les param&es du deuxibme
appel doivent tre stocks quelque part afin de revenir dessus la fin du premier Lutilisation dune pile est un moyen gnral pour mettre en uvre la
appel. Notons que chaque appel provoque, , son tour, deux nouveaux appels, jusqu rcursivit. Si la pile est programme explicitement, comme dans le paragraphe
larriv& de vecteurs de longueur 1 (ou 0). prcdent, on y stocke les informations permettant de savoir o lon en est dans la
cascade dappels. On verra dautres exemples dans le chapitre sur la marche arrire.
On peut envisager la cascade dappels dans la forme dun arbre (figure 3.1).
En fait, lors de lutilisation dune procdure rcursive, un compilateur engendre
des instructions qui g&rent une pile. Y sont gardes les valeurs des paramtres de
tri(g..d) lappel en cours et des variables locales chaque niveau dappel. Ce sujet est couvert
avec plus de d&ails dans des cours de compilation tels que [Cunin 19801.

On peut se demander quels sont les schmas rcurrents qui permettent une
traduction facile vers une boucle avec affectation directe de variables. Un problme
tri(g..cl) tri(cl..d) qui se rduit de manire rcurrente en deux sous-problmes, ou plus, ne permet pas
une telle traduction, car il faut toujours garder la trace des appels en suspens. Dans

A
un schma un seul appel, la traduction vers une boucle est directe dans le cas dune
rcursivit terminale. Dans ce cas, aucun calcul ne reste excuter aprs la fin de
lexcution de lappel rcursive, comme dans le cas de la recherche linaire. Le
problbme sera reconsidr dans le chapitre 7, qui traite de la transformation de
tri(g..c2) tri(c2..cl) programmes.

A
tri(g..c3) tri(c3..c2)
3.4.4. Deux pivots

Comme la division dun problbme en deux sous-problmes - chacun de la


moiti du cot du premier - reprt%ente un grand gain defficacit, on peut se
demander si lide de diviser un probl&me en trois reprsente encore une amlioration.
Figure 3.1. Appels aprspartition
Cest purement au titre dune spculation intellectuelle que la question se pose pour
le tri par diviser pour rgner avec partition. Lauteur ne connat pas de publication ni
Cette figure montre les appels en cours aprs trois partitions, les indices ayant dapplication de I?d&.
t6 simplifis pour allger le dessin (suppression des +l et -1). Apr&s chaque
partition, on reprend la branche gauche, en laissant la branche droite en suspens. Le La mise en uvre dun tel algorithme (programme 3.11) ncessite donc deux
successeur gauche est de nouveau partitionn, et ainsi de suite. pivots, 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,
La modlisation par procdure n5cursive est donc une mise en uvre directe et ceux qui sont plus grands que le plus grand des pivots et ceux qui sont entre les
simple de lalgorithme. Par la suite, nous avons montr une mise en uvre avec une deux. On trie par la suite les trois ensembles par trois appels r6cursifs.
pile. La pile a servi se rappeler ce qui reste faire un moment donn. Elle

60 61
Auio-QUE IT PROGRAMMtWION hOORITHMlQUE I?I PROGRAmION

DEBUT DONNEES n: entier; Dans cette figure, Pl est la valeur du plus petit des deux pivots, P2 celle du
t: TAB [1 ..n] DE entier; plus grand. Les lments les plus petits occupent la premire zone dans le vecteur,
PROC tri(min, max: entier): les plus grands occupant la demi?% (quatrime) zone. Les Mments ayant des valeurs
VAR tg, td, pl, p2, tl, t2, t3: entier; \ interm&liaires occupent la deuxime zone, laissant la troisime pour les lments
SI max>min nayant pas encore t consid&.
ALORS pl :=t[min]; t2:=min+l; p2:=t[t2]; tl :=min;
test:=t[max]; t3:=max; Introduire un lment dans la quatribme zone ne pose aucun probl&me; il
TANTQUE t243 pousse le trou droit un cran a gauche, le dernier lment non trait tant pris comme
FAIRE SI tesbt2 lment de comparaison. De mme, on peut introduire un lment a la fin de la
ALORS t[t3]:=test; t3:=t3-1; test:=t[t3] deuxi&me zone, repoussant le trou central un cran droite et en considrant le
SINON SI test.4 premier des lments non traits. Pour introduire un lment dans la premire zone,
ALORS t[tl]:=test; tl :=tl+l; t[t2]:=t[tl] il faut mordre sur la deuxibme. Le premier l6ment de la deuxime zone passe la
SINON t[t2]:=test fin de cette zone, en poussant le trou central. Le premier trou peut ainsi avancer dun
\ FINSI; cran, laissant de la place pour llment insrer. On considre le premier lment
t2:=t2+1; test:=t[t2] non trait, ject par lavance du trou central.
FINSI
FAIT; Cette mthode apporte-t-elle des amliorations ? En thorie, oui; la complexit
t[t l]:=pl ; t[t2]:=p2; est dordre o(n*log3(n)) au lieu de o(n*logz(n)). En pratique, il faut des vecteurs de
tri(min, tg-1); tri(tg+l, td-1); tri(td+l, max) trs grande taille pour sen apercevoir.
FINSI
FINPROC;
tri(1, n) 3.4.5. Tri par fusion
FIN
Le tri par fusion date dune poque o les mmoires centrales taient petites
Programme 3.ll. Diviser pour rgner avec deux pivots par rapport aux fichiers trier, ces derniers tant stocks sur des bandes magntiques.
Le principe est simple : on coupe le fichier en deux moitis, on trie chaque moiti,
puis on fusionne les deux mdiitis tries en intercalant les valeurs de lune et de
La seule difficult dans ce programme rside dans le maniement des trous et les lautre dans le bon ordre. Lopration est rpte rcursivement autant de fois que
ensembles pendant la partition. Il y a trois trous : deux pivots et un lement de ncessaire. Lopration de fusion ncessite une deuxime copie du fichier, ce qui
comparaison. Les trois trous dfinissent quatre zones dans le vecteur : trois double lespace mmoire occup. En pratique, la fusion se faisait avec deux bandes
ensembles B trier et une quatribme zone qui contient les lments en attente de magntiques en entre, chacune avec une moiti trie du vecteur, et une troisime
partition. La figure 3.2 montre la distribution de trous et de zones pendant bande en sortie pour recevoir le tout.
lopration de partition.
La rcursivit ne va pas jusquau bout; on divise le vecteur par deux jusqu ce
que le rt%ultat de la division puisse tenir dans la mmoire principale. On peut ds
lors trier cette zone du vecteur en mmoire avec un algorithme du type dj vu. Tout
lart de la programmation de ce type de situation comportant des bandes magntiques
Pl et[i]<P2 non traits consistait bien organiser les informations sur les bandes afin dviter de coteux
allers et retours pour rechercher le prochain bloc.
Figure 3.2. Vecteur en cours de partition
En ignorant lexistence des bandes magntiques, lalgorithme peut travailler de
la mani&e suivante :
- On divise le vecteur tl autant de fois que ncessaire pour que ls zones soient

62 63
.kGORlTHh4lQUFiETPROGRAMMtUlON fiLGORlWMIQUE ET PROGRAMMAITON

de longueur au plus 1. DONNEES n: entier, t: TAB [l ..n] DE entier;


- On fusionne des zones de longueur 1, par paires, pour crer des zones de DEBUTVAR 1, pl, p2, p3, il, i2, i: entier;
MONDE on fusionne des paires de zones de longueur I en zones de
longueur 2 dans une nouvelle copie t2 du vecteur. longueur 21;
- Les zones de longueur 2 sont fusiondes pour crer des zones de longueur 4, pl est lindex du premier Mment da la premire zone, p2 lindex
de nouveau en tl. du debut de la seconde zone, p3 ds la zone suivante (n+l sil
- On continue de la sorte jusquh la fin du processus. ny en a pas);
i &ments ont 15th recopi& vers le nouvel exemplaire du
vecteur, il est lindex du premier lment non recopi8 da la
Prenons comme exemple un vecteur de 8 lments, tri ?I lenvers. Les tats premire zone, i2 de la deuxime;
successifs de fusion sont les suivants : I:=l;
WNTQUE la-~
t1: (87654321) Vecteur de dpart l FAIRE i:=O; pl :=l;
ANTQUE i<n
t2: (78563412) Fusion dlments crant des paires
FAIRE p2:=pl+l; p3:=min(p2+l, n+l); il :=pl; i2:=p2;
t1: (56781234) Fusion par paires ANTQUE i-+3-1
t2: (12343678) Fusion par groupes de quatre FAIRE i:=i+l;
SI il=p2
Le programme 3.12 montre une mise en uvre correspondante. ALORS t2[i]:=tl[i2]; i2:=i2+1
SINON SI i2=p3 OUALORS tl[il]<tl[i2]
ALORS GZ[i]:=tl[il]; il :=il +l
SINON t2[i]:=tl[i2]; i2:=i2+1
FINSI
FINSI
FAIT;
\
pl :=p3
FAlT;
1:=2*1;
SI ktl
ALORS pl :=l ; i:=O;
7ANTQUE i<n
FAIRE p2:=l+l; p3:=min(p2+1, n+l); il :=pl ; i2:=p2;
TANTQUE icp3-1
FAIRE i:=i+l ;
SI il=p2
ALORS tl[i]:=t[i2]; i2:=i2+1
SINON SI i2=p3 OUALORS t2[il]t2[i2]
ALORS tl[i]:=t2[il]; il:=il+l
SINON tl[i]:=t2[i2]; i2:=i2+1
FINSI
FINSI
FAIT;
pl :=p3
FINSI;
1:=2*1
FAlT
FIN

Programme 3.12. Triparfusion

64 65
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 aux
conclusions suivantes :

- La mthode de recherche du plus petit lment nest jamais bonne. On ne Chapitre 4


Iutilisera pas.

- Pour de grands vecteurs dont les lments sont distribus alatoirement, la


mthode de diviser pour rgner avec partition est la meilleure. Elle est mauvaise dans Des structures de donnes
le cas dun vecteur dej tri, ou presque tri. Pour limiter les dgts dans ce cas, il
vaut mieux prendre le pivot au milieu de la zone, ce qui complique lgerement le
programme (voir exercice).

- Pour des vecteurs presque tris, les deux methodes dinsertion ou par bulles
sont de bonnes candidates, condition dutiliser la version optimise pour la
deuxitme. Lune ou lautre peut tre la meilleure, en fonction des propriets Les langages de programmation classiques permettent lutilisation de variables
particuli&es de lordonnancement approximatif dj existant. simples (entiers, rels, . . .) et de tableaux, voire, ventuellement dautres types de
donnes composes (records, . ..). D ans le dernier exemple du chapitre 3 (tri par
diviser pour rgner), nous avons eu besoin dune structure de donnes particulire, la
3.6. Exercices pile, qui nexiste pas directement dans ces langages. En effet, dans la plupart des
langages de programmation, on ne dispose pas dun type pile.
1. Dans le tri par insertion, lutilisation de ETPUIS permet de supprimer la variable
arrt. Dans un langage sans ETPUIS, comment arriver au mme rsultat par Un certain nombre de structures de donnes de ce type reviennent constamment w
lintroduction dune bute ? dans les programmes. Dans ce chapitre, nous allons dcrire les principales structures,
avec les moyens de les reprsenter dans des langages existants. Avec le
2. Donner une rgle permettant de calculer le nombre de comparaisons ncessaires dveloppement de nouveaux langages, on peut sattendre voir ces objets devenir des
danslecas: types standards. En premier lieu, nous allons considrer les piles, les jles (queue
- dun tri par insertion, ou FIFO - First In, First Out), les arbres (tree), les treillis (lattice) et les
- dun tri par bulles. graphes (graph).

3. Dans la dernire version du tri par diviser pour rgner, on fera la modification 4.1. Les piles
consistant a prendre comme pivot lelment au milieu de la zone trier.
Une pile est un ensemble ordonn dobjets de mme type (entiers, rels, . ..).
4. Un bon exercice au niveau dune classe est de comparer les diffrents tris, mis en Cest comme si lon gardait une pile de livres sur son bureau. On peut poser un
machine par diffrents lves. On mesurera, par lhorloge et en comptant les nouveau livre sur la pile, ou reprendre le livre qui est en haut de la pile. Extraire un
oprations, le cot de lexcution de chaque tri, en essayant une srie de vecteurs livre du milieu est tellement difficile que nous renonons a cet exercice.
diffrents. On variera la distribution dlments (tris, presque tris, alatoire, tris On dispose dun vecteur dont les lments sont du type appropri. Il existe deux
Ienvers , . ..) et la longueur du vecteur. Ltablissement de courbes pour chaque oprations fondamentales : poser un objet (empiler, ou push) et en retirer un
mthode permet den confirmer la complexit thorique. (dpiler, ou pull). Le vecteur sert a stocker les objets poss. Pour savoir combien
l
dobjets sont dans la pile a un moment donn, on utilise un pointeur de niveau. Le
l pointeur 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 pile PROGRAMME DISCUTABLE
dentiers. DONNEES taille: entier; file: TABLEAU [l ..taille] DE entier;
VAR ancien: entier INIT 1; libre: entier INIT 1;
PROCEDURE mettre(x: entier);
DONNEES taille: entier, PRECOND librestaille;
pile: TABLEAU [l ..taille] DE entier; file[libre]:=x; libre:=libre+l
VAR pl: entier INIT 1; FINPROC;
PROCEDURE empiler(x: entier); PROCEDURE enlever(x: entier);
PRECOND pIstaille; PRECOND anciewlibre;
pile[pl]:=x; pl:=pl+l x:=file[ancien]; ancien:=ancien+l
FINPROC; FINPROC
PROCEDURE dp\iler(x:entier);
PRECONQ pl>l ; Programme 4.2. Unefile discutable
pl:=pl-1 ; x:=pile[pl]
FINPROC Pour mettre un objet dans la file, il faut quil y ait une place libre (PRECOND
libreltaille). Pour en enlever, il faut quil y ait au moins un objet dans la file
Programme 4.1. Mise en uvre dune pile (PRECOND ancienclibre). Les deux indices ancien et libre cernent les objets
restants dans la file, qui se trouvent en file[ancien..libre-11.
Pourquoi avoir dit que le programme ci-dessus est discutable ? Tout
On voit que le nombre dobjets dans la pile un moment donn est ~1-1. Les simplement parce quil ne rutilise pas Iespace dans la file. Une fois arriv au bout
procdures supposent que la pile ne dborde pas (PRECOND plltaille) et que lappel (libre=taille+l), on ne peut plus y mettre de nouveaux lments, mme si le retrait
de dpiler na pas lieu avec une pile vide (PRECOND pl>l). En pratique, on teste dautres lments a libr de la place. Il faut rendre la file circulaire, en testant
ces conditions par des SI ALORS spcifiques en dbut de procdure. autrement la prsence dau moins un lment (programme 4.3).

Dans le chapitre prcdent, nous avons programm directement la pile sans DONNEES taille: entier, file: TABLEAU [Maille] DE entier;
utiliser les procdures empiler et dpiler. La taille de la pile tait suppose suffisante. VAR n: entier INIT 0; ancien: entier INIT 1; libre: entier INIT 1;
Une pile vide tait le signe de terminaison de lalgorithme. PROCEDURE mettre(x: entier);
-i PRECOND netaille;
La pile donne ici est une pile dentiers. Le mme schma de programme peut file[libre]:=x;
servir pour la construction dune pile de rels, de boolens, . . . (il suffit de changer le SI libre=taille
type des lements du tableau pile). ALORS libre:=1
SINON libre:=libre+l
c FINS1
4.2. Les files FINPROC;
PROCEDURE enlever(x: entier);
Une file est une structure qui ressemble une pile, a la diffrence pres que lon PRECOND n>O;
retire llment le plus ancien au lieu du plus rcent. Une telle structure est x:=file[ancien];
particulirement utile, par exemple, dans un systme dexploitation, pour la gestion SI ancien=taille
des files dattente. On pourrait imaginer la paire de procdures du programme 4.2. ALORS ancien:=1
SINON ancien:=ancien+l
FINS1
FINPROC
Programme 4.3. Unefile circulaire

68 69
&OORITHMlQUE ET PROGRAMMKMON hOORllXhUQUE ET PROGRAMhCWION

La nouvelle variable n indique le nombre dlments actuellement p&ents dans Formellement, un arbre est une structure compose de nuds (node) et de
la fe. Les pr&conditions de non-pltkitude et de non-vide dpendent donc de la valeur bronches (arc, branch). Une branche menant du noeud nl au noeud n2 fait que n2 est
de n. Les variables libre et ancien avancent chaque fois de 1, en recommenant au un successeur (successor) de nl, nl tant le prkdkcesseur (predecessor) de n2.
dbut de la file une fois arrives la fin. Dans un syst&me dexploitation, on parle Chaque nud, lexception de la racine, possde un et un seul prdcesseur. Un nud
souvent dun producteur (producer) et dun consommateur (consumer) a la place peut avoir un nombre quelconque de successeurs. Un nud sans successeur est une
de mettre et enlever (voir [Griffiths 19881). feuille.

Suivre un chemin dans larbre se fait en suivant des branches successives.


4.3. Les arbres Ainsi, si n2 est un successeur de nl et n3 est un successeur de n2, alors il existe un
chemin de nl n3 (par lintermdiaire de n2). Nous limitons nos arbres des arbres
Larbre est une structure fondamentale dans lalgorithmique. Nous en avons dj connexes, cest-Mire que tout nud n est accessible partir dune unique racine.
vu un dans lalgorithme de tri par diviser pour rgner. Le pivot sert diviser le Accessible veut dire quil existe un chemin de la racine de larbre jusquau nud n.
vecteur en trois zones : Notons que lunicit des prdcesseurs fait que ce chemin est unique.
- une partie gauche,
- le pivot,
- une partie droite. 4.3.1. Arbres binaires et arbres n-aires
Les parties gauche et droite sont de nouveau divises, chacune en trois
nouvelles zones, et ainsi de suite. La figure 4.1 prsente ces divisions en forme La dfinition donne ci-dessus permet un nud dun arbre davoir un nombre
darbre. quelconque de successeurs. En pratique, les programmeurs se limitent souvent
lutilisation darbres binaires, dans lesquels un nud a au plus deux successeurs. A
priori, cela pourrait constituer une limitation du pouvoir dexpression, mais en fait
t[l ..n] ce nest pas le cas. On dmontre que-tout arbre n-aire peut tre reprsent sous la
forme dun arbre binaire, sans perte dinformation.

La forme binaire dun arbre n-aire sappelle un diagramme en forme de vigne


t[p+l ..n] (vine diagram). Au lieu de garder, pour chaque nud, des pointeurs vers ses
successeurs immdiats, on garde un pointeur vers son premier successeur (fils an)
et un deuxime vers le prochain successeur de son pr&Icesseur (frre cadet). La figure
4.2 en donne un exemple.

t[l ..pl-1] t[pl] t[pl +l ..p-1] t[p+l ..p2-l] UP21 t[p2+1 ..n] On voit sur la figure 4.2 les couples de pointeurs reprsents dans des botes
deux cases. Une case ban& indique labsence de successeur. Cette faon de dcrire un
Figure 4.1. Arbre du tri diviserpour rgner arbre correspond dassez prs sa reprsentation physique dans la mmoire de
Iordinateur.

Notons que les informatidiens ont pris lhabitude dinverser les arbres : la
situation initiale, la racine (root), est en haut, et les lkments terminaux, les
feuilles (leaf, leaves), en bas. Des arbres australiens, en quelque sorte . . . On parle
donc dalgorithmes qui descendent de la mcine jusquaux feuilles.

70 71
~ORITHMIQUE ET PROGRAhSMbXION .iLOORITHMIQUFi If2 PROGRAMMB-ION

Les deux premires colonnes de cette figure ne sont donnes que pour faciliter
la lecture. Dans la ralit, seuls sont conservs les vecteurs succg (successeur
gauche) et succd (successeur droit).

Etant donn la possibilit de transformer un arbre n-aire en arbre binaire, cette


representation est toujours suffisante. La structure avec deux botes par nud date de
LISP [McCarthy 19601. Si lon voulait conserver la forme originale, avec n
successeurs possibles, la table de la figure 4.3 comporterait autant de colonnes que le
nombre maximum de successeurs.

4.3.3. Parcours darbres

Lalgorithme classique de parcours dun arbre utilise un double appel rcursif


(programme 4.4).

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


PROC parcours(n: entier);
Figure 4.2. Tran@mnation darbre n-aire en arbre binaire
SI succg(n)zO
ALORS parcours(succg[n])
4.3.2. Reprsentation darbres FINSI;
SI succd(n)+O
Pour illustrer la reprsentation physique des arbres binaires, reprenons les ALORS parcours(succd[nJ)
botes de la figure 4.2, en les mettant dans une table (en pratique on utilise deux FINSI
vecteurs). Les noms des noeuds deviennent des entiers qui servent dindex dans ses FINPROC
vecteurs. En reprenant larbre de la figure 4.2, avec a=l, b=2, et ainsi de suite, on
obtient les vecteurs de la figure 4.3. Programme 4.4. Parcours dun arbre binaire

nom iIl&X succg


Le parcours complet dun arbre commence par un appel de
A 1 2 0 parcours(racine)
B 2 5 3
c 3 0 4
Le parcours dun noeud implique le parcours de tous ses successeurs. Les tests
D 4 8 0
sur les successeurs tablissent leur existence.
E 5 0 6
F 6 0 7
Pour viter de tester successivement lexistence dun successeur gauche, puis
G 7 0 0
celle dun successeur droit, on peut avoir recours la notion de bute. Un successeur
H 8 0 9
inexistant a lindex 0. Il suffit de crer un noeud dindex 0 comme bute (programme
1 9 0 10
4.5).
J 10 0 0

Figure 4.3. Reprsentation de larbre de lafigure 4.2

12 73
fiLGORITHMQUFiJ3TPROGR4MMATION fiLGORlTHMIQUElTPROGR4MWTION

DONNEES succg, succd: TABLEAU [O..taille] DE entier;


PROC parcours(n: entier);
SI nd)
ALORS parcours(succg[n]);
parcours(succd[n])
FINSI
FINPROC
Programme 4.5. Utilisation dune butke

Chaque fois quun nud na pas de successeur (gauche ou droit), le programme


appelle parcours(O). Le test au dbut de la procdure fait que lexcution ne va pas
plus loin.
4 5 7 A5
Pour liminer la rcursivit, on peut utiliser une pile, dans laquelle on garde le
souvenir des nuds qui restent a parcouru (programme 4.6). Figure 4.4. Parcours en profondeur dabord (ordrepr@xt?)

DONNEES succg, succd: TABLEAU [O..taille] DE entier;


racine: entier; La num&otation des nuds de cet arbre correspond lordre de visite des nuds
DEBUT VAR n: entier INIT racine, pl: entier INIT 1, dans un parcours dit deprojhdeur dabord (depth first seatch). Nous verrons par
fini: bool INIT FAUX, la suite que cet ordre est celui de lvaluation dite prt?jxt?e (ptefixed). Il est possible
pile: TABLEAU [l ..tpile] DE entier; dimaginer un parcours de larbre en largeur dabord (breadth first search, figure
MONDE pl: premire case libre dans pile; 4.3, mais le programme est plus difficile Ccrire (voir exercice en fin de chapitre).
TANTQUE NON fini
FAIRE SI n=O
ALORS fini:= pl=l ;
SI NON fini
ALORS dpiler(n)
FINSI
SINON empiler(succd[n]); n:=succg[n]
FINSI
FAIT
FIN
1
Programme 4.6. Parcours avec pile

43.4. Parcours prfix et post-fix

Considrons larbre binaire complet trois niveaux de profondeur qui se trouve


8
A 9 10
AA 11
l2 13
A
14 15

en figure 4.4. Dans un arbre binaire complet, tous les noeuds autres que les feuilles
ont exactement deux successeurs. De plus, tout chemin de la racine une feuille est Figure 4.5. Parcours en largey dabord
de la mme longueur (trois dans notre cas).

74 75
&OORITHMIQUE ET PROGRAMMATION iLGORITHMlQuE ET PROGRAMM.WION

Revenons sur le parcours en profondeur dabord, en dcorant le programme avec numt5ros des noeuds la place de visite-2 donnerait lordre infix (hfbxd! (figure
une mention pour chaque visite dun nud (programme 4.7). 4.7), celui donn par visite-3 tant post-jxt (postfuted) (figure 4.8). Ces drff&ents
ordres ont leur importance lors du traitement des expressions dans un compilateur.

PROCEDURE parcours(n);
SI n>o 8
ALORS visite-l ;
parcours(sg[n]);
visite-2;
parcours(sd[n]);
visite3
FINSI /
FINPROC

Programme 4.7. Triple visite dun nud 2 6 10 14

Ces numros de visite correspondent au fait que, dans un parcours darbre, on


visite chaque nud trois fois (figure 4.6), une fois en descendant gauche, une fois
ayant termin le parcours des successeurs gauche et avant de parcourir les successeurs
1
A 3 5
AA 0, 7 9 11 13

droits, et une dernire fois en remontant droite la fin.


Figure 4.7. Parcours en ordre infix

1
1 3
J\O

0 2

3 6 10 13

3
4 5 8 9 11 12
Figure 4.6. Triple visite des nuds dun arbre

Figure 4.8. Parcours en ordrepost-fixk


Supposons quau cours du parcours en profondeur dabord de larbre dans le
programme 4.7, on imprimait le numro de nud a la place de visite-l. Alors lordre
dimpression des nuds serait celui de la figure 4.4, ordre dit prfixe. Imprimer les

76 77
h3ORITHhtIQUE I?I- PROGRAMWWION fiLOORI?TIhUQUE ET PROGRAMWXION

4.4. Les treillis 4.5. Les graphes

Un treillis ressemble un arbre, mais en permettant un nud davoir plus Un graphe est toujours une collection de nuds et de branches, mais sans
dun pr&l&esseur. Les branches peuvent donc se rejoindre. Nanmoins, il nest pas limitations. Ceci permet des boucles, cest--dire quil peut exister un chemin qui
possible de boucler, cest--dire que tous les chemins vont vers lavant, en terminant m&ne du nud n jusqu lui-mme. Le rseau du mtro parisien est un exemple de
sur une feuille. Nous retrouverons le probl&me des boucles dans le paragraphe sur les graphe, o lon peut revenir au point de dpart dun voyage. On voit quun treillis est
graphes. La figure 4.9 donne un exemple de treillis. un cas particulier du graphe, un arbre tant un cas particulier du treillis.

Pour des raisons pragmatiques nayant rien faire avec la thorie, les
Racine informaticiens limitent souvent les graphes quils manipulent. Ainsi, on prendra
souvent la forme de vigne, afin de ne parler que de graphes binaires. De mme,
certains programmes ne travaillent que sur des graphes possdant une racine, cest--
dire que seront considrs comme tant nuds du graphe, les nuds qui sont
accessibles B partir de la racine. La notion de racine dans un graphe na pas de
justification thorique; elle correspond une volont de simplifier les programmes de
traitement.

Dans le cas gnral, parcourir un graphe binaire partir de sa racine avec


lalgorithme donn pour les arbres mnerait une boucle, car lalgorithme suit tous
les chemins possibles. Pour visiter chaque nud une fois, sans boucler, on a recours
& la technique de marquage. Le programme garde un drapeau boolen pour chaque
nud, indiquant si le nud a djh t visitk. On ne visite pas deux fois un noeud
(programme 4.8).

DONNEES taille: entier;


succg, succd: TABLEAU [O..taille] DE entier;
Figure 4.9. Un treillis racine: entier;
DEBUT VAR marque: TABLEAU [O..taille] DE bool INIT FAUX;
PROCEDURE visiter(n: entier);
Notons, dans cette figure, que tous les chemins qui commencent la racine SI NON marque[n]
terminent sur lune des feuilles Fl ou F2 dans un nombre fini de pas. ALORS marque[n]:=VRAl;
visiter(succg[n]); visiter(succd[n])
On peut parcourir un treillis comme un arbre, par exemple avec un des FINSI
programmes du paragraphe prcdent. Ce parcours visitera certains noeuds plusieurs FINPROC;
fois, car ils ont plus dun prdcesseur. En fait, chaque nud sera visit autant de fois visiter(racine)
quil y a de chemins qui mnent de la racine jusqu lui. Il se peut que lexistence de FIN
visites multiples soit gnante, pour des raisons defficacit ou de rkpptition
intempestive doprations. Pour visiter chaque nud une et une seule fois, on Programme 4.8. Visite dun graphe
applique lalgorithme de parcours dun graphe (voir ci-dessous). En fonction des
besoins immdiats, on traite donc un treillis comme un arbre ou, le plus souvent,
comme un graphe. Ce programme suppose lexistence dun nud de bute 0, qui est marqu.
Ainsi, le test de marquage et le test dexistence ne font quun. Notons que la

78 79
reprsentation dun graphe sur un couple de vecteurs succg et succd est la mme que Avec cette representation de la marque, lalgorithme classique prend la forme du
celle dun arbre. On peut enlever la rcursivit de cet algorithme en utilisant une pile, programme 4.9.
exactement comme dans le cas dun arbre. Par la suite, nous montrerons une mthode
de parcours dun graphe sans rcursivit mais aussi sans pile.
PROC parcours(n);
En gnkal, on parcourt un treillis comme un graphe, cest--dire en marquant SI m[sg[n]]=O
les nuds visites. Cela vite les visites rptr5es aux nuds qui sont sur plusieurs ALORS m[n]:=l ;
chemins. parcours(sg[n])
FINSI;
SI m[sd[n]]=O
4.51. Algorithme de Schorr-Waite ALORS m[n]:=2;
parcours(sd[n])
Lalgorithme classique de parcours dun graphe, comme celui dun arbre, met en FINSI;
jeu, soit un systme dappels rcursifs, soit une pile. Une application frquente de m[n]:=3
lalgorithme se trouve dans des interprteurs pour des langages tels que LISP, o, FINPROC
quand la mmoire affecte est pleine, il faut examiner les donnes en cours afin de
recuprer de lespace dans la mmoire principale. Pendant lexecution dun Programme 4.9. Marquage avec troisvaleurs
programme, on cree des nuds et des arcs, on en supprime et on les modifie. Aprs
un certain temps, la partie de la mmoire affecte au graphe est pleine. Mais, suite
aux diffrentes manipulations, certains nuds ne sont plus utiles. Lutilit dun nud En enlevant la rcursivit de cette procdure, on peut dduire le programme
est dfinie par son accessibilit. Tout noeud accessible partir de la racine est utile (il 4.10.
peut toujours servir). Un nud qui nest pas accessible ne peut plus servir. Pour
rcuprer lespace occup par les nuds inaccessibles, on commence par le marquage
de tous les noeuds accessibles. Par la suite, dans une deuxime phase, on examine DEBUT n:=racine;
tout lespace utilisable, en rcuprant les cases non marques. Ce processus sappelle TANTQUE NON fini
le ramasse miettes (garbage collection). FAIRE CAS m[n]
DANS
Le problme vient du fait que le ramassage des miettes intervient au moment 0: m[n]:=l;
o lon constate que la mmoire est pleine. On ne souhaite pas alors lancer une SI m[sg[n]]=O
procdure rcursive, tant donn que son excution ncessite louverture dune pile de ALORS n:=sg[n]
taille non prvisible. Une solution de ce problme existe [Schorr 19671. Il sagit de FINSI,
rutiliser les pointeurs pour mettre en uvre la notion de prdcesseur. 1: m[n]:=2;
SI m[sd[n]]=O
Considrons le parcours classique dun graphe. La figure 4.6 a dj montr ce ALORS n:=sd[n]
parcours sur trois nuds dun arbre. Chaque noeud est visit trois fois. Pour se FINSI,
rappeler o il en est, lalgorithme de Schorr-Waite garde dans la marque le nombre de 2: m[n]:=3; n:=pred[n]
visites au noeud dj effectues: FINCAS
FAIT
marque-0 noeud non visit FIN
marque=1 en train de visiter la descendance gauche
marque=2 descendance gauche termine, visite de la descendance Programme 4.10. Version sans rtcursivit
droite en cours
marque=3 le marquage de tous les successeurs du nud a t effectu

80 81
,dLGORITHMIQ~ ET PROGRAMMATION

Dans ce programme, la condition de terminaison est que tous les successeurs de n=prdcesseur(l), marque[l]=3, p=l, sg[l]=2, sg[l]=3.
la racine ont t marquks. Dans ce cas, lalgorithme remonte la racine pour la
demi& fois, cest--dire que m[racine]=3. Le programme utilise toujours la notion de On retrouvera un rsum de ces tats dans la figure 5.6.
bute (un successeur absent pointe vers le nud fictif 0, qui est marqu), mais il
teste si le successeur ventuel (droite ou gauche) est marquk avant dy aller. Avec cette introduction, nous arrivons au programme 4.11.

La difficult de cette version du parcours vient du fait que lon ne sait pas
remonter vers le pticesseur (n:=pred[n]) aprs avoir pass la valeur de la marque DONNEES Un graphe cod en forme de vecteurs comme avant
3. La structure des donnes ne comporte que des pointeurs vers les successeurs de DEBUT VAR n, p: entier;
chaque noeud. Pour n5soudre le problme, Schorr et Waite ont propos de renverser le nkracine; p:=O;
pointeur vers le $uccesseur suivi afin dindiquer, de manire temporaire, le TANTQUE m[racine]<3
pr&l&esseur du nud. Pour ce faire, on garde, tout moment, dans une variable p, la FAIRE CAS m[n]
valeur prcdente de n, le nud courant. Considrons la situation quand lalgorithme DANS
arrive pour la premire fois sur le nud 1 de la figure 5.6 : 0 : m[n]:=l ;
SI m[sg[n]]=O
n=l, marque[l]=O, p=prdcesseur(l), sg[l]=2, sd[l]=3. ALORS % La voie est libre gauche %
cycleh sg[nl, p)
Appelons les cases qui indiquent les successeurs dun nud sg[n] et sd[n]. SINON % La voie nest pas libre, mais on fait comme si lon y
Lalgorithme va procder au marquage de la descendance gauche. n va donc prendre la tait all et comme si Ion en revenait %
valeur de sg[n], p prenant la valeur de n (il suit toujours n avec un temps de retard). wWg[nl, PI
Comme n a pris la valeur du successeur gauche, la case qui contient lindex de ce FINSI,
successeur fait maintenant double emploi. On le rkutilise temporairement pour se 1 : m[n]:=2;
rappeler du prdcesseur (lancienne valeur de p). On arrive la situation suivante : SI m[sd[n]]=O
ALORS % La voie est libre droite %
n=2, marque[l]=l , p=l, sg[l]=prdcesseur(l), sd[l]=3. cycle(n, sd[n], sg[nl, P)
SINON % Comme si lon revenait de droite %
A la fin du marquage de la descendance gauche, cest-Mire quand marque[2] passe 3, cycWg[nl, p, sd[nl)
lalgorithme remonte sur le nud 1 dans ltat suivant, avec p toujours juste FINSI,
derrire n : 2: m[n]:=3; cycle(n, sd[n], p)
FINCAS
n=l, marque[l]=l, p=2, sg[l]=prdcesseur(l), sd[l]=3. FAIT
FIN
On va maintenant repartir droite, ayant restaur le successeur gauche et en
conservant le prdcesseur du nud 1 dans sd[ l] pendant la visite : Programme 43 . Mise en uvre du prdcesseur

n=3, marque[l]=2, p=l, sg[l]=2, sd[l]=prdcesseur(l).


Le programme comporte deux points particuliers : linstruction cycle et ce qui
En remontant de la droite, on aura : se fait quand le chemin nest pas libre, droite ou gauche.

n=l, marque[l]=2, p=3, sg[l]=2, sd[l]=prdcesseur(l). Linstruction cycle correspond une affectation multiple. Ainsi, considrons le
cycle suivant :
n va remonter vers le prdcesseur, en laissant le nud 1 dans son tat de
dp-t: cyWn, ss[nl, P)

82 83
ALGORITHMIQUE m PROGRAMMMION z!LGORITHMQUE ET PROGRAMMATION

11 correspond a laffectation multiple : m=O


m=3
h w[nl, PI := (sg[nl, P, n)

Pour excuter une affectation multiple, on calcule les valeurs droite, puis on
les affecte, en parallble, dans les variables indiques gauche. Cette faon dcrire
&Vite de considrer des effets de bord qui pourraient rsulter de lordonnancement des
affectations individuelles. Par exemple, la squence suivante daffectations donnerait m=l
un rdsultat incorrect :

n:=sg[n];
sg[n]:=p; j
p:=n
m=2
La premire affectation n fait que les deux autres affectations reprent la
nouvelle valeur de n quand cest lancienne qui est recherche. Il faudrait sauvegarder
lancienne valeur de n : P

xn:=n; Figure 4.10. Etats dans Schorr-Wtite


n:=sg[xn];
sg[xn]:=p; La nouvelle id& est de garder le pointeur vers le pticesseur dans la case du
p:=xn successeur que lon ne prend pas. La figure 4.11 montre les tats rsultants, dans
lesquels le pointeur vers le descendant restant doit obligatoirement changer de place.
Dautres squences de code donnent le mme rsultat.
m=O
Quand le successeur prvu est marqu, soit parce quil nexiste pas, soit parce m=3
quil est en cours de traitement sur un autre chemin, le programme ne doit pas le
prendre en compte. Mais les pointeurs doivent tre mis dans un tat qui correspond
laugmentation de la valeur de m[n]. Lalgorithme met jour les pointeurs comme si
n revenait du chemin qui mne au successeur marqu, bien quil ny soit jamais all.

m=l
4.5.2. Amlioration de lalgorithme de Schorr-Waite

Cette prsentation vient de [Griffiths 19791, en rponse celle de [Gries 19791.


Cest ce dernier qui a transmis lide de lastuce qui permet de raccourcir le
programme ci-dessus. Nous ne connaissons pas lidentit de linventeur de lastuce.
m=2
Considrons les tats par lesquels passent les noeuds au cours du traitement
(figure 4.10).

Figure 4.ll . Etats dans Schorr-Waite amtlior

84 85
t&GORITHhllQUE IS PROGRAMION

Cette idee, priori un peu bizarre, donne lieu au programme 4.12. Cette version finale du programme, tres condense, est assez agrable du point
de vue de lesthtique, mais elle a demand un travail considerable. Cest un bon
exercice de style. En plus, le programme rsultant peut tre repris tel quel et installe
DONNEES Un graphe cod en forme de vecteurs comme avant dans un ramasse-miettes performant.
DEBUT VAR n, p: entier;
nkracine; p:=O;
TANTQUE m[racine]<3 4.5.3. Reprsentation de graphes sur une matrice binaire
FAIRE CAS m[n]
DANS On peut aussi reprsenter un graphe sur une matrice binaire, ce qui facilite le
0: m[n]:=l ; traitement de graphes n-aires. Un 1 B lintersection de la ligne Y et de la colonne X
SI m[sg[n]]=O veut dire que le nud X est un successeur du nud Y. Considrons le graphe de la
ALQRS cycle(n, sg[n], sd[n], p) figure 4.12.
SINON cycle(sg[n], sd[n], p)
FINSI,
1 : m[n]:=2; A
SI m[sg[n]]=O
ALORS cycle(n, sg[n], sd[n], p)
SINON cycle(sg[n], sd[n], p)
FINSI, C
2: m[n]:=3; cycle(n, sg[n], sd[n], p)
FINCAS
FAIT E
FIN

Programme 4.12. Schorr-Waite amlior

On voit que, dans cette version du programme, les mmes cycles se rptent.
En regroupant, dune part, les cycles identiques et, dautre part, les augmentations des Figure 4.12. Un graphe
valeurs de m[n], on obtient le programme 4.13.

DEBUT VAR n, p: entier; Sa reprsentation en forme de matrice binaire se trouve sur la figure 4.13.
n:=racine; p:=O;
TANTQUE m[racine]<3 A B C D E F
FAIRE m[n]:=m[n]+l ; A 0 1 1 0 0 0
SI m[n]=3 OUALORS m[sg[n]]=O B 0 0 1 0 1 0
ALORS cycle(n, sg[n], sd[n], p) c 0 0 0 1 0 0
SINON cycle(sg[n], sd[n], p) D 0 1 0 0 0 0
FINSI E 0 0 0 0 0 1
FAIT F 0 0 0 0 0 0
FIN
Figure 4.13. Reprsentation sur une matrice binaire
Programme 4.13. Version condenske

86 87
Un 1 reprsente un arc qui mne du nud indiqu par la ligne celui de la Les nuds B, C, D presentent la particularit dtre leurs propres successeurs
colonne, un 0 indiquant labsence dun tel arc. Cette representation est plus compacte (un 1 sur la diagonale principale). Cest une indication de la prsence dune boucle
que la table utilide auparavant dans le cas dun graphe permettant de multiples (on peut aller de B jusqu B). Le graphe nest donc pas un treillis et, fortiori, nest
successeuts (graphes n-aires). Elle se prte aussi certaines classes de manipulations, pas un arbre.
comme dans le paragraphe suivant.
Lalgorithme direct de calcul dune fermeture transitive suit la dfinition : SI B
est un successeur de A, ALORS tous les successeurs de B sont galement
4.5.4. Fermeture transitive successeurs de A. Considrons la ligne A de la figure 4.13. Elle comporte des 1
dans les positions B et C. Ainsi, les successeurs de B sont des successeurs de A,
La fermeture dune relation est une opration bien connue des mathmaticiens. comme le sont les successeurs de C. Pour les successeurs de B, on prend la ligne B
Elle &ulte de la transitivit de lopration considere. Par exemple, cette proprit en lajoutant la ligne A par lopration OU inclusive. On fait de mme pour chaque
nous permet de dduite: 1 de la ligne A, que le 1 soit dorigine ou quil rsulte dune addition. On ne reprend
pas deux fois un 1 dans la mme position. Pour la ligne A, cela donne les oprations
SI aeb ET bec de la figure 4.15.
ALORS a<c
FINSI
A B C D E F
Intuitivement, on dit que les amis des amis sont des amis. Considrons la
notion de successeur dans un graphe. Dans la matrice du paragraphe prcdent, un 1 ligne A au dpart : 0 1 1 0 0 0
dans la position (~,y) indique quil existe un arc entre le nud y et le noeud x (x est addition de Ia ligne B : 0 1 1 0 1 0
successeur de y). Maintenant, si x est un successeur de y, et si y est un successeur de addition de la ligne C : 0 1 1 1 1 0
z, on peut dduire que x est un successeur de z (en passant par y), cest--dire quil addition de la ligne D : 0 1 1 1 1 0 (sans changement)
existe un chemin entre z et x. La fermeture transitive dun graphe donne sa addition de la ligne E : 0 1 1 1 1 1
connectivitk Pour chaque nud n, on obtient la liste complte des nuds qui sont addition de la ligne F : 0 1 1.1 1 1 (sans changement)
accessibles partir de n.
Figure 4.15. Fermeture transitive, une ligne
La figure 4.14 montre la fermeture transitive du graphe de la figure 4.13. On
voit, dans la premire ligne, quil est possible, en partant de A, datteindre les noeuds
B, C, D, E, F. En revanche (premiere colonne), A na pas de prdcesseur. On voit Aucun nouvel 1 nayant t introduit, on a termin avec la ligne A. La mme
bien que A est la racine dun graphe connexe. De la mme faon, dans la dernire opration a lieu pour chaque ligne du graphe. Cet algorithme nest pas optimal. Il a
ligne, on voit que F na pas de successeur, cest--dire que F est une feuille. t amlior plusieurs reprises [Warshall 19621, [Griffiths 19691.

A B C D E F 4.6. Ordres partiels et totaux


A 0 1 1 1 1 1
B 0 1 1 1 1 1 Les quatre structures, les files, les arbres, les treillis et les graphes, ont des
c 0 1 1 1 1 1 proprits dordonnancement importantes. Dans une file, il existe un ordre total,
D 0 1 1 1 1 1 cest--dire que pour chaque couple (x, y) dlments, une et une seule des relations
E 0 0 0 0 0 1 suivantes est vraie (pas est la position de llment donn) :
F 0 0 0 0 0 0
Posa() < PWY)
Figure 4.14. Fermeture transitive du graphe de lafigure 4.13 ou Pw)o P=(Y)

88 89
&OORITHMIQUE ET PROGRAMIUKIXON
tiLGORlIHMQUEETPROGRA~ION

Cette propriete fait quil nexiste quun seul ordre dcriture dans lequel les suite. Le tout constitue donc un arbre binaire dont les nuds sont dcor& (dans le
clments se trouvent chacun leur place. Elle est vidente dans le cas dune file (voir champ val) avec le nom de la personne reprsente. Un nom est une suite de lettres
le cas des entiers positifs). de 8 caracteres au plus. La racine de larbre sappelle adam (ou ve, si lon
Dans un arbre ou dans un treillis, il nexiste que des ordres partiels. Un ordre prlbe). On fbira les proc&hr.res n%trsives suivantes :
doit respecter la rgle suivante : - PROC trouver(nom, n) -> (bool, entier).
SI x est successeur de y La variable nom contient le nom dune personne. Le boolen retourn en
ALORS ~OS(X) > pas(y) &ultat sera VRAI si et seulement si la personne nomme est prsente dans larbre
FINSI ou le sous-arbre de racine n. Si le nom est prsent lentier retourn en rsultat
contiendra lindex du nud comportant le nom.
Considerons larbre binaire trivial de la figure 4.16.
- PROC parent(p, enf, n) -> (bool, entier).
Comme pour trouver, mais on cherche un couple parent - enfant de noms p et

A
enf. Lentier rsultant contiendra, le cas ch&nt, lindex du parent.
- PROC cousingermain(a, b, n) -> (bool, entier, entier).
Recherche de cousins germains de noms a et b.
- PROC aeul(a, enf, n) -> (bool, entier, entier).
2 3 Recherche des liens entre laeul de nom a et son descendant enf. On imprimera
(dans le bon ordre) les noms des personnes dans la descendance (a est parent de b, b
Figure 4.16. Arbre binaire simple est parent de c, . . . , i est parent de enf), ou un message appropri si enf nest pas un
descendant de a.
La rgle dordonnancement est respecte par les deux squences suivantes :
2. Par la suite, on peut se poser les mmes questions avec des familles plus
123 naturelles, o chaque enfant a un p&re et une mre, avec des mariages stables et
132 monogames. On garde le contrle des naissances (pas plus de deux enfants par
famille). On engendre un treillis.
La figure 4.4 (prfix ou en profondeur), comme la figure 4.5 (en largeur),
prksentent des ordres partiels dans un arbre. Les ordres des figures 4.7 (infix) et 4.8 On btira un systme conversationnel qui accepte des informations des types
(post-fixe) ne respectent pas la rgle. Les arbres et les treiilis permettent toujours les suivants :
ordonnancements partiels des lements les constituant (il existe un seul ordre, cest-a- - a se marie avec b,
dire un ordre total, si et seulement si aucun nud na plus dun successeur direct). - naissance de lenfant e du couple m, f.

Lordonnancement nest plus possible pour un graphe qui comporte une boucle. Larbre familial est un fichier sur disquette. Les procdures de recherche peuvent
En effet, comme la boucle indique quil existe au moins un lment qui est son prendre la forme de questions (interface ?) comme :
propre successeur, il nest plus possible de respecter la kgle dordonnancement par la -Quiestlepredex?
relation de succession. - Qui est la grand-mre maternelle de y ?
- Des questions de lexercice 1.
4.7. Exercices
3. Dans un arbre binaire complet n niveaux, combien y a-t-il de nuds ?
REMARQUE. - La notion de pointeur na pas t introduite. Il faut donc grer Combien de feuilles ?
des tables dindex.
4. Ecriture du programme de parcours dun arbre binaire en largeur dabord.
1. On considre des familles de type un peu particulier. Il y a un seul parent, avec au
plus deux enfants. Un enfant peut lui-mme tre parent dautres enfants, et ainsi de

90 91
Chapitre 5

Rcurrence et rcursivit

Que ce soit pour la rsolution de problmes, pour la spcification


dalgorithmes, voire mme pour leur mise en uvre, la rcwrence (induction) est
un outil mathmatique essentiel. Tout informaticien se doit de la matriser.
Heureusement, la rcurrence est une technique simple, en depit de sa puissance.

Dans les chapitres prcdents, nous avons dj vu des programmes bass sur la
rkurrence. Il est dailleurs difficile dimaginer des programmes qui ny font pas appel,
car la simple boucle en est une forme. Linformaticien parle souvent de rduire un
problme en n vers un problme en n-l. Dans dautres cas (diviser pour rgner ou
parcours de graphes, par exemple), on parle de la rduction dun problme en n vers
deux problmes en n/2. Il sagit maintenant de rendre le lecteur plus conscient du
mcanisme et de sa puissance.

Au niveau de la programmation, nous avons dj vu que la rcurrence peut se


traduire par la rcursivit
(recursion) ou par des itrations, avec ou sans pile. Le
choix de mthode dpend de la complexit du problme considr, de la puissance du
langage de programmation utilis et de lefficacit requise.

Comme dhabitude, nous abordons les techniques travers des exemples. Ceux-
ci sont souvent bien connus, car cest un sujet sur lequel beaucoup de collgues ont
dj travaih.

5.1. Lexemple type - les tours dHanoi

Si ce problme est utilis comme exemple dans tous les cours de ce type, ce
nest pas un hasard. Il est mme arriv au niveau des journaux de vulgarisation
hGORIWMIQUE ET PROGRAMMKfION /KGO~QUE ET PROGRAh4MkXION

[Bezert 19851. La source la plus ancienne que nous connaissons est de E. Lucas, PROCEDURE hanoi(n, a, b);
sous le pseudonyme de M. Claus, en 1883. Les tours dHanoi donnent lieu a une SI n=l
solution lgante par la n?currence, une analyse itkative demandant plus de travail. ALORS dplacement(a, b);
SINON hanoi(n-1, a, 6-a-b);
Le titre du problme vient de lhistoire raconttk habituellement, qui est celle de dplacement(a, b);
moines bouddhistes en Asie du sud-est qui grnent le temps en transfrant des hanoi(n-1,6-a-b, b)
disques, tous de tailles diffrentes, sur un jeu de trois piquets (voir figure 5.1). Dans FINSI
cette figure il ny a que cinq disques, mais la tradition veut que les moines jouent FINPROC
avec 64. Lhistoire est une invention du dix-neuvibme sicle, Lucas la plaant
B&u&s (en Inde). On ne sait pas comment elle sest resitue Hanoi . . . Programme 5.1. Toursdtianoi, version de base

Dans cette proc&re, nous avons suppos que les piquets sont numrots 1.2,
3. Deplacer un disque se fait par la procdure dplacement. Pour n=l le deplacement
est immediat, autrement on applique lalgorithme dcrit ci-dessus, 6-a-b tant le
numro du troisime piquet (6=1+2+3, donc en soustrayant deux des trois
possibilits de 6 on obtient la troisime).

La figure 5.2 montre les appels en cascade de la procdure hanoi (note h) pour
le transfert de trois disques. Le dplacement dun disque est not d.

A B C
h(3,12)
Figure 5.1. Position de dpart des tours dtianoi

Le jeu consiste transfrer la pile de disques du piquet A vers le piquet B, h(2,1,3) W 2) ~(2,3,2)
en utilisant C comme piquet de manuvre, tout en respectant les deux rgles
suivantes :
- un disque ne peut pas tre pos sur plus petit que lui,
- on ne dplace quun disque la fois.

La solution la plus simple vient de la rponse la question suivante : si je


A
h(l ,112) dU,3) ht1 ,231
A
h(l,3,1) d(3,2) W ,112)

savais transfrer n-l disques, saurais-je transfrer n ?. La rponse est oui, car
autrement nous naurions pas pos la question. Ainsi, pour transfrer n disques de A
B, on commence par le transfert de n-l disques de A C, suivi du dplacement du
dernier disque (le plus gros) de A B, suivi du transfert des n-l disques de C B.
Cela donne la proc&rre du programme 5.1.
Figure 5.2. Arbre dappels pour trois disques

Larbre se lit de la maniere suivante :


- Pour transferer 3 disques du piquet 1 au piquet 2 (racine de larbre), on

94 95
ALGORITHMIQUE m PROGRAM~WION fdLGORlTHMIQUE IX PROGRAMMtWION

transfre deux disques de 1 a 3, un disque de 1 2, puis deux disques de 3 2 51.2. Une analyse plus pousse
(successeurs de la racine).
- Les successeurs de type h sont dcomposs de la mme manire, en La solution rcursive au problbme des tours dHanoi est satisfaisante pour
appliquant rcursivement la procdure. lesprit et marche dans lordinateur. Mais elle comporte linconvnient de ne pas tre
- Les feuilles de larbre sont des dplacements dun seul disque. tres pratique pour le joueur humain. Mettons nous un instant la place des moines,
qui dplacent leurs disques la main. Quel disque faut-il dplacer un moment
En reprenant les feuilles de larbre dans lordre, de gauche a droite, on dduit les donn ? Lalgorithme rcursif necessite la mise a jour constante dune pile pour
dplacements simples, dans lordre, pour le cas de trois disques : prendre en compte les appels en cours, mais il ne serait pas trs pratique pour les
moines de grer une telle pile.
d(lS) d(l3) d(Z3) d(l2) W,l) d(32) d(1,2)
En fait, un peu de rflexion nous permet de faire mieux, au moins pour jouer
Les sceptiques peuvent toujours essayer avec trois pices de monnaie ! la main. Pour obtenir des rgles simples pour le joueur humain, nous avons besoin
de quelques thtkmes.
5.1.1. Cotit de lalgorithme

Se pose maintenant la question de savoir combien de dplacements individuels Thorme 1.


sont ncessaires pour transfrer n disques. En considrant le programme du
paragraphe prcdent, on voit que le transfert de n disques cote deux fois le prix du Dans une position quelconque, il y a au plus trois dplacements possibles.
transfert de n-l disques plus 1 dplacement, par le fait que :

h(n)= h(n-1)+ 1 + h(n-1) Preuve.

On obtient les quations de rtkurrence suivantes, avec c reprsentant le cot de Supposons quaucun piquet nest vide. Comparons les tailles des trois disques
lopration, mesur en nombre de dplacements individuels : en haut des piquets. Le plus gros des trois ne peut pas bouger, car il faudrait le poser
sur plus petit que lui. Le moyen peut se poser sur le plus gros (une possibilit),
Cl = 1 mais pas sur le plus petit (qui est plus petit que lui). Le petit peut passer sur Iun ou
c,=2*c,,+1 lautre des deux autres piquets, ce qui donne trois possibilits en tout. Maintenant, si
pourrbl
un des piquets est vide, il joue le rle du plus gros disque, qui ne peut pas bouger de
toute faon, et largument ne change pas. Si tous les disques sont sur le mme piquet
Pour voir la solution de ces quations de rcurrence, considrons quelques cas :
(deux piquets vides), cest-a-dire dans la position de dpart, il ny a que deux
n possibilits : le plus petit peut aller sur lun ou lautre des deux piquets restants.
cn
1 1
2 3 Thorme 2.
3 7
4 15 Le disque moyen ne doit pas bouger deux fois de suite.

On voit intuitivement que Preuve.

C,=2"-1 Sur les piquets de dpart et darrive, les autres disques sont tous plus gros que
lui. Sur le troisime piquet, il y a le plus petit. Aprs un dplacement, le moyen
reste donc le moyen. Son seul dplacement possible serait de retourner do il vient,
En substituant cette valeur dans lquation, la solution est confirme. ce qui serait parfaitement inutile.

96 97
hOORlTHMIQUE ET PRCGRAMMATION

Thorme 3. pour n (le tour continue). Comme la propriete est vraie au niveau de trois disques
(voir les dkplacements r&sultants de la figure 5.2), elle est vraie pour n disques, -3.
Le plus petit ne doit pas bouger deux fois de suite.
Cette preuve est juste, mais elle pose souvent des probltmes aux lves en
raison du changement apparent de la direction du cercle entre le niveau n et le niveau
Preuve. n-l. Cest un faux problme, mais il indique une autre proprit intressante.
Supposons que le transfert complet souhaite est de A B. Alors, si le nombre total
Ce nest pas la peine, car il aurait pu y aller en un coup. de disques est impair, le premier dplacement (ncessairement du plus petit) est
galement de A B. Mais, si le nombre total de disques est pair, le premier
dplacement est de A C (lautre possibilit). Avec un nombre impair de disques, le
Tborme 4.
cercle est
Tous les dplacements dindex impair sont des dplacements du plus petit
abcabc...
disque, les dplacements pairs tant du moyen.
Avec un nombre pair, il est
Preuve.
acbacb...
Cest le petit qui commence dans la position de dpart, dplacement 1. Par la
suite, le moyen et le plus petit alternent, daprks les thoremes 1-3. Si n est pair, n-l est impair, et inversement. Mais, en regardant les param&res
des appels de n et de n-l dans le formule F ci-dessus, on se rend compte de
Nous avons dmontre que pour savoir qui bouge, il suffit de savoir si le dernier Iinversion de la direction.
transfert tait du petit disque ou du moyen. Le prochain dplacement concerne donc
lautre disque mobile. Comme les dplacements du disque moyen sont imposs (une Nous pouvons donc dduire la regle pour les moines, qui doivent transfrer,
seule possibilit), ils ne posent pas de problbme. Reste trouver une regle pour les rappelons le, 64 disques. Pour effectuer un transfert de A B, le premier deplacement
dplacements du plus petit. est de A C (64 est un nombre pair, pour un nombre impair de disques le
deplacement aurait t de A B). Par la suite, il suffit de se rappeler si le coup qui
vient davoir lieu tait un dplacement du plus petit disque, ou non :
Thhorme 5. - Si le dplacement prcdent tait du plus petit disque, on dplace le moyen
(une seule possibilit).
Le plus petit disque parcourt les piquets dans un ordre fixe, cest--dire quil fait - Si le dplacement prcdent tait du disque moyen, on dplace le plus petit
des cercles. vers le prochain piquet dans le cycle A C B A C B . . .

Preuve. 5.2. Des permutations


Par rcurrence sur n. Supposons que la proprit soit vraie pour n- 1, cest--dire La gnration des permutations de n objets est un exercice dalgorithmique et de
que le petit disque tourne, par exemple, dans lordre a b c a b c . . . On sait que programmation qui prsente un intrt pdagogique certain tout en menant a des
(formule F) : programmes utiles. La litt&ature scientifique comporte de nombreux papiers sur le
sujet.
n>l => h(n, a, b) = h(n-1, a, c); d(a,b); h(n-1, c, b)
Nous abordons ces algorithmes dun point de vue personnel, en fonction de
Comme le d(a,b) ne concerne pas le plus petit disque, si les deux appels de
dcouvertes alatoires. Le premier programme date dune des coles de FL. Bauer.
h(n-1, . ..) font tourner le petit disque dans le mme sens, alors la proprit est vraie

98 99
ALOORIlTIMIQUE ET PROGRAMMATION h3ORlWMIQUE ET PROGRAMMATION

5.2.1. Permutations par Ichanges de voisins Sur cette figure, on voit que le 4 traverse les autres objets de droite a gauche,
puis retourne au point de dpart par une traverse de gauche a droite. Au moment de
La spcification de ce probleme nous a t donne dans les annes 70, par un son changement de direction, le 4 ne peut pas revenir immdiatement, car lchange
collegue. Malheureusement, nous ne nous rappelons plus de qui il sagissait. Si reproduirait la permutation pnkdente. Chaque fois que le 4 termine une traverse, et
jamais il lit ces lignes, ce serait avec plaisir que nous lui attribuerons son bien . . . Le donc va changer de direction, lalgorithme effectue un change dans le monde des
probleme est dengendrer toutes les permutations des n lments dun vecteur, en trois. Cela veut dire que les trois objets restants mettent leur vie au niveau infrieur.
appliquant les seules rgles suivantes. Le 4 traverse chaque permutation du monde des trois avant que lalgorithme en
produise la prochaine. Dans le monde des trois, le trois traverse chaque permutation
- Entre deux permutations successives, la seule diffrence r6sulte de lchange de
du monde des deux. Ainsi, on justifie lalgorithme par la formule de rcurrence
deux voisins. Notons quen gnral V[il a deux voisins, V[i-l] et V[i+l], mais v[l] et
suivante : lobjet n traverse completement chaque permutation des n-l objets
v[n] nont chacun quun seul voisin, ce qui veut dire que le vecteur nest pas circulaire
restants. On engendre ainsi toutes les permutations de n objets. La demibre colonne
et, en particulier, v[l] et v[nl ne sont pas des voisins.
de la figure 5.3 indique les permutations des trois objets qui sont engendn$es chaque
- En numrotant chacun des objets par lindex de sa position de dpart (l..n), changement de direction du quatrime. Le sens du mot pivot deviendra clair par la
lchange qui a lieu entre deux permutations successives concerne llment le plus suite.
grand possible, sans reproduire une permutation dj produite.
Ces deux rgles impose un ordre unique de production des permutations, mme 52.2. Le programme
si cet ordre nest pas vident a premire vue. Afin de bien cerner le problme,
considrons lordre impos par cet algorithme pour les permutations de quatre entiers Dans ce programme, nous travaillons sur lentier i, qui est lindex de lchange
(figure 5.3). considr. LCchange i transforme la permutation i en la permutation i+l. La valeur
de i varie donc de 1 factoriel(n)-1, o n est le nombre dobjets, lchange dindex
Numm Pivot Monde des trois factoriel(n) reproduisant la position de dpart. Les objets sont reprsents par les
1234 4 123 entiers (l..n). Le vecteur v contient, chaque instant, la dernire permutation
2 1243 4 produite.
3 1423 4
4 4123 3
5 4132 4 132 Avec les conventions ci-dessus, nous allons considrer les questions suivantes :
6 1432 4 - A lchange dindex i, quel est lobjet qui doit schanger avec un voisin plus
- 7 1342 4 petit que lui ? On appelle cet objet le pivot.
8 1324 3
- Dans quelle direction le pivot doit-il bouger ?
9 3124 4 312
10 3142 4 - O se trouve le pivot dans v ?
11 3412 4
12 4312 2 La figure 5.3 indique le pivot dans le cas des permutations de quatre lments.
13 4321 4 321 Reprenons cette sequence (figure 5.4).
14 3421 4
15 3241 4
16 3214 3
17 2314 4 231 123456789101112131415161718192021222324
18 2341 4 444344434 4 4 2 4 4 4 3 4 4 4 3 4 4 4fin
19 2431 4
20 4231 3
21 4213 4 213 Figure 5.4. Valeurs de i et du pivot dans permutations(4)
22 2413 4
23 2143 4
24 2134 Dans cette figure, la Premiere ligne indique les index des changes successifs, la
Figure 5.3. Permutations de quatre entiers deuxime le pivot pour lchange. On voit que le quatre prend trois changes pour

100 101
hOOR111IMIQuE ErPROGRAMM4TION fiLOORIIHMIQUE EI PROGRAMhfH-ION

traverser la permutation courante du monde des trois, suivi dun change dans ce positions a partir de son point de dpart.
monde des trois. On voit que chaque fois que 4 nest pas un diviseur de i, cest le 4 - Le point de dpart du pivot est complttement gauche ou complbtement
qui est le pivot. Considrons maintenant le monde des trois. Les changes le droite de lensemble des lments du monde des nn, qui se trouvent dans des
concernant sont les 4, 8, 12, 16 et 20, tous les i multiples de 4. Il suffit de diviser positions successives (tout lment dordre suprieur est en fin de traverse).
ces valeurs par 4 pour retrouver la squence 1,2,3,4,5. De manire rcurrente, dans
le monde des trois, le pivot est le 3, sauf si 3 divise le nouvel i (lancien i/4). Pour Le point de dpart naturel dune traverse est la position 1 (traverse de gauche
le cas gnral, on obtient le programme 5.2 pour le calcul du pivot. &oite) ou nn (de droite a gauche). Mais considrons, dans la figure 5.3, lchange
numro 4, qui est le premier du monde des 3. Le pivot, dans ce cas le 3, nest pas en
position 3, mais en position 4. La raison est que le 4 a termin une traverse de
DEBUT nn:=n; ni:=i; droite gauche sans revenir. On voit quil faut dplacer le point de dpart naturel par
TANTQUE nn DIVISE ni le nombre dlments dordre suprieur qui ont accompli un nombre impair de
FAIRE ni:=ni/nn; nn:=nn-1 traverses. Tout cela nous donne le programme 5.3.
FAIT
% nn est le pivot pour lchange i %
FIN DEBUT DONNEES n: entier;
VAR i, ni, nn, p, q, d, pos: entier;
Programme 5.2. Calcul dupivot VAR perm: TABLEAU [ 1 ..n] DE entier;
POUR i:= 1 JUSQUA n FAIRE perm[i]:=i FAIT;
POUR i:= 1 JUSQUA fact(n)-1
Le fait de recopier n et i dans les variables temporaires nn et ni vite de les FAIRE ni:=i; nn:=n; d:=O;
d&ruire. Loprateur DIVISE donne un rsultat VRAI si son deuxime oprande est TANTQUE nn DIVISE ni
un multiple exact du premier, FAUX autrement. Dans la plupart de langages de FAIRE ni:=ni/nn; nn:=nn-1 ;
programmation, il faudrait kcrire un test du type suivant : SI impair(ni) ALORS d:=d+l FINSI
FAIT;
SI nn*entier(ni/nn)=ni ALORS . . . p:=entier(ni/nn); q:=reste(ni/nn);
SI pair(p)
Examinons maintenant le problme de savoir o en est le pivot dans ses ALORS pos:=nn+d-q+l ; changer(perm[pos], perm[pos-11)
traverses du monde infrieur. A la fin de la boucle ci-dessus, nn est le pivot et ni SINON pos:=q+d; changer(perm[pos], perm[pos+l J)
lindex de lchange dans le monde des nn. Considrons les valeurs de p et q, FINSI
Calcul&s comme suit : FAIT
FIN
p:=entier(ni/nn); q:=reste(ni/nn);
Programme 5.3. Permutationspar changes
Notons que q>O, car la division laisse ncessairement un reste (condition de
terminaison de la boucle). On dmontre que p est le nombre de traverses dj
effectues par nn, q tant lindex de lchange dans la traverse actuelle. Cela rsulte Dans ce programme, d est le dplacement cr par les traverses dlments
du fait quune traverse ncessite tut-1 6changes avec nn comme pivot. dordre suprieur. Aprs la division ni/nn, la nouvelle valeur de ni reprsente le
nombre de traverses dj effectues par lancien M. Si ce nombre est impair, nn est
Avec cette information, on peut dduire les faits suivants. reste a gauche, provoquant une augmentation de la valeur de d. Le calcul de pos, la
- Si p est pair, le pivot procde de droite gauche, et si p est impair, de gauche position du pivot, prend en compte les faits dduits ci-dessus.
droite. Effectivement, la premire traverse, avec p=O, a lieu de droite a gauche, la
deuxime, avec p=l, dc gauche droite et ainsi de suite. Le calcul de pos, avec le cumul de d, peut tre vit en gardant en mbmoire le
- Le pivot a effectu q-l changes dans cette traverse. Il a donc avanc de q-l vecteur inverse du vecteur perm. Llment perm[i] indique lobjet qui se trouve en

102 103
ALG~RITHMICKE m PROGRAMMMION &GORIIHMIQUE I7r PROGRAMMtWON

position i. Llment inv[i] va indiquer la position de lobjet i en perm. Cest donc fichier. On voit que la reprsentation choisie doit tre une fonction de lutilisation
une reprsentation duale de la relation biunivoque que lon va en faire. La double reprsentation est souvent ncessaire, cest--dire que
h pr6fecture garderait deux fichiers, lun tri en fonction des noms des propritaires,
position <-> objet lautre par des numros dimmatriculation.

On obtient le programme 5.4.


5.2.3. Relation avec les tours dHanoi

DEBUT DONNEES n: entier; La technique dutiliser lindex du coup jouer marche aussi dans les tours
VAR i, ni, nn, p, q, pos, voisin: entier; dHanoi. Supposons que les disques sont numrots de 1 (le plus grand) n (le plus
VAR perm: TABLEAU [l ..n] DE entier; petit). Pour savoir quel est lindex du disque qui doit bouger, on peut utiliser un
POUR i:= 1 JUSQUA n programme semblable celui que nous avons dduit ci-dessus pour les permutations
FAIRE perm[i]:=i; inv[i]:=i (programme 5.5).
FAIT;
POUR i:= 1 JUSQUA fact(n)-1
FAIRE ni:=i; nn:=n; d:=O; DEBUT nn:=n; ni:=i;
TANTQUE nn DIVISE ni TANTQUE 2 DIVISE ni
FAIRE ni:=nihn; nn:=nn-1 FAIRE ni:=ni/2; nn:=nn-1
FAIT; FAIT;
p:=entier(ni/nn); q:=reste(ni/nn); pos:=inv(nn); % Cest le disque nn qui bouge %
SI pair(p) FIN
ALORS voisin:=perm[pos-11; perm[pos-l]:=nn;
inv[nn]:=pos-1 ; inv[voisin]:=inv[voisin]+l Programme 5.5. Encore les tours dtianoi
SINON voisin:=perm[pos+l]; perm[pos+l]:=nn;
inv[nn]:=pos+l; inv[voisin]:=inv[voisin]-1
FINSI; Ce calcul dpend du fait que le plus petit disque bouge une fois sur deux, que le
perm[pos]:=voisin second bouge une fois sur deux des coups restants, et ainsi de suite.
FAIT
FIN Lide de travailler sur les proprits numriques de lindex du coup sav&re
intressante dans un ensemble dapplications.
Programme 5.4. Permutations par changes, version 2

5.2.4. Une variante


Dans cette version, pos est la position du pivot, voisin lobjet avec lequel il va
schanger. Les deux vecteurs sont mis jour de manire vidente. En relaxant la r&gle concernant lchange de voisins, on peut produire un
deuxihme programme, similaire au premier, qui engendre toutes les permutations de
Lide de garder la reprsentation inverse dune relation revient souvent dans les n objets dans un autre ordre. Nous allons travailler sur la rcurrence suivante : le
programmes, comme dans les bases de donnes. Considrons le fichier de pivot n traverse de droite gauche chaque permutation du monde des n-l. Pour quatre
propritaires de voitures tenu jour par une prfecture. On peut, par exemple, le trier objets, les permutations sont engendres dans lordre de la figure 5.5.
dans lordre alphabtique des noms des propritaires. Dans ce cas, connatre le
numro dimmatriculation de DUPONT est une opration rapide (avec un algorithme
de recherche dichotomique, par exemple). Mais dcouvrir le nom du propritaire du
vhicule 9999Xx44 devient difficile, car il faut inspecter chaque entre dans le

104 105
DEBUT DONNEES n: entier;
VAR i, j, nn, p, q: entier;
perm: TABLEAU [l ..n] DE entier;
i:=O;
TANTQUE idact(n)
Index Mondes FAIRE nn:=n; P:=i;
Les4 Les 3 Les2 POUR j:=l JUSQUA n FAIRE perm[j]:=O FAIT;
TANTQUE nn>O
0 1234 123 12 FAIRE % placer lobjet nn %
1 1243 q:=reste(p/nn); p:=entier(p/nn); j:=n;
2 / 1423 TANTQUE q>O
3 4123 FAIRE % sauter q positions vides %
4 1324 132 SI permjj]=O ALORS q:=q-1 FINSI;
5 1342 FA,T j:=j-1
6 1432
7 4132 TANTQUE permjj]zO
8 3124 312 FAIRE % trouver la prochaine position vide %
9 3142 j:=j-1
10 3412 FAIT;
11 4312 permjj]:=nn;
nn:=nn-1
12 2134 213 21 FAIT;
13 2143 % perm contient la permutation dindex i %
14 2413 i:=i+l
15 4213 FAIT
16 2314 231 FIN
17 2341
18 2431 Programme 5.6. Traverse unidirectionnelle
19 423 1
20 3214 321
21 3241 Pour chaque valeur de i, le programme calcule la position de chaque objet nn
22 3421 (llnnln) dans le vecteur perm. Par la mme logique que celle de lalgorithme
23 4321 prcdent, on prend la partie entire (en p) et le reste (en q)de la division de p (une
copie de i au dpart) par nn. La partie entire indique combien de traverses
Figure 5.5. Nouvelles permutations de quatre objets
compltes ont t effectues par nn. Le reste indique le nombre davances dj
effectues par nn dans la traverse actuelle. Les index i vont de 0 fa&(n)-1 pour
faciliter les calculs.
Considrons le programme 5.6.
La valeur de q permet de calculer la position de lobjet nn dans perm. Lobjet nn
a dj avanc q fois. En commenant droite, lalgorithme passe sur q positions
vides dans perm. Lobjet nn va occuper la prochaine position vide. La boucle est
rpte pour chaque objet n, n-l, n-2, . . . . 1. La nouvelle valeur de p est lindex de la
permutation dans le monde des nn-1 .

106 107
ALGORITHMIQUJ~ m PROGRA~~W~TION

Ce nouvel algorithme a un avantage important par rapport au prcdent : il a la dfinition suivante : Les 1Cments dans chaque permutation sont considrs
calcule chaque permutation a partir des valeurs de i et. de n, sans consulter les comme des cara&res (numriques) dun mot. Ces mots sont organiss en ordre
permutations prcdentes. 11 est donc capable de calculer la permutation i sans alphabtique (ordre numrique si lon considre les Clments comme les chiffres dun
engendrer ses prdcesseurs. Cette possibilit sert souvent, car de nombreuses nombre).
applications ncessitent de tirer au sort une permutation. Apr&s le tirage au sort dun
entier albatoire entre 1 et factoriel(n), lalgorithme peut engendrer la permutation
correspondante. 5.3. Exercices

Sur les tours dHanoi


5.2.5 Une version rcursive
1. En supposant que les moines de Hanoi veuillent transfrer le jeu complet de 64
Ce nest pas par got de la difficult que les programmes pour les permutations disques, en prenant une seconde pour le dplacement individuel dun disque, combien
prsents en premier lieu ncessitent une certaine rflection, mais justement pour leur faudrait-il de temps ? La 1Cgende veut que la terminaison du transfert signale la
apprendre raisonner. Evidemment, on peut travailler directement, en Ccrivant une fin du monde.
procdure rkursive de manire naturelle (programme 5.7).
2. Etablir une courbe de complexitk de lalgorithme des tours dHanoi en mesurant le
temps nkessaire au calcul pour diffrents nombres de disques. Lexercice sert faire
VAR pos: TAB [O..max-11; prendre conscience des problkmes dexplosion combinatoire.
PROC perm(i, n):
VAR p, q, j: entier; 3. Avec 64 disques, et en numrotant les disques d, (le plus petit), d,, . . . . b (Ie
SI n=l
ALORS pos[l]:=l plus gros), dans quel ordre d2 parcourt-il les piquets et, en gCn&al, quelle est la rgle
SINON p:=entier(i/n); q:=reste(i/n); perm(p, n-l); pourq ?
POUR j:=n-1 PAR -1 JUSQUA q+l FAIRE pos~]:=pos[j-1] FAIT;
pos[q]:=n 4. Considrons les index des dplacements simples i 1 (le premier coup), i,, . . . Quel
FINSI . est le numro du disque qui bouge au coup ij ?
FINPROC

Programme 5.7. Version rcursive


Sur les permutations

5. La possibilit de tirer au sort une permutation est utile dans de nombreuses


Dans cette procdure, i est lindex de la permutation engendrer,
applications. On reprendra la mthode de gnration des permutations par change de
Oli<factoriel(n-1). n est le nombre dlments placer dans pos[O..n-11. La
voisins (&5.2.2), en la modifiant afin de pouvoir calculer la permutation numro i
numrotation partir de 0 facilite lutilisation du systme de partie entire et reste,
sans en engendrer les i-l prkdentes.
d@ tudi.
6. Ecrire un programme qui engendre les permutations dans lordre alphabtique (la
Ainsi, sil existe plusieurs lments placer (n>l), on place n-l Clments par
valeur numrique de lentier produit en concatenant, dans lordre, les objets de la
lappel rcursif, puis on insre le n-ibme sa place en dcalant les q derniers
permutation i, est plus petite que celle de la permutation i+l) sans utiliser une
lments chacun dune case vers la droite. Dans le monde des n-l, lindex de la
procdure rcursive. Le programme possdera la proprit de la question prcdente
permutation concerne est p (entier(i/n)).
(engendrer une permutation sans engendrer ses pklcesseurs).
Cet algorithme, appel rptition pour les valeurs de i de 0 factoriel(n)-1,
engendre les permutations dans lordre alphabtique. Cet ordre, classique, correspond a 7. On considre les nombres pouvant tre forms partir des chiffres 1, 2, . . . . 9,
chaque nombre comportant une et une seule occurrence de chaque chiffre. En

108 109
ALOORITHMIQUJ3 ET PROGRAMMPLTION

organisant ces nombres dans lordre numerique, quelle est la valeur du 1OO.OOO&me
nombre ? (Concours de jeux mathmatiques de France, 1986).

8. Considrons lensemble de valeurs duales des permutations du 85.2.2. (vecteur


inv). Nous lavons utilis pour faciliter la recherche de la position courante de chaque
objet. Est ce que cet ensemble forme un nouvel ordonnancement des permutations de
n objets ? Chapitre 6
9. Un thorme bien connu des mathmaticiens est que toute permutation de n objets
est un produit unique de cycles. On dmontrera le thorme en laccompagnant dun
programme qui identifie les cycles concerns pour une permutation dom&. La marche arrire
10. Le code de Gray est bien connu dans le monde de la transmission dinformations.
Il est dfini de la manire suivante :

On considre lensemble de caractres forms dun nombre fixe de bits. Comme


dhabitude, n bits permettent de disposer de 2 caracti?res. Dans le code de Gray, deux
caract&w qui se suivent ne diffrent que par la valeur dun seul bit. Dans ce chapitre nous abordons une nouvelle catgorie dalgorithmes : ceux qui
mettent en jeu la rrwrcAe arrire (backtracking). Il sagit de resoudre des problmes
On crira un programme qui engendre les caractres successifs du code de Gray sur n non dterministes. Un problbme qui nest pas dterministe ne peut pas tre rsolu de
bits, sachant que le bit qui change de valeur chaque fois est celui du poids le plus manire directe. Considrons la situation de quelquun qui arrive un carrefour dans
faible possible. Par exemple, pour n=3, on aura lordre suivant : un labyrinthe. Il ne sait pas si la bonne dcision est de tourner gauche ou droite.
La solution est dessayer une des possibilits ouvertes, en la poursuivant aussi
000 longtemps que possible. Si la dcision mne un blocage, il faut revenir sur ses pas
001 afin dessayer une autre possibilit. Cest cette ide de revenir sur ses pas qui donne
011 lieu lexpression marche arrire.
010
110
111 6.1. La souris et le fromage
101
100 Nous considrons comme application de la marche arrire un problme de
labyrinthe artificiel. Sur un chiquier classique (8 cases par 8), il y a un morceau de
fromage que veut manger une souris. Les coordonnes des cases quils occupent sont
[xf, yfl et [xs, ys]. Le problme est dtablir un chemin que peut prendre la souris
pour aller jusquau fromage, sachant quelle ne peut avancer que dune case la fois,
soit horizontalement, soit verticalement, et quil existe des barrires infranchissables
entre certaines cases voisines. Le problme est ancien, mais la premire utilisation
ayant un rapport avec linformatique que nous connaissons est [Zemanek 19711. Il a
t utilis par un des auteurs comme exercice de programmation depuis une cole
dt en 1972 et a servi comme support dans un cours dintelligence artificielle
[Griffiths 1986, 19871.

110
hGOlUTHMIQUEiETPROGRAhfMKllON

Nous allons donc crire un programme mettant en uvre la marche arriere pour 1 DEBUT DONNEES barrire: TAB [1..8, 1..8, 1..4] DE bool;
la recherche dun chemin, sans essayer de trouver le chemin le plus court. Le 2 xs, ys, xf, yf: entier;
programme prsente les camctkistiques suivantes : 3 VAR marque: TAB [1..8, 1..8] DE bool INIT FAUX;
4 pile: TAB [1..64] DE entier;
- A chaque tour de la boucle principale, il considere, sil en existe, un pas en 5 x, y, xn, yn, dir, pl: entier;
avant, sinon il en fait un en an-Se. 6 X:=X~; y:=ys; marque[x, y]:=VRAI; dir:=O; pl:=l;
- Le pas en avant est dans la premire direction disponible (qui na pas encore 7 TANTQUE NON (x=xf ET y=yf) ET pl>O
t essaye) partir de la case courante. 8 FAIRE SI dire4
9 ALORS dir:= dir+l ;
- Lordre de disponibilit est : nord, est, sud, ouest, qui sont reprsentes par les 10 SI NON barrire[x, y, dir]
entiers 1,2, 3,4. 11 ALORS xn:= CAS dir DANS (x, x+1, x, x-l) FINCAS;
- En arrivant sur une case, le programme la marque. Les marques ne sont 12 yn:= CAS dir DANS (y+1 , y, y-l, y) FINCAS;
jamais enleves. La souris ne repasse jamais en marche avant dans une case dj 13 SI NON marque[xn, yn]
marque, car lalgorithme essaie toutes les possibilits partir de chaque case visite, 14 ALORS x:=xn; y:=yn; marque[x, y]:=VRAI;
et il ne faut pas quil boucle. 15 pile[pl]:=dir; pl:=pl+l ; dir:=O
FINSI
- Faire marche arrire consiste en un retour vers le prdcesseur de la case FINSI
courante, suivi dun essai dans la prochaine direction disponible partir de cette case 16 SINON PI:=PI-1 ;
(sil en existe). 17 SI PI>0
- La marche arrire rsulte du constat que lon a essay les quatre directions 18 ALORS dir:=pile[pl];
partir dune case sans trouver un chemin. 19 x:= CAS dir DANS (x, x-l, x, x+1) FINCAS;
20 y:= CAS dir DANS (y-l, y, y+1 , y) FINCAS
- Pour faire un pas en arriere, il faut savoir do on est venu. Ainsi, a chaque FINSI
dcision, la direction prise est sauvegarde sur une pile. A chaque retour en arrire, FINSI
on revient sur la dcision la plus rcente, qui est en tte de la pile. Si la situation est FAIT
toujours bloque, on prends encore le prkdcesseur, et ainsi de suite. FIN

Le programme 6.1 est donn en entier pour faciliter la prsentation, les Programme 6.1. La souris et le fromage
commentaires tant regroups a la fin.

Les numeros de ligne servent aux commentaires.


1. barrire[i, j, dir] est VRAI si et seulement sil y a une barriere entre la case [i, j] et
sa voisine en direction dir. Le tableau est initialis ailleurs. Le bord de lchiquier est
entoure de barrieres pour viter de faire rfrence a des cases inexistantes.
2. [xs, ys] est la position de dpart de la souris, [xf, yfl celle du fromage.
3. marque[i, j] est VRAI si et seulement si la souris a dj visit la case [i, j]. Ce
tableau est initialis FAUX.
4. Une pile de 64 Clments suffit.
5. [x, y] est la position courante de la souris. [xn, yn] est une position vise par la
souris. dir reprsente le nombre de directions que la souris a dj essayes partir de
la case [x, y].

112 113
6. Linitialisation met [x, y] la position de dpart [xs, ys], qui est marque. Aucune DEBUT DONNEES xs, ys, xf, yf: entier;
direction na t essaytk La pile est vide. barr: TAB [1..8, 1..8, 1..4] DE bool;
7. On boucle tant que le fromage nest pas atteint et quil existe des chemins VAR marqu: TAB [1..8, 1..8] DE bool INIT FAUX;
essayer. existe chemin: bool;
PROC jr%dre(x, y) -> bool;
8. Existe-t-il encore une direction essayer ? VAR trouve: bool;
9. Alors on prend la prochaine. dir: entier;
10. Si la route nest pas barrke, on calcule les coordonnes [xn, yn] de la case voisine trouv:= x=xf ET y=yf;
en direction dit SI NON marque[x, y]
11,12. dir=l veut dire vers le nord, cest-a-dire augmenter y de 1, et ainsi de suite. ALORS marqu[x, y]:=VRAI; dir:=O;
TANTQUE NON trouv ET dir<4
13. Dans labsence de marque sur [xn, yn], on peut y aller. Si la case est marquee, on FAIRE dir:=dir+l ;
essaiera la ptochaine valeur de dir au prochain tour de la boucle. SI NON barr[x, y, dir]
14. Le mouvement a lieu, avec marquage. ALORS trouv:=joindre(CAS dir DANS x, x+1, x, x-l FINCAS,
15. La dcision est enregistre sur la pile. Pour la nouvelle case le nombre de CAS dir DANS y+1 , y, y-l, y FINCAS)
I
directions dja essayes est 0. FINSI
FAIT;
16. Comme il nexiste plus de directions essayer, il faut faire marche arrire.
St trouv ALORS imprimer(x, y) FINSI
17. Si la pile nest pas vide, on prend la direction prise pour arriver sur la case FINSI;
courante, qui se trouve en haut de la pile (18). pl=O arrive quand tous les chemins RETOURNER trouv
possibles ont t essays partir de [xs, ys] et le fromage na pas t atteint. Il ny a FINPROC;
donc pas de chemin possible. existechemin:=joindre(xs, ys)
19,20. On calcule, en inversant les lignes 11 et 12, les coordonnes du prdecesseur, FIN
et le programme fait un nouveau tour de la boucle. j
Programme 6.2. Forme rtkmive
A la fin du programme, si un chemin existe, la pile contient toutes les I
dcisions prises sur lesquelles lalgorithme nest pas revenu. Ainsi la pile contient
une solution du probleme. 11 nest pas intressant de programmer ici une boucle Le lecteur ayant tout suivi jusquici naura pas de probleme pour comprendre ce
dimpression, mais le principe de la disponibilit des rsultats acquis est valable pour programme.
les algorithmes de marche arrire en gnral. Pendant lexcution du programme, la
pile contient a chaque moment les dcisions en cours dessai.
l 6.1.2. Marche arrire, arbres et graphes
l
6.1.1. Version rcursive La marche arriere est un moyen dexplorer systmatiquement un arbre de
possibilits. Evidemment, lexploration systmatique ne termine que si le nombre de
Dans le cas dune recherche complte sur toutes les possibilits, la marche possibilitt% est fini. Il faut aussi noter lexistence de lexplosion combinatoire, o le
arrire est lquivalent dun parcours darbre ou de graphe (voir $6.1.2). Dans le nombre de possibilits, bien que fini, est tellement grand que lexploration est en
probleme considr ici, nous sommes en prsence dun graphe, car il serait possible dehors des capacits des ordinateurs.
de revenir sur la case que lalgorithme vient de quitter, et lon pourrait boucler. Cela
La figure 6.1 montre quelques branches de larbre de possibilites pour la souris.
est une autre explication du besoin de marquage, pour empcher le programme de
Commenant sur la case [xs, ys], elle a quatre directions disponibles (en ignorant des
suivre les boucles. Comme dans tous les algorithmes de ce type, on peut crire le
barrires et les limites de lchiquier). Considrons la direction est, menant la
programme dans la forme dune procdure rcursive (programme 6.2).
case [xs+l, ys]. A partir de cette nouvelle case, quatre directions sont encore
imaginables, dresses sur la figure.

114
hOORITHhUQUE FiT PROGRAMMAITON kGORlTHMlQUE ET PROGRAMMHION

Dans le programme 6.3, np est un entier qui indique le nombre de reines


actuellement places. En marche avant, le programme considre la prochaine case [x,
y]. Le test 08 au dbut de la boucle sert a passer a la ligne suivante (y:=y+l) en cas
de besoin. Si la case [x, y] nest pas couverte par une dame dj place, on peut y
placer une nouvelle dame. Si la case nest pas libre, la prochaine case sera considre
au prochain tour de la boucle (x:=x+1 la dernire ligne).

4
[xs+l , ys+l] [xs+2, ys] [xs+l , p-11 [xs, ys]
l
l
>
DEBUT VAR np: entier INIT 0; % Le nombre de reines places %
x, y: entier;
x:=1; y:=l;
TANTQUE np c 8
% coordonnes dune case essayer %

FAIRE SI x > 8 ALORS x:=1 ; y:=~+1 FINSI;


SIY<
Figure 6.1. Arbre de possibilits pour la souris 1 ALORS SI libre(x, y)
ALORS np:=np+l ; empiler(x, y);
FINSI
Or, une de ces directions mbne la souris de retour sa case de dpart. Si lon SINON dpiler(x, y); np:=np-1
continuait dresser un arbre, il serait de taille infinie, car on recommence FINSI;
indfiniment avec la mme case. Pour reprsenter le labyrinthe par une structure x:=x+1
formelle, il faut passer un graphe, avec un nud par case. Les arcs sont toujours FAIT
bidirectionnels, reliant des cases voisines qui ne sont pas spares par des barrires. FIN
Notons que ce nest pas seulement le fait de pouvoir retourner directement vers la
case prcdente qui impose un graphe; on peut aussi arriver, par exemple, la case Programme 6.3. Les huit reines
[xs+l, ys+l] en deux pas de deux faons diffrentes (par [xs, ys+l] et par [xs+l,
YSI).
Lindication de la ncessit de faire marche arrire est quil ne reste plus de case
Le marquage des cases du labyrinthe correspond donc exactement au marquage essayer (y>8). Dans ce cas, on dpile x et y pour revenir dans ltat prcdent, en
des nuds dans le parcours dun graphe. Dans le cas du labyrinthe, le graphe est le diminuant le compteur np. Le prochain tour de la boucle considrera la prochaine
graphe de connectivit des cases, reprsentes par des nuds. Le programme 6.2 a la case. Le processus sar&e quand np arrive a 8, cest-Mire quand solution est trouve.
forme dun parcours de graphe n-aire. Comme nous savons quune telle solution existe, il nest pas ncessaire de considrer
le cas o la marche arrire ne peut pas avoir lieu.

6.2. Les huit reines Dans ce programme, la pile contient les coordonnes des reines places.
Comme il y a deux valeurs a empiler (x et y), il peut devenir intressant de dfinir
Il sagit encore dun exercice archi-classique, mais sa prsence ici est toujours deux piles, px et py. Dans ce cas, notons que np peut servir pour indiquer la hauteur
justifie par des raisons pdagogiques. Il faut placer huit reines sur un chiquier de de chaque pile. Par ailleurs, il nous faut remplacer lappel de la procdure libre par
telle faon quaucune reine ne soit en prise par rapport une autre. Deux reines sont une boucle qui decide si la case (~,y) est couverte par une reine dj place (mme
mutuellement en prise si elles se situent sur la mme ligne, la mme colonne ou la ligne, colonne ou diagonale). On obtient le programme 6.4.
mme diagonale. Le probleme est ancien [Bezzel 18481 [Gauss 18501, mais il a t
remis au got du jour avec larrive des ordinateurs. De nombreux articles modernes
lui sont consacrs, jusqu dans des revues populaires [Paclet 19841. Il y a 92
solutions, dont videmment un grand nombre dues la symtrie.

116 117

/
.kOORIIHMIQUE ET PROGlL4hfMMlON
kGORlTHB5QIJEiETPROOlUMMATION

DEBUT VAR px, py: TAB [1..8] DE entier; DEBUT VAR py: TAB [1..8] DE entier;
np: entier INIT 0; x, y: entier INIT 1;
x, y: entier INIT 1; libre: bool;
libre: bool; i: entier;
i: entier; TANTQUE x < 9
TANTQUE np < 8 FAIRE SI y < 9
FAIRE SI x > 8 ALORS x:=1 ; y:=~+1 FINSI; ALORS libre:=VRAI; i:=l ;
SIY< TANTQUE libre ET i<x
ALORS libre:=VRAI; i:=O; F;!RIE+;bre:= NON( y=py[i] OU abs(x-i)=abs(y-py[ij))
TANTQUE libre ET ienp .=
FAIRE i:=i+l ; FAIT;
libre:=NON(x=px[ij OU y=py(i] OU abs(x-px[i])=abs(y-py[i])) SI libre ALORS py[x]:=y; x:=x+1 ; y:=0 FINSI
FAIT; SINON x:=x-l ; y:=py[x];
SI libre FINSI;
;;sS np:=np+l ; px[np]:=x; py[np]:=y y:=y+l
FAIT
SINON x:=px[np]; y:=py[np]; np:=np-1 FIN
FINSI;
x:=x+1 Programme 6.5. Suppression dune pile
FAlT
FIN
Dans cette version du programme, la variable np disparat (sa valeur est la
Programme 6.4. Les huit reines, version 2 mme que celle de x-l). La variable x est la coordonnke en x de la nouvelle reine a
placer, y tant lautre coordonne de la prochaine case essayer. La marche arrire
devient ncessaire si y arrive 9, cest--dire sil ny a plus de cases essayer pour la
6.2.1. Une version ambliore valeur courante de x. Le test libre ne comporte plus de test sur x, car les x sont tous
diffrents par construction, x servant galement de pointeur dans la pile des y (il
La solution ci-dessus marche, mais on peut lamliorer. Profitons du fait que indique la premire place libre dans cette pile).
nous savons quil y a une et une seule reine par colonne. Il nest plus ncessaire de
gader une pile des x (programme 6.5).
6.2.2. Une deuxime approche

La demiere version ci-dessus ressemble un peu un compteur octal, qui grene


tous les nombres en octal de 0 77777777. Pour faciliter la programmation, nous
avons numrot les cases de lchiquier de 0 a 7 au lieu de 1 8. Considrons le
programme 6.6.

118 119
ALGORITHMIQUE ET P R O G R A M M A T I O N

DEBUT VAR camp: TAB [0..7] DE entier INIT 0; 00000000


VAR couvert: bool INIT VRAI; 0 0 0 0 0 0 0 1
i, j: entier; 00000002
TANTQUE couvert
FAIRE % avancer le compteur % et ainsi de suite. Avec la marche arrire, on dcouvre immdiatement que tout
i:=7; nombre commenant par 0 0 . . . est liminer. La marche arrire donne un
TANTQUE comp[i]=7 FAIRE comp[i]:=O; i:=i-1 FAIT; algorithme qui considre, dans lordre arithmtique :
comp[i]:=comp[i]+l ;
% tester la position cre % 00000000
i:=l ; couvert:=FAUX; 01000000
TANTQUE NON couvert ET k8 02000000
FAIRE j:=O; 02100000
TANTQUE NON couvert ET j-4
FAIRE couvert:=comp[i]=comp[jl et ainsi de suite. Compter le nombre de cas essays est la& comme exercice.
OU abs(i-comp[i])=abs(j-comp[jl);
j:=j+l Cette ligne de rflexion pourrait nous amener B considrer, la place du
FAIT; compteur octal, les permutations sur 8 objets. On sait en effet que tous les x,
i:=i+l comme tous les y, doivent tre diffrents. Le nombre de cas : considkrer au total est
FAIT de factoriel(8), cest--dire 40320 ( comparer avec les plus de 16 millions pour le
FAIT compteur octal). En faisant de la marche arri&re sur les permutations, il deviendrait
FIN possible de considrer encore moins de cas.

Programme 6.6. Avec un compteur octal Le programme de dpart dnombre les permutations successives, en utilisant
un des programmes du chapitre 5 (programme 6.7).

Dans ce programme, le compteur (camp) est initialis la valeur zro. Le


boolen couvert indique que deux reines se voient. Son initialisation VRAI est DEBUT VAR i: entier INIT 1, trouv: bool INIT FAUX;
une vidence : dans la position de dpart, toutes les reines se voient. La boucle TANTQUE NON trouv
externe tourne tant que la dernikre position examine nest pas la bOMe (aucune paire FAIRE trouv&=libre(perm(i))
de reines en prise mutuelle). i:=i+l
FAIT
Le contenu de la boucle est en deux parties : lavancement du compteur et FIN
lexamen de la nouvelle position cre. Les 7 droite du compteur deviennent des 0,
et le prochain chiffre gauche augmente de 1. Puis, pour chaque reine i (1...7), on Programme 6.7. Avec despermutations
teste si la reine j (O...i-1) est compatible. Les tests sarrtent la premi&re
incompatibilit.
En y ajoutant de la marche arrire, on pourrait arriver au programme 6.8.
Le nombre de positions essayer avant de dcouvrir toutes les solutions est de
8*, cest--dire 224, ou 16 Mga dans le sens de linformatique (1 Mga =
1024*1024). Considrer un peu plus de 16 millions de cas prend un certain temps.
Notons que la marche arrire diminue considrablement ce chiffre. En effet, les
premires positions essayes dans lalgorithme du compteur sont les suivantes :

120 121
fb3ORITHMIQuE m PROGRAMMKMON fiLOORITUMIQUJ3 JTI- PROGRAMhMION

DEBUT VAR perm: TAB [1..8] DE entier INIT 0; Sur les huit reines
disp: TAB [1..8] DE bool INIT VRAI;
n, i: entier INIT 0; 4. On modifiera le programme donn au $6.2.1 afin de trouver toutes les solutions.
TANTQUE ne8
FAIRE i:=i+l ; 5. Ecrire la version rcursive du programme du $6.2.1.
TANTQUE i<9 ETPUIS NON disp[i] FAIRE i:=i+l FAIT;
SI i<9 6. Ecrire un programme qui compte le nombre de cas essays en marche arriere sur le
ALORS couvert:=FAUX; j:=O; compteur octal (voir $6.2.2).
TANTQUE j<n ETPUIS NON couvert
FAIRE j:=j+l ; couvert:= n+l-j = abs(i-perm]) 7. Faire la mme chose pour le programme bas sur les permutations,
FAIT; -
SI NON couvert
ALORS n:=n+l; perm[n]:=i; disp[i]:=FAUX; i:=O Dautres applications de la marche arrire
FINSI
SINON i:=perm[n]; disp[i]:=VRAI; perm[n]:=O; n:=n-1 8. Extrait partiel du concours de jeux mathmatiques, 1987.
FINSI
FAIT On considre un triangle de cinq lignes :
FIN
X
Programme 6.8. Avec permutations et marche arrire xx
xxx
xxxx
Dans ce programme, les permutations essayer sont engendrees en perm. xxxxx
Llement disp[i] du tableau booleen disp indique si lobjet i est disponible, cest--
dire sil ne figure pas dj dans la permutation : disp[i] est VRAI si i ne figure pas Dans chacune des 15 positions, il faut placer un des 15 premiers entiers en
dans perm[l..n]. n indique le nombre de reines dj placees. A chaque moment, la respectant la condition suivante : lentier dans chaque position, sauf dans la demiere
valeur de i est lindex du dernier objet essay comme candidat la place perm[n+l], ligne, a comme valeur la diffrence entre les valeurs de ses successeurs immdiats
qui est la prochaine reine placer. (on considere le triangle comme un treillis binaire). Un dbut de solution pourrait
tre :
6.3. Exercices 7
103
Sur la souris et le fromage 11 14
...
1. Ecrire le programme qui ajoute lheuristique, cest--dire qui prend comme
direction pn5fMe celle du fromage. Chaque entier ne figure quune seule fois dans le triangle. On crira un
programme utilisant la marche arrire pour trouver une solution au problme.
2. Ecrire le programme de numerotation successive qui trouve un chemin de Combien y a-t-il de solutions en tout ?
longueur minimale.

3. Il existe combien de chemins diffrents allant de la case 11, 11 a la case [8,81 sur
un chiquier vide ? Une mme case ne peut pas figurer deux fois sur un mme
chemin. On &ira un programme qui compte le nombre de chemins.

122 123
Chapitre 7

Transformation de programmes

La transformation de programmes, par des techniques automatiques ou


manuelles, devrait intresser linformaticien professionnel pour plusieurs raisons :
- La transformation automatique de spcifications en programmes excutables
peut diminuer le cot de la production de programmes, tout en amliorant leur
fiabilitk
- On peut d6couvri.r des versions plus efficaces de certains programmes.
- En restant proche de la spcification dun programme, on en facilite la
portabilit.
- Le programmeur amCliore sa matrise des outils, ce qui nous intresse pour la
pdagogie.

Le besoin dindustrialiser la production des logiciels a provoqu lintroduction


de nombreux mots-cls nouveaux. Ces nologismes, tels que programmation
structuree, gnie logiciel, . . . . ne reprsentent pas seulement un phnomene de mode,
mais recouvrent aussi une ralit technique. Afin de sassurer de la qualit des
produits industriels, on a souvent recours la spcification formelle. Celle-ci sert a
la demonstration ventuelle dun programme, sa validation, voire mme sa
production. Cest pour ce dernier aspect que les techniques de transformation
deviennent utiles. Une spcification est une formulation mathmatique, surtout
algbrique, dun problme. Dans les mthodes de dmonstration de programmes, on
dispose dune spcification et dun programme, puis on dmontre que le programme
est une mise en uvre de la spkcification. Plutt que dmontrer lquivalence de ces
deux textes, on est arriv naturellement se poser la question de savoir sil est
possible de driver le programme partir de la spcification.
fdLOORIllU5QUE GT P R O G R A M M A T I O N fiLGORlTHhffQUEETPROGRAM.bMCION

Dans certains cas, la reformulation dun programme peut savrer plus efficace Cest en essayant de rdiger la spkification formelle de lalgorithme que nous
que la version dorigine. Nous avons vu leffet de certaines transformations dans le avons trouv une amlioration. Essayons de dnombrer les cas qui se ptisentent. On
cadre de programmes r&rsifs dans un chapitre prtkkdent. consid&re que le mode dun vecteur est un doublet : la longueur de la chane la plus
! >F.
longue et la valeur qui parat dans cette chane. On obtient les cas suivants :
La transformation dun programme nest possible que si le programme est crit I
dans une forme propre. Lutilisation dastuces dpendant dun compilateur particulier 1. n-l: mode(v[l..n]) = (1, V[I])
est proscrire. Notons que cela revient dire les mmes choses que lon retrouve 2. n>l , v[n]zv[n-11: mode(v[l ..n]) = mode(v[l ..n-11)
dans les ouvrages sur la portabilit des logiciels [Brown 19771. 3. n>l, v[n]=v[n-11, long(mode(v[l ..n]))>long(mode(v[l ..n-11)):
mode(v[l ..n]) = (long(mode(v[l ..n-l]))+l, v[n])
Enfin, mme si les techniques de transformation navaient aucune application 4. n>l, v[n]=v[n-11, long(mode(v[l ..n]))llong(mode(v[l ..n-11)):
pratique directe, nous les enseignerions quand mme nos tudiants. Effectivement, mode(v[l..n]) = mode(v[l..n-1])
en examinant diffrentes versions dun mme programme, ils &Parent mieuX ce qui
est intrins&que au problme de ce qui dpend du langage, du compilateur, voire de Lamlioration est venu en essayant de formaliser le test qui dcide si la chane
lordinateur particulier quils utilisent un instant-donn. Les paragraphes suivants courante est plus longue que le mode trouv jusqualors, cest--dire le test suivant :
donnent quelques exemples de transformations. Pour aller plus loin, on peut
consulter utilement des ouvrages tels que [Burstall 19751, [Darlington 19731. long(mode(v[l ..n]))>long(mode(v[l ..n-11))

Evidemment, on peut laisser le test sous cette forme, mais on cherche


7.1. Revenons sur le mode dun vecteur naturellement un test qui dcide si la nouvelle chane est plus longue que lancienne.
Cest en posant la question de cette manire que nous avons trouv lide (pourtant
Ce probl&me a form le sujet du premier vrai programme de cet ouvrage ($2.1). simple) de considerer le test suivant : soit lm la longueur du mode de v[l..n-11.
Il a t le sujet de plusieurs tudes [Griffiths 19761, [Arsac 19841, car on peut Alors, la chane dont v[n] fait partie est plus longue que lm si et seulement si
lamliorer trs simplement, cependant lamlioration reste difficile trouver. Nous
avons dcouvert la modification en explorant les techniques de transformation. La v[n] = v[n-lm]
version de dpart de cet algorithme tait celle du programme 7.1.
Il Dans la transformation de la spcification ci-dessus, on remplacera le test sur
les longueurs par ce nouveau test. l%r ailleurs, on note que les cas 2 et 4 donne la
DEBUT DONNEES n: entier; mme solution (le mode est inchang). Mais, si v[n]#v(n-1), il est certain que
v: TABLEAU [l ..n] DE entier; I
v[n]#v[n-hn]. On en dduit que la comparaison de v[n] avec son prdcesseur nest
VAR i, lcour, Imax, indm: entier INIT 1; pas ncessaire. La spcification devient :
TANTQUE kn
FAIRE i:=i+l ; 1. n=l: mode(v[l..n])=(l, V[I])
SI v[i]=v[i-1] 3. n>l, v[n]=v[n-long(mode(v[i ..n-l]))]:
ALORS Icour:=lcour+l ; mode(v[l ..n]) = (long(mode(v[l ..n-l]))+i, v[n])
SI lcouolmax 4. n>l , v[n]#v[n-long(mode(v[l ..n-l]))]:
ALORS Imax:=lcour; indmc-i mode(v(1 ..n)) = mode(v(1 ..n-1))
FINSI
SINON Icour:=l Le test v[n]=v[n-1] a disparu. En transformant cette spcification vers un
FINSI / programme itratif, on obtient le programme 7.2.
FAIT
FIN

Programme 7.1. Encore le mode dun vecteur

126 127
hCiO=QUE ET PROGRAWION fiLOOWTHMIQUEETPROGRAMh4MION

DEBUT DONNEES n: entier, parce que 3 est un nombre impair, 3 * 320 = 1 * 640 + 1 * 320. Donc il faut garder
v: TAB [l ..n] DE entier; les valeurs en face des nombres impairs. En Ccrivant ceci dans la forme dune
VAR i, indm, Im: entier INIT 1; procdure, on obtient le programme 7.3.
TANTQUE ien
FAIRE i:=i+l ;
SI $j=@-lm] % regard en arrire mult(a,b):SI a=0
ALORS indm:=i; Im:=lm+l % nouveau max ALORS 0
FINSI SINON SI impair(a)
FAIT ALORS b + mult(a-1, b)
FIN SINON mult(a/2, lf2)
FINSI
Programme 7.2. Le mode amlior FINSI

Programme 7.3. Multiplication avec rcursivit


On a gagn une variable et un test par lment du tableau. Cette optimisation,
bien que simple, nest pas vidente au dpart
Pour enlever la rcursivit, on introduit une variable res pour le cumul des
valeurs retenues (programme 7.4).
7.2. La multiplication des gitans

Lide de ce programme nous est venu de P.L. Bauer, qui la incorpor dans son multp(a,b,res):TANTQUE a>0
cours de programmation [Bauer 19761. Elle vient de lobservation de la mthode de FAIRE SI impair(a)
multiplication utilise par des gens sur des marchs de lEurope centrale. Montrons ALORS res:=res+b; a:=a-1
cette mthode sur un exemple, 25 * 40 : SINON a:=a/2; b:=b*2
FINSI
25 40 FAIT
12 80
6 160 Programme 7.4. Suppression de la rtcursivitk
3 320
1 640 I
! Comme il sagit dentiers, reprsentes sous forme binaire dans lordinateur, on
On a divis les nombres de la colonne gauche par deux, en multipliant par deux peut simplifier en faisant appel des dcalages (decg pour dcaler dune place vers la
ceux de la colonne de droite en mme temps. Lopration est rptee autant de fois I gauche, decd droite). Par ailleurs, si a est impair, a-l est pair, donc le SINON peut
que possible, en laissant tomber les moitis rsultant de la division par deux dun disparatre (programme 7.5).
,
nombre impair. Par la suite, on supprime, dans la colonne de droite, les valeurs
correspondant un nombre pair dans la colonne de gauche. Les nombres restant
droite sont additionns : multp(a,b,res):TANTQUE a>0
FAIRE SI impair(a)
ALORS res:=res+b; a:=a-1
40+320+640=1000
FINSI;
Ce qui est le rkwltat escompt. decd(a); decg(b)
FAIT
Les oprations ci-dessus ne sont pas le tour de passe-passe que lon pourrait
imaginer. En fait, 6 * 160 (deuxieme ligne) est strictement gal 3 * 320. Mais, Programme 7.5. Version avec dcalages

128 129
akOORIIHMIQUE ET PROGRAIdMWION

Etant donn que a est dcal droite, a:=a-1 nest pas n6cessaire, car le 1 que On utilise des connaissances intuitives des proprits telles que la
lon enBve est le dernier bit droite, supprime de toute faon par le dcalage qui va commutativit, la distributivit, . . . des oprateurs. Une tude des conditions
suivre. Cela nous permet de dduire lalgorithme de multiplication rellement mis en &essaires et suffisantes pour permettre des transformations ne peut quamliorer
uvre par les circuits dans les ordinateurs (figure 7.1). notre matrise de loutil de programmation.

Bauer signale que le programme de multiplication peut se gnraliser. Le mme


schma de programme permet la minimalisation du nombre de multiplications
t&essaires pour le calcul dune puissance entire (voir exercice en fin de chapitre).

7.3. Exercices

1. Utiliser le programme du 57.2 comme schma pour le calcul de ab.

2. Enlever la rcursivit des procdures divfact et div2 du $7.2.


res

Figure 7.1. Multiplication de deux entiers

On decale a vers la droite jusqu lanMe dun 1 dans le bit de droite. On dcale
dautant b vers la gauche. On ajoute la nouvelle valeur de b dans le registre rsultat.
La triple opration est rpte pour chaque bit de a ayant la valeur 1.

Lintroduction dune variable permettant de supprimer une rcursivit sans


recourir une pile est une technique habituelle. On le fait sans rflchir dans
beaucoup de cas. Considrons le programme bateau de calcul dun factoriel :
fact(n): SI n=l
ALORS 1
SINON n fact(n-1)
l

FINSI
Aucun programmeur nhsite crire la boucle suivante
fact:=l ;
TANTQUE ml FAIRE fact:=fact * n; n:=n-1 FAIT
Mais il hsiterait beaucoup plus sur les fonctions suivantes :
divfact(n): SI n=l ALORS 1 SINON n / divfact(n-1) FINSI
div2(n): SI n=l ALORS 1 SINON div2(n-1) / n FINSI

130 131
-
Chapitre 8

Quelques structures
de donnes particulires

Dans ce chapitre, nous introduisons plusieurs formes nouvelles darbres : les


arbres ordonns (ordered trees), les arbres quilibrs (balanced trees) et les B-
arbm (B-trees)

8.1. Les arbres ordonns

Pour quun arbre soit ordonn, il faut attacher une valeur chaque nud. Dans
la pratique, comme par exemple dans des systmes de gestion de fichiers ou de bases
de donnes, cette valeur est souvent une cl, du type dcrit pour ladressage dispers
(voir chapitre 2) ou dun style approchant. Ordonner un arbre revient a faire en sorte
que, si la valeur attache au noeud n est val[n], chaque nud dans le sous-arbre dont
la racine est le successeur gauche de n a une valeur associe vg tel que vgcval[nl, les
nuds droite possdant des valeurs suprieures. Cette dfinition implique quune
valeur ne peut figurer quune seule fois dans larbre. La figure 8.1 montre un exemple
darbre binaire ordonn (voir page suivante). -

Larbre de la figure aurait pu tre produit par lalgorithme naturel de


construction si les lments considrs staient prsents dans lun des ordres
suivants :

71042831
74211083
hOORIIHMIQUE EI- PROGRAMMWION

Yi,a;
*,- . ~

_-+ii
-, Larbre defini par les trois vecteurs succg, succd et val est fourni en entre,
; avec sa racine, la valeur v trouver ou a placer et lindex pl de la premik case libre
>f$s
dans chaque tableau. Si v est dj dans larbre, n se positionne sur le nud qui porte
4 la valeur v, sinon on cn5e un nouveau nud lendroit adquat de larbre.
10 /
Avec un arbre ordonn6, la recherche dun objet se fait plus vite quavec les
2 3 algorithmes prcdents (4.3.3), qui examinaient tous les nuds de larbre.
8
Lordonnancement permet de suivre toujours le bon chemin, cest--dire celui sur
lequel est, ou sera, le nud possdant la valeur recherche. Le nombre de tests dpend
. x ainsi de la profondeur de larbre.
1 3

Figure 8.1. Un arbre binaire ordonn


8.2. Les arbres quilibrs
/
Ces ordres sont des ordres partiels de parcours de larbre, o lordre partiel doit Lalgorithme du paragraphe prcdent amliore la vitesse de recherche dun
respecter la rgle suivante : un nud devance, dans lordonnancement, ses objet, mais le nombre de nuds examiner nest pas encore minimis. En effet,
successeurs. considrons larbre (figure 8.2) qui rsulterait dune arrive dobjets dans lordre
/ suivant :
Lalgorithme naturel de construction de larbre est aussi celui qui sert
rechercher la prsence dun objet dans larbre (programme 8.1). / 12347810

DEBUT DONNEES succg, succd, val: TABLEAU [l ..taille] DE entier;


v, racine, pi: entier;
VAR n: entier;
n:=racine;
TANTQUE wval[n]
FAIRE SI v<val[n]
ALORS SI succg[n]>O
ALORS n:=succg[n]
SINON succg[n]:=pl; n:=pl; PI:=PI+~;
succg[n]:=O; succd[n]:=O; val[n]:=v
FINSI
SINON SI succd[n]>O
ALORS n:=succd[n]
SINON succd[n]:=pl; n:=pl; pl:=pl+l ;
succg[n]:=O; succd[n]:=O; val[n]:=v
FINSI
FINSI
FAIT
FIN Figure 8.2. Arbre ordonn inejkace

Programme 8.1. Arbre ordonnk

134 135
fiLGO-QUEETPROGRAhtMATION

Les recherches sont minimises seulement si larbre est quilibr, ou du moins Cet arbre nest plus quilibr, car le nud de valeur 4 a 3 noeuds dans son sous-
si la profondeur maximale de larbre est minimise. La figure 8.3 montre larbre de arbre gauche et 5 droite. Pour le requilibrer, il y a plusieurs possibilits, dont
lexemple dans sa forme quilibn5e. celle de la figure 8.5.
6

5
1 3 7 10

Figure 8.3. Equilibrage de larbre de la figure 8.1

Soient ng le nombre de nuds dans le sous-arbre gauche dun nud donn, nd


le nombre de nuds dans le sous-arbre droit. Alors un arbre est quilibr si et
seulement si abs(ng-nd)<2. Si, pour tout nud, ng=nd, larbre est strictement Figure 8.5. Rquilibrage de larbre de la figure 8.4
quilibr, comme celui de la figure 8.3. Cela ne peut arriver que si le nombre de
nuds le permet (nombre total de noeuds = 2 - 1). On voit que lalgorithme de
recherche dans un arbre ordonne et quilibr a une efficacit dordre o(log2(n)), tandis Notons que larbre de la figure 8.4 est en fait aussi bon que celui de la figure
que lalgorithme classique est dordre o(n), avec n le nombre de noeuds. 8.5 en ce qui concerne lefficacit des recherches, car leurs profondeurs sont les
mmes. On peut dfinir la profondeur dun arbre comme tant la longueur du plus
Ajoutons maintenant deux nuds, de valeurs 6 et 11, larbre prcdent. On long chemin menant de la racine une feuille. Lefficacit des recherches se mesure
obtient larbre de la figure 8.4. en calculant le nombre de tests ncessaires pour atteindre chaque objet de larbre, ou
pour en placer un nouveau. Cest dans ce sens que les arbres des figures 8.4 et 8.5
sont defficacite Cgale (voir paragraphe ci-dessous sur les B-arbres).
4

8.2.1. Algorithmes de manipulation darbres Cquilibrs

La cration dun arbre quilibr partir dun ensemble dobjets ordonns nest
pas difficile. Commenons avec un vecteur v qui contient les valeurs, dans lordre
numrique. On peut considrer le programme 8.2.

6 11

Figure 8.4. Avec deux nuds en plus

136 137
hGORITHMIQUE ET PROGRAMMtWION

DEBUT DONNEES n: entier; une lecture sur support externe (en gnral un disque). La multiplication des enMes-
v: TABLEAU (1 ..n] DE entier; sorties est un facteur dterminant pour lefficacit du syst&me global, surtout dans un
VAR val, sg, sd: TABLEAU [l ..n] DE entier; contexte conversationnel, o les temps de rr5ponse ne doivent pas dpasser certaines
pl: entier lNIT 1; limites. Ce paragraphe reprend des notions exposes dans [Miranda 19871, qui traite
racine: entier; de tous les aspects des bases de donnes.
PROCEDURE arb(i, j: entier) RETOURNER entier;
VAR x, k: entier; Les B-arbres [Bayer 19711, [Bayer 19721 apportent une solution efficace au
SI i=j probEme, sans pour autant prtendre une efficacit parfaite. Ils reprsentent un
ALORS val[pl]:=v[i]; sg[pl]:=O; sd[pl]:=O; pl:=pl+l ; point dquilibre, vitant les algorithmes coteux de restructuration que ncessitent
RETOURNER (~1-1) les arbres binaires quilibtis.
SINON SI j>i Un B-arbre nest jamais binaire. Un nud possde au plus 2*d+l successeurs
ALORS k:=(i+j)/2; X:=~I; pl:=pl+l ; val[x]:=v[k]; et 2*d tiquettes, o d est la densit du B-arbre. Ce sont des arbres ordonns et
sg[x]:=arb(i,k-1); sd[x]:=arb(k+l,j); quilibrs. Dans le vocabulaire des B-arbres, le terme quilibr& se dfinit de la
RETOURNER x manire suivante : la longueur dun chemin de la racine jusqu une feuille est la
SINON RETOURNER 0 mme, quelque soit la feuille. Nous prsentons ici les B-arbres les plus simples,
FINSI avec d=l, cest--dire que chaque nud comporte au plus deux tiquettes (les valeurs
FINSI du paragraphe pr&dent, appeXes cls dans le langage des bases de donnes) et trois
FINPROC; successeurs. La figure 8.6 montre un tel B-arbre, complet deux niveaux (8
racine:=arb(l ,n) &iquettes pour 4 nuds).
FIN

Programme 8.2. Arbre quilibr

La procCdure arb procbde par dichotomie, en retournant lindex de la racine de


larbre quelle cre. Elle cn5e un arbre quilibr avec les valeurs v[i]..vu]. Si i=j,
lunique valeur est insr6e dans un nouveau nud, qui est en fait une feuille. Si icj,
Figure 8.6. Un B-arbre complet avec d=l
lindex mdian k est calcul. Un nud est cr pour VF]. Les successeurs de ce nud
sont calcul& par des appels de arb avec les valeurs a gauche de k, puis les valeurs B
droite. On retourne lindex du nud cr&. Enfin, si i>j, aucun lment nest insrer,
Par ailleurs, on applique la rbgle quun B-arbre doit tre rempli au moins
donc la procda retourne la valeur 0 (successeur vide).
50%, ce qui revient dire, pour d=l, que chaque noeud comporte au moins une
tiquette. Un nud qui nest pas une feuille a au moins deux successeurs. Pour
Le problme se corse quand on dispose dun arbre quilibr6 et que lon veut y
comprendre la faon de construire un B-arbre, ou de rechercher un objet, prenons
insrer un nouvel objet. Lopration est intrinsquement coteuse, les algorithmes
lexemple de larrive dobjets dans lordre le plus difficile, soit des objets comportant
directs &ant particuli&rement lourds.
des tiquettes 1,2,3, . . . Les tiquettes 1 et 2 se logent dans la racine (figure 8.7).

8.3. Les B-arbres

La minimisation du nombre de noeuds a examiner pendant le parcours dun Figure 8.7. Aprs lecture des 1 et 2
arbre est particulirement intressante pour la recherche dun fichier a travers le
catalogue tenu par le syst&me dexploitation, ou pour les accs a des objets dans des A la lecture du trois, il faut introduire un nouveau niveau, car la racine est
bases de donnes. En effet, dans ces cas, chaque examen dun nud peut ncessiter pleine (figure 8.8).

138 139
fiLOORIlWMIQUE ET PROGRAMhhWON &GORlIFMQUE ET PROGRAMh4tUTON

Le 7 a fait clater le nud qui contenait 5 et 6. Il ny avait pas de place pour le


6 dans le nud au-dessus, qui contenait dj 2 et 4. A son tour, ce nud clate,
provoquant larrive dune nouvelle racine. Cela augmente la profondeur de larbre.

Figure 8.8. Aprs lecture du 3 Notons que la profondeur augmente toujours par ladjonction dune nouvelle
racine. Cette propriet assure la continuite de la dfinition de B-arbre, o chaque
feuille est la mme distance de la racine. Les noeuds sont galement remplis 50%
Le 4 peut sajouter dans la feuille qui contient dj le 3. Mais larrive du dans le plus mauvais des cas, car chaque nud cr reoit toujours une tiquette. La
5 provoque nouveau un bouleversement, car on voudrait rajouter dans ce mme figure 8.10 montre les limites de lalgorithme simple, car larbre comporte trois
noeud. Comme il ny a pas la place pour une troisime tiquette, le 5 provoque niveaux pour un ensemble dtiquettes qui nen ncessite que deux. Cela rsulte du
lclatement du nud comportant le 3 et le 4. Lclatement consiste en la choix de donnes de dpart, o nous avons considr lordre le plus mauvais. Le
remonte de ltiquette intermdiaire (dans ce cas le 4), en crant deux nouveaux rsultat est nanmoins tout fait acceptable, surtout en sachant quun ordre alatoire
noeuds pour les tiquettes dcentralises (ici 3 et 5). Le rsultat se trouve en figure darrive des tiquettes mne un bien meilleur taux de remplissage des nuds.
8.9.
Dans les bases de donnes, ou dans le stockage de fichiers en gnral, les
Ctiquettes sont des cls dans le sens de ladressage disperse (voir chapitre 2). Sauf
accident, ceci assure une distribution correcte de valeurs. Si lefficacit tait vraiment
critique, on aurait pu viter lintroduction dun nouveau nud dans la figure 8.10.
Rappelons que ltiquette 7 fait clater la case qui contenait auparavant le 5 et le 6.
La monte du 6 fait clater la racine, qui comportait le 2 et le 4. La remonte du 4
cre une nouvelle racine. En fait, il y a une place pour le 4 cte du 3, comme dans
/ la figure 8.11.
Figure 8.9. Aprs lecture du 5
/

On voit que le 4 peut se loger au niveau au-dessus, car le nud comportant


ltiquette 2 nest pas plein. A son tour, le six se logera dans la case qui contient dj
le 5, car il reste un espace. Larrive du 7 va encore provoquer des clatements (figure
8.10).

Figure 8.ll. Rkorganisation pour viter dintroduire un niveau

Il a galement fallu rorganiser le trio 5, 6, 7. On note que retrouver une


organisation optimale est loin dtre trivial. En gnral, on accepte lalgorithme de
base, qui est raisonnable. Des valuations des cots des diffrentes oprations se
trouvent en [Bayer 19721, [Knuth 19731, [Aho 19741.

Le programme 8.3 recherche une valeur dans un B-arbre, en lintroduisant dans


Figure 8.10. Aprs lecture du 7 larbre si elle ny est pas encore.

140 141
I

i t

DONNEES sg, SC, sd, valg, vald, pred: TAB [1 ..taille] DE entier; La complexiti de cet algorithme montre le travail faire pour mettre en route
v , racine: entier; ce genre de technique. Le programme qui restructure un B-arbre pour lui donner une
DEBUTVAR n. pos. orph, nn: entier; repr&entation optimale est encore plus difficile. Un traitement complet de ces
fini, trouve: bool;
h:=racine; trouti:= v=valg[n] OU v=vald[n]; 1 problkmes dpasse la port& de cet ouvrage.
TANTQUE sg[r+O ET NON trouve
FAIRE SI vsvalg[nl
ALORS n:=sg[n] I 8.4. Exercices
SINON SI v>vald[n] ET vald[n]>O
ALORS n:=sd[n]
SINON n:=sc[n] 1. Ecrire un programme qui dcide si un arbre binaire donn est ordonn.
FINSI
FINSI;
trouv:= v=valg[n] OU v=vald[n] l 2. Ecrire un programme qui dcide si un arbre binaire donn est quilibr.
FAlT;
SI NON trouv
ALORS orph:=O; fini:=FAUX;
mNTQUE NON fini
FAIRE SI vald[n]=O
ALORS fini:=VRAl;
SI n=O
ALORS nnxouveau-nud; sg[nn]:=racine; sc[nn]:=orph;
sd[nn]:=O; pred(nn]:=O; valg[nn]:=v; vald[nn]:=O;
pred[racine]:=nn; pred(orph]:=nn; racine:=nn
SINON SI v>valg[n]
ALORS vald(n]:=v; sd[n]:=orph
SINON vald[n]:=valg[n]; valg[n]:=v; sd[n]:=sc[n];
sc[n]:=orph
FINSI
FINSI
SINON nn:=nouveau noeud:
SI v<valg[n] -
ALORS Bchange(v,valg[n]); pos:=l ; valg[nn]:=vald[n]
SINON SI v>vald(n] ET vald[n]>o
ALORS valg[nn]:=v; v:=vald[n]; pos:=2
SINON valg[nn]:=vald[n]; pos:=3
FINSI
FINSI;
vald[n]:=O; pred[nn]:=pred[n];
CAS pos
DANS 1: sc[nn]:=sd[n]; sg[nn]:=sc[n]; sc[n]:=orph,
2: sg[nn]:=sd[n]; sc[nn]:=orph,
3: sg[nn]:=orph; sc[nn]:=sd[n]
FINCAS;
sd(n]:=O; sd[nn]:=O; n:=pred[n]; orph:=nn
FINSI
FAlT
FINSI
FIN

Programme 8.3. B-urbres

142 143
Bibliographie et rfrences

CACM : Communications of the Association for Computing Machinery


JACM : Journal of the Association for Computing Machinery
LNCS : Lecture Notes in Computer Science
AHD A.V., HOPCROET J.E., ULLMANN J.D., The design and analysis of computer
algorithms, Addison Wesley, 1974.
AK) A.V., HOPCROFT J.E., ULLMANN J.D., Data structures and algorithms, Addison
Wesley, 1983.
&SAC J., Premires leons de programmation, CEDIC/Fernand Nathan, 1980.
kSAC J., Les bases de la programmation, Dunod, 1983.
ARSAC J., La conception des programmes, Pour la science, numro spcial 85,
novembre 1984, (dition franaise de Scientific American).
BAWR EL., EI~K~. J., (eds.), Advanced course in compiler construction, Springer
Verlag, LNCS 21, 1974.
BAVER F.L., (ed.), Software engineering, Springer Verlag, LNCS 30, 1975.
BAUI!R EL., Samekon K., (eds.), Language hierarchies and interfaces, Springer
Verlag, LNCS 46, 1976.
BAUFR EL., BROY M., (eds.), Program construction, Springer Verlag, LNCS 69,
1979.
BAYER R., Binary B-trees for virtual memory, Proc. ACM-SIGFZDET Workshop,
New York, 197 1.
I
BP;YER R., Mc G~GB~ E., Grganisation and maintenance of large ordered indexes,
Acta Informatica 1,3, p. 173-189, 1972.
Bmoux P., B IZARD Ph., Algorithmique : construction, preuve et &Valuation des
programmes, Dunod, 1983.
BJZEXT D., MONET P., Les tours dHanoi, ou comment changer de disques, OI,
janvier 1985.
&GORlTHhtlQUEJZTPROGRAhfhMTON

BEZEL Max, Schach zeitung, 1848. m D.E., The art of computer programming, vol. 3 : Sorting and searching,
BOUSSARD J.-C., MAHL. R., Programmation avance : algorithmique et structures Addison Wesley 1973.
de donnees, Eyrolles, 1983. LEDGARD HF., Programmingproverbs, Hayden, 1975, traduit en franais par
BROWN P.J., (ed.), Software portability, Cambridge university press, 1977. ARtSAC J., Proverbes de programmation, Dunod, 1978.
B~JRSXU R.M.,DARUNcrroN J., Some transformations for developping recursive LUCAS M., PEYRIN J.-P., SCHO~ P.C., Algorithmique et reprsentation des
programs, SIGPLAN notices 10, 6, juin 1975. donnes, 1 - Files, automates dtats finis, Masson, 1983a.
CARRoLL L., Symbolic logic, part 1 : elementary, Macmillan 1896, traduit en LUCAS M., Algorithmique et reprtsentation des donnes, 2 - Evaluations, arbres,
franais par GHIXNO J. et COUMIZ E., La logique sans peine, Hermann, graphes, analyse de textes, Masson, 1983b.
1966. Mc Cm J., Recursive computations of symbolic expressions and their
COUR~ J., KWARSKI I., Initiation h lalgorithmique et aux structures de donnes, computation by machine, part 1, CACM 3, 4, avril 1960.
1 - programmation structure et structures de donnes lmentaires, 2 - MEYHZ B., BAUDOIN C., Mthodes de programmation, Eyrolles, 1978.
rcursivit et structures de donnes avances, Dunod, 1987. MIR~NDA S., BUS-~A J.-M., Lart des bases de donnes, Tome 1 : Introduction aux
Cm P.Y., GRIFFITHS M., S~BOU P.C., Construction mthodique et vrification bases de donnes, Eyrolles 1987.
systmatique de programmes : lments dun langage, Congrs AFCET, OXUSOFF L., RAIXY A., Lvaluation smantique en calcul propositionnel, thses,
novembre 1978. Luminy, janvier 1989.
CUNIN P.Y., G-S M., VOIRON J., Comprendre la compilation, Springer PACLFT Ph., Aventures en noir et blanc, J&S no 26, p. 28-30, avril-mai 1984.
Ver&, 1980. QUINJZ W.V.O., Methods of logic, Holt, Rinehart & Winston, 1950, traduit en
DARLING-~~N J., B-AU R.D., A system which automatically improves franais par CLAVELIN M., Armand Colin, 1972.
programs, 3rd. conf on arhjkial intelligence, Stanford, aot 1973. SAMUEU A.L., Some studies in machine leaming using the game of checkers,
DUKSTRA E.W., A discipline of programming, Prentice Hall, 1976. IBM jnl. of res. and dev., 3, 1959, rimprim dans [Feigenbaum 19631.
FEIGENBAUM E.A., FE%DMAN J., (eds.), Computers and thought, McGraw Hill, SCHOU P.C., Algorithmique et reprsentation des donnes, 3 - rcursivitt et arbres,
1963. Masson, 1984.
GAUSS Carl, 1850, (lettre du 2/9). SCHORR H., WABE W.M., An efSicient machine independentprocedure for garbage
GERBIER A., (nom collectif), Mes premires constructions de programmes, Springer collection in various list structures, CACM, aot 1967.
Verlag, LNCS 55, 1977. SIEC~, P., Reprsentation et utilisation de la connaissance en calcul propositionnel,
GMGRASSO V.M., GIRZI T., Projet DU-II, Universite Aix-Marseille III, 1989. thse, Luminy, 1987.
GREGOIRE, (nom collectif), Informatique-programmation, tome 1 : la programmation SMUUYAN R., The lady or the tiger, Knopf 1982, (traduit en franais par MARIHON
structuree, tome 2 : la spcification rcursive et lanalyse des algorithmes, J., Le livre qui rendfou, Dunod, 1984).
Masson, 1986, 1988. WARSHALL S., A theorem on Boolean matrices, JACM 9, 1, janvier 1962.
GRIES D., The Schorr-Waite marking algorithm, dans [Bauer 19791. Wl~m N., Algotithms + Data Structures = Programs, Prentice Hall, 1976.
GRIES D., The science of programming, Springer Verlag, 1981. WIRM N., Systematic programming : an introduction, Prentice-Hall, 1973, (traduit
GRIFFTIHS M., Analyse dterministe et compilateurs, thse, Grenoble, octobre 1969. en franais par LECARME O., Introduction la programmation systmatique,
GFUFRTHS M., Program production by successive transformation, dans [Bauer 19761. Masson 1977).
GRIFFITHs M., Development of the Schorr-Waite algorithm, dans [Bauer 19791.
GRIFFITHs M., Mthodes algorithmiques pour 19ntelligence artificielle, Hem&,
1986.
GRIFFUHS M., PALI~~ER C., Algorithmic methods for artificial intelligence,
Herrds, 1987.
GRIFFITHS M., VAYS!%DE M., Architecture des systmes dexploitation, Herms,
1988.
m D., Antiquit binaire : la multiplication gyptienne, OI no 54 bis,
dcembre 1983.
J&S, Qui est mcanicien ?, Jeux et stratgie 26, p. 84, avril-mai 1984.

146 147
fiLOORlTHh4IQUB III- PROGRAhfMKl-ION

Graphe Graph 4
Infix Infixed 4.3.4
Iuvariant Invariant 2.2.1
Largeur dabord Breadth first search 4.3.4
Marche arrire Backtracking 6
Nud 4.3
OUALORS COR 2.2.2
Glossaire Pile Stack ou LIFO 3.4.1
Post-condition Postcondition 2.2.1
Postfix Postfured 4.3.4
Pr&condition Precondition 2.2.1
I ,
predecessellr Predecessor 4.3
Prfix Prefixed 4.3.4
Producteur Ph.llXI 4.2
1. Franais - anglais Profondeur dabord Depth first search 4.3.4

Adressagedisperse Hash code 2.5 Racine Root 4.3


Adne TiW? 4 Ramasse-miettes Garbage collection 4.5.1
Arbre quilibti Balancedtree 8 Rcurrence Induction 5
Arbre OdOM ordedtree 8 Rcursivit Recursion 5
Assertion Assertion 2.4 Schma de programme Program scheme 2.4
B-arbre B-tree 8 Schorr-Waite 4.5.1
Branche Branch 4.3 Spcification Specification 2.4
Successeur Successor 4.3
CHOIX CHOICE 2.2.3
ClasSe Class 2.5 Treillis Lattice 4
Cl Key 2.5 Tri Sort 3
Consommateur Consumer 4.2
Dpiler Pull 4.1 2. Anglais - franais
Diagramme de vigne Vine diagram 4.3.1
Diviser pour rgner Divide and conquer 2.3 Assertion Assertion 2.4
Empiler Push 4.1 B-Tiee B-arbre 8
Etat du monde State of the world 2.1.1 Backtracking Marche arriere 6
ETPUIS CAND 2.2.2 Balancedtree Arbre quilibn5 8
Fermeture transitive Transitive closure 4.5.4 CAND ETPUIS 2.2.2
Feuille 4.3 CHOICE CHOIX 2.2.3
File Queue ou FIFO 4 Class Classe 2.5
FINCHOIX ENDCHOICE 2.2.3 Consumer Consommateur 4.2
COR OUALORS 2.2.2

149
Divide and conque1 Diviser pour rgner 3.3 Solutions de quelques exercices
ENDCHOICE FINCHOIX 2.2.3
FIFO File 4
Garbage collection Ramasse miettes 4.5.1
Graph Graphe 4
Hash code Adressage disperse 2.5 CHAPITRE 2
Induction Rcurrence 5
Question 1
Invariant Invariant 2.2.1
Cl Voir chapitre 7.
Key 2.5
Lattice Treillis 4 Question 2
LIFO Pile 4.4.1
Arbre ordonn 8 Supposons que nous arrivons dans la situation suivant :
Postcondition Post-condition 2.2.1 objet=15, bas=centre=7, haut=8, t[T=lO, t[8]=20
Precondi tion Pr-condition 2.2.1
Pmducer Producteur Alors, lobjet nest pas trouv et t[centre]cobjet. La prochaine valeur de centre
4.2 i
Program scheme Schma de programme sera entier((7+8)/2), cest-Mire 7. Lalgorithme boucle.
2.4
Pull Dpiler 4.1
Push Empiler 4.1
CHAPITRE 3
Queue File 4 t
Recursion Rcursivit 5 l Question 1

Schorr-Waite 4.5.1 DONNEES n: entier;


sort Tri 3 t: TABLEAU [O..n] DE entier;
Specification Spcification 3.4 PRECOND n>O;
Stack Pile 4.4.1 DEBUT VAR i, j, temp: entier;
Transitive closure Fermeture transitive MONDE i: t[l ..i] est tri;
4.5.4
Tm i:=l ; t[O]:= - maxint
4
TANTQUE i<n
Vme diagram Diagramme de vigne 4.3.1 FAIRE i:=i+l ;
MONDE j est la position du trou,
temp:=t[i]; j:=i;
TANTQUE j>l ET t[i-l]>temp
FAIRE tjjj:=tjj-11; j:=j-1
FAIT;
t[j]:=temp
FAIT
FIN
POSTCOND t[ 1 ..n] est tri

150 !
fiLGORITHMlQUFifTPROGRAMMATION

Le problme vient du fait que quand j=l, tu-11 nexiste pas. On cre un t[O], PROC cousin_germain(a, b: chaine(8), n: entier) -> (bool, entier, entier):
fictif, en linitialisant au plus petit entier ngatif. En fait, cette initialisation nest SI n=O
pas ncessaire, car si t[O] est tifrence, il nest plus vrai que j> 1. , ALORS RETOURNER (FAUX, 0)
SINON SI ((val[sg[sg[n]]=a OU val[sd[sg[n]]=a)
ET (val[sg[sd[n]]=b OU val[sd[sd[n]]=b))
CHAPITRE 4 OU ((val[sg[sg[n]]=b OU val[sd[sg[n]]=b)
ET (val[sg[sd[n]]=a OU val[sd[sd[n]]=a))
Question 1 ALORS RETOURNER VRAI
FINSI;
PROC trouver(nom: chaine(8), n: entier) -> (bool, entier): SI cousin_germain(a, b, sg[n])
VAR b: bool, x: entier; ALORS RETOURNER VRAI
SI n=O SINON RETOURNER cousin_germain(a, b, sd[n])
ALORS RETOURNER (FAUX, 0) FINSI
SINON SI val[n]=nom FINSI
ALORS RETOURNER (VRAI, n) FINPROC
SINON (b, x):= trouver(nom, sg[n]); 1
SI b PROC aeul(a, enf, n) -> bool:
ALORS RETOURNER (b, x) VAR b:. bool, x, y: entier;
SINON RETOURNER trouver(nom, sd[n]) (b, x):=trouver(a, n);
FINSI 4 SI b
FINSI ALORS (b, y):=trouver(enf, x); RETOURNER b
FINSI FINSI
FINPROC FINPROC

PROC parent(p, enf: chaine(8), n: entier) -> (bool, entier): REMARQUE. - Cette version suppose quun nom ne peut figurer quune fois dans
VAR b: bool, x: entier; larbre. Elle nassure pas limpression, qui pose le problme particulier de lordre
SI n=O dimpression demand. Supposons une prockdure trouver-bis, qui comporte un ordre
ALORS RETOURNER (FAUX, 0) dimpression. Alors les rsultats seraient imprims avec les noms des enfants avant
FINSI: ceux de leurs parents. Le plus simple est dempiler le nom lintrieur de la
SI val[n]=p procdure (dans une pile globale) et dimprimer la pile la fin du programme.
ALORS SI val[sg[n]]=enf OU val[sd[n]]=enf
ALORS RETOURNER (VRAI, n)
FINSI Question 3
FINSI;
(b, x):= trouver(p, enf, sg[n]); Un tel arbre comporte (2-1) noeuds et 2- feuilles.
SI b
ALORS RETOURNER (b,x)
SINON RETOURNER parent(p, enf, sd[n]) I CHAPITRE 5
FINSI
FINPROC Question 1

Le nombre de dplacements est 2@ - 1 (voir $5.1.1)

152 153
fiLGONMMIQLJE JT PROGRAMhfATION

2 - 1 secondes = 18446744073709551615 secondes - perm: TABLEAU (1 :n) DE integer INIT 1;


= 307445734561825860 minutes 15 secondes nn:=n;
= 5124095576030431 heures 15 secondes TANTQU E nn> 1
= 213087315667934 jours 15 heures + . . . FAIRE (p,q):=i DIVPAR nn;
= 5 838 008 664 843 annes 239 jours + . . . SI q=O ALORS p:=p-1 ; q:=nn FINSI;
j:=n+l ;
(avec lanne 365 jours, cest-Mire sans prendre en compte les annes bissextiles). TANTQUE q> 1
En arrondissant a 5 800 milliards dannes, on voit que la fin du monde nest FAIRE j:=j-1;
pas pour demain. Le rsultat est un bel exemple de lexplosion combinatoire. TANTQUE perm(j)>l FAIRE j:=j-1 FAIT;

FAIT q:=q-l
Question 3 perm(j):=nn; nn:=nn-1; i:=p+l
FAIT
Lordre est invers a chaque changement de disque, cest--dire que 4 fait des
cercles dans le sens oppose celui de d, et, plus grukalement, di tourne dans le
t Question 6
oppos a 4-1.
Ordre alphabtique, toujours pour tirer le i-ieme permutation. Cest la mme
chose en plaant les objets a lenvers
Question 4 ;
TANTQUE n>O
DEBUT DONNEES i: entier; FAIRE n:=n-1 ; (p,q):=i DIVPAR fact(n);
VAR n: entier; SI q=O ALORS p:=p-1; q:=fact(n) FINSI;
n:=l; j:=l;
TANTQUE 2 DIVISE i FAIRE i:=i/2; n:=n+l FAIT TANTQUE perm(j)>O FAIRE j:=j+l FAIT;
FIN TANTQUE j<p
FAIRE j:=j+l ;
i est lindex du coup, n lindex du disque qui bouge coup i. Tous les coups TANTQUE perm(j)>O FAIRE j:=j+l FAIT
impairs sont du disque d,. Pour les impairs, on divise i par deux, en enlevant le FAIT;
disque 1 (passage au monde des 2) . . . Voir le calcul du pivot dans le problme des perm(j):=p+l ; i:=q
permutations. FAIT

Question 5 Question 8

Le pivot marche toujours de droite gauche et on gnre le i-ime permutation Oui. Chacun des fact(n) permutations est diffrente des autres (la relation avec
de n objets la permutation dorigine est bi-univoque). Comme elles sont toutes diffrentes et il y
a le compte . . .

154 155
&GORlTHhfIQUEETPROGRAMhUTION
/
CHAPITRE 6 Question 8

Question 1 DEBUT tab: TAB [i ..5, 1..5] DE entier INIT 0;


occup: TAB [0..16] DE bool INIT FAUX;
Version avec heuristique : i: entier INIT 1; j: entier INIT 0;
p, q, val: entier; marche: bool;
PROCEDURE prochain(dir) RETOURNER entier; TANTQUE i<6
RETOURNER(9 dir=O FAIRE j:=j+l ;
ALORS dirpref(x,y,xf,yf) TANTQUE occup[j] ET je16 FAIRE j:=j+l FAIT;
SINON SI dir=4 SI je16
ALORS 1 ALORS tab[5,i]:=j; occup[j]:=VRAl; p:=5; q:=i; marche:=VRAI;
SINON dir+l TANTQUE p>l ET q>l ET marche
FINSI FAIRE val:=abs(tab[p,q]-tab[p,q-11);
FINSI) SI occup[val]
FINPROC; ALORS marche:=FAUX;
PROCEDURE dirpref(x,y,xf,yf) RETOURNER entier; TANTQUE pc6
RETOURNER(SI xcxf ET y<=yf FAIRE occup[tab[p,q]]:=FAUX; tab[p,q]:=O; \
ALORS 1 p:=p+l ; q:=q+l
SINON SI y<yf ET x>=xf FAIT
ALORS 2 SINON p:=p-1 ; q:=q-1 ; tab[p,q]:=val; occup[val]:=VRAI
SINON SI x>xf ALORS 3 SINON 4 FINSI FINSI
FINSI FAIT;
FINSI) SI marche ALORS i:=i+l ; j:=O FINSI
FINPROC; SINON i:=i-1 ; x:=5; y:=i; j:=tab[5,i];
X:=X~; y:=ys; marque(x,y):=true; dir:=O; empiler(O); TANTQUE y>0
TANTQUE xoxf OU yoyf FAIRE occup[tab[x,y]]:=FAUX; tab[x,y]:=O; x:=x-l; y:=~-1
FAIRE SI prochain(dir)odirpref(x,y,xf,yf) FAIT
ALORS dir:=prochain(dir); FINSI
xn:= CAS dir DANS (x,x+1 ,x,x-l) FCAS; , FAIT
yn:= CAS dir DANS (y+1 ,y,~-1 ,y) FCAS; FIN
SI NON barrire(x,y,dir) ETPUIS NON marque(xn,yn)
ALORS x:=xn; y:=yn; marque(x,y):=vrai;
empiler(dir); dir:=O CHAPITRE 7
FINSI
SINON desempiler(dir); Question 1
SI dir=O
ALORS -- il ny a pas de chemin puiss(a,b): SI b=O
FINSI; ALORS 1
x:= CAS dir DANS (x,x-l ,x,x+1) FINCAS; SINON SI impair(b)
y:= CAS dir DANS (y-l ,y,~+1 ,y) FINCAS ALORS a * puiss(a, b-l)
FINSI SINON puiss(a*a, b/2)
FAIT FINSI
FINSI

156 157
h3ORITHMIQuE IS PROGRAhfhCWlON fiL,GORIT?MQUEJ%TPROGRAhAMKClON

puiss(a,b,res): res:=l ; CHAPITRE 8


TANTQUE b>O
FAIRE SI impair(b) Question 1
ALORS res:=res*a; b:=b-1
FINSI; DEBUT DONNEES taille, racine: entier;
a:=a*a; b:=b/2 sg, sd, val: TAB (1 ..taille) DE entier;
FAIT PROCEDURE ord(n, min, max: entier) RETOURNE bool;
SI n=O
ALORS RETOURNER VRAI
Question 2 SINON SI val(n)>max OU val(n)<min
ALORS RETOURNER FAUX
div2(n) = l/fact(n) SINON RETOURNER(ord(sg(n), min, val(n)-1)
ET ord(sd(n), val(n)+l, max))
diiact(n) = n*ln-7!*(n-4).., FINSI
(n-l) * (n-3) * . . . FINSI
FINPROC;
= SI pair(n) imprimer(ord(racine, - maxint, maxint))
ALORS 2 * (fact(n/2))2 / fact(n) FIN
SINON fact(n) / 2- / (fact((n-1)/2))2
FINSI Question 2
DEBUT DONNEES n: entier; DEBUT DONNEES sg, sd, val: TABLEAU (1 ..taille) DE entier;
VAR div2: entier INITl ; racine: entier;
TANTQUE n>l FAIRE div2:=diWn; n:=n-1 FAIT
VAR x: entier;
FIN
PROC qu(n, poids: entier) RETOURNE bool;
VAR qg, qd: bool;
DEBUT DONNEES n: entier;
pg, pd: entier;
VAR haut, bas, divfact: entier; SI n=O
haut:=1 ; bas:=1 ; ALORS poids:=O; RETOURNER VRAI
TANTQUE n>l I S I N O N qg:=qu(sg(n), p g ) ; eqd:=qu(sd(n), p d ) ;
FAIRE haut:=haut*n; bas:=bas*(n-1); n:=n-2
poids:=pg+pd+l ;
FAIT; RETOURNER (qg ET qd ET abs(pg-pd)<2)
divfact:=haut/bas FINSI
FIN
FINPROC;
imprimer(qu(racine, x))
FIN

1II I Il
la Villette

158 159 1
360243 8
Al hmique et pr
dun enseignement defiv
des tudiants de Ier et 2= cycles universitaires
et dans le cadre de la formation permanente.
II sadresse donc aussi bien aux tudiants
qui dsirent se spcialiser en informatique
quaux professionnels de lentreprise
souhaiteraient acqurir des eiments de rig
en programmation.
A partir des exemples ci
les tours dHanoi), la descr
des diffrentes mtho
dalgorithmes sont proposs. Des exercices avec
ur solution concluent chaque chapitre et
sument lessentiel des points abords.

Vous aimerez peut-être aussi