440
Structures de données et méthodes formelles

Structures de données et méthodes formelles ||

  • Upload
    marc

  • View
    241

  • Download
    8

Embed Size (px)

Citation preview

Page 1: Structures de données et méthodes formelles ||

Structures de donnéeset méthodes formelles

Page 2: Structures de données et méthodes formelles ||

SpringerParisBerlinHeidelbergNew YorkHong KongLondresMilanTokyo

Page 3: Structures de données et méthodes formelles ||

Marc Guyomard

Structures de donnéeset méthodes formelles

Page 4: Structures de données et méthodes formelles ||

Marc GuyomardEnssat IrisaUniversité de Rennes 1Technopole Anticipa6, rue de KerampontBP 8051822305 Lannion Cedex

ISBN : 978-2-8178-0199-5 Springer Paris Berlin Heidelberg New York

© Springer-Verlag France, 2011

Imprimé en France

Springer-Verlag est membre du groupe Springer Science + Business Media

Cet ouvrage est soumis au copyright. Tous droits réservés, notamment la reproduction et la repré-sentation, la traduction, la réimpression, l’exposé, la reproduction des illustrations et des tableaux, la transmission par voie d’enregistrement sonore ou visuel, la reproduction par microfi lm ou tout autre moyen ainsi que la conservation des banques de données. La loi française sur le copyright du 9 septembre 1965 dans la version en vigueur n’autorise une reproduction intégrale ou partielle que dans certains cas, et en principe moyennant le paiement des droits. Toute représentation, reproduc-tion, contrefaçon ou conservation dans une banque de données par quelque procédé que ce soit est sanctionnée par la loi pénale sur le copyright.L’utilisation dans cet ouvrage de désignations, dénominations commerciales, marques de fabrique, etc. même sans spécifi cation ne signifi e pas que ces termes soient libres de la législation sur les marques de fabrique et la protection des marques et qu’ils puissent être utilisés par chacun.La maison d’édition décline toute responsabilité quant à l’exactitude des indications de dosage et des modes d’emploi. Dans chaque cas il incombe à l’usager de vérifi er les informations données par comparaison à la littérature existante.

Maquette de couverture : Jean-François Montmarché

Illustrations de couverture : (Fotolia.com)programming layout © Mike Kiev #11376759circuit imprimé © Sylvie Thenard #8582813Connected shape algorithm © 1xpert #29471089

Page 5: Structures de données et méthodes formelles ||

COLLECTION Télécom

Directeur de la Collection : Pierre-Noël Favennec

COMITÉ SCIENTIFIQUE

Président : Claude Guéguen

Michel Allovon (Orange Labs)Chantal Ammi (Télécom Ecole de management)Annie Blandin (Télécom Bretagne)Jean-Pierre Cocquerez (UTC Compiègne, GDR ISIS)Frédérique de Fornel (ICB Dijon, GDR Ondes)Georges Fiche (APAST Lannion)Alain Hillion (Télécom Bretagne)René Joly (Télécom ParisTech)Henri Maître (Télécom ParisTech)Chantal Morley (Télécom SudParis)Gérard Pogorel (Télécom ParisTech)Gérard Poulain (APAST Lannion)Serge Proulx (UQAM Montreal)Nicolas Puech (Télécom ParisTech)Guy Pujolle (UPMC Paris)Pierre Rolin (Télécom SudParis)Basel Solaiman (Télécom Bretagne)Sami Tabbane (SupCom Tunis)Joe Wiart (Orange Labs)

Page 6: Structures de données et méthodes formelles ||

À Éveline,David, Astrid et ChristopheOrlane, Sirina, Émilie, Vic

. . . I have no objectionwith people feeling more comfortable

with the word “English”replacing the word “mathematics”.I just wonder whether such people

are not assigningthemselves a more difficult task. . .

. . . Je n’ai rien à objecteraux personnes qui se sentent plus à l’aise

quand le mot « français »remplace le mot « mathématiques ».

Je me demande simplementdans quelle mesure ces personnesne se compliquent pas la tâche. . .

J.-R. Abrial, The B-Book, 1996.

Page 7: Structures de données et méthodes formelles ||

PréfaceLe cours de mathématiques pour l’informatique, de même que le cours de

logique des propositions et des prédicats du premier ordre font encore partie dela formation de base des informaticiens. Ainsi les départements d’informatique,dès la création des iut, ont-ils bénéficié d’enseignements de mathématiques pourl’informatique et d’enseignements de logique alors même que la formation duredeux ans et que la plupart des étudiants, il y a 40 ans, ne poursuivaient pasleurs études. Mais, trop souvent, l’utilisation des mathématiques demeure fortlimitée pour ne pas dire absente dans le processus qui mène de la spécificationdu problème à la construction du logiciel. Marc Guyomard présente, dans cetouvrage, une approche de la construction des algorithmes relatifs aux structuresde données, une approche par la preuve. C’est le livre d’un sage ! Sapiens ni-hil affirmat quod non probet. L’auteur délivre à la fois un cours original sur lesstructures de données et une méthode formelle de construction de programmes.Ce livre est au cœur de l’informatique. Il suffit d’y lire les applications des diffé-rentes structures de données, pour constater que l’informatique du XXIe sièclefait un grand usage des structures manipulées dans ce livre. Structures de don-nées et méthodes formelles traite des fondements sans lesquels, malgré la puis-sance actuelle des machines, nous ne disposerions pas des logiciels performantsqui sont à la disposition de tous aujourd’hui. Et ceux qui ont utilisé différentssystèmes d’exploitation bien connus fournis avec les micro-ordinateurs, peuventles donner en exemples de la « loi de Reiser » – appelée sur la Toile « Loi deWirth » alors que N. Wirth ne fait que citer M. Reiser : « Le logiciel ralentitplus vite que le matériel n’accélère. » L’Église catholique en était-elle peut-êtreconsciente en choisissant comme saint patron des informaticiens Isidore de Sé-ville qui, d’après ce que l’on peut lire, répété de nombreuses fois sur la Toile –ce qui n’est pas un gage de vérité 1 même si c’est un critère pour améliorer son« page rank » –, aurait inventé les « tries » (l’une des structures étudiées dansce livre), qui sont appliqués dans son ouvrage célèbre, les Etymologies. Leibnizdisait : Sedemus et calculemus, asseyons-nous et calculons. C’est ce que proposeMarc Guyomard. Son point de départ est une spécification écrite en utilisant lamathématique élémentaire sur les ensembles et les relations ainsi que la logiquedes prédicats (le quoi), spécification à partir de laquelle il dérive – il calcule – lareprésentation des algorithmes (le comment). Il utilise la notation de la méthodeB mise au point par Jean-Raymond Abrial, méthode qui a maintenant fait lapreuve de son intérêt pédagogique et opérationnel. La notation est en grande

1. En fait, comme le note Donald Knuth dans le tome 3 de son monumental The Art ofComputer Programming cité parmi les douze meilleures monographies du siècle par l’AmericanScientist – les « Étymologies » sont ordonnées selon un ordre lexicographique imparfait, portantuniquement sur la première lettre. De là aux tries, il y a un long chemin !. . .

Page 8: Structures de données et méthodes formelles ||

x Structures de données et méthodes formelles

partie celle qu’utilisent couramment les mathématiciens et les logiciens, com-plétée par des symboles fort pratiques. Nous pensons à ce propos qu’il est sansdoute plus profitable d’enseigner une partie des programmes de mathématiquesdans le cadre de l’enseignement de spécification/programmation que d’en fairedes enseignements cloisonnés. L’avantage qui en résulte est de rapprocher l’outil(les mathématiques) de sa principale application (la spécification), compétenceau cœur du métier d’informaticien. Ainsi on peut mettre l’accent sur une activitéessentielle, celle d’abstraction. La méthode B opère par raffinage, afin de passerde l’abstrait (la spécification) au concret (l’algorithme rédigé dans un langageexécutable sur un ordinateur) et à satisfaire en cours de processus, des obliga-tions de preuves, preuves qui peuvent être assistées par des logiciels. Comme ila réutilisé les spécifications ensemblistes et la logique, Marc Guyomard réutilisele modèle fonctionnel en programmation, modèle très souvent enseigné à justeraison, et il l’applique lors de la dérivation de programmes au lieu d’appliquerle cadre algorithmique. Voilà sur quoi repose l’originalité de la démarche pré-sentée et appliquée par Marc Guyomard dans ce livre. Il a renouvelé le fameux« structure de données + algorithmes = programmes » de N. Wirth en énon-çant « spécifications + fonction d’abstraction + calcul = programme ». Il luirestait à choisir quelles structures de données présenter et dans quel ordre. Ila choisi une perspective historique, perspective trop peu souvent utilisée dansles enseignements d’informatique où l’on a parfois tendance à considérer qu’unebibliographie de plus de 5 ans d’âge n’a pas sa place dans une publication. Nousavions été séduit par les remarquables polycopiés de Marc Guyomard, en parti-culier un cours sur la compilation et un autre sur la construction de la boucle.C’est avec plaisir que nous avons appris que Marc Guyomard allait diffuser soncours sur les structures de données qu’il dispense aux étudiants de l’Enssat deLannion. Je suis sûr que les enseignants, les étudiants, les praticiens apprécierontce livre qui leur fournit à la fois, une présentation raisonnée de très nombreusesstructures de données, bien plus que ce que l’on trouve habituellement dans leslivres comparables, et une méthode originale de développement de programmesfondé sur la preuve. Toutes les notions et les notations nécessaires pour suivrel’exposé sont présentées, lorsque le besoin s’en fait sentir, Structures de donnéeset méthodes formelles est un livre que les programmeurs doivent avoir à portéede la main.

Henri HabriasProfesseur émérite à l’Université de Nantes

Page 9: Structures de données et méthodes formelles ||

Table des matières

Préface ix

Avant-propos 1

I Les bases 13

1 Mathématiques pour la spécification et les structuresde données 151.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.2 Raisonnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.3 Calcul propositionnel . . . . . . . . . . . . . . . . . . . . . . . . . 211.4 Calcul des prédicats . . . . . . . . . . . . . . . . . . . . . . . . . 22

1.4.1 Quantification universelle . . . . . . . . . . . . . . . . . . 221.4.2 Deux nouveaux types d’expressions . . . . . . . . . . . . . 25

1.5 Égalité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261.6 Théorie des ensembles . . . . . . . . . . . . . . . . . . . . . . . . 27

1.6.1 Opérations ensemblistes traditionnelles . . . . . . . . . . . 291.6.2 Choix dans un ensemble . . . . . . . . . . . . . . . . . . . 301.6.3 Relations binaires . . . . . . . . . . . . . . . . . . . . . . 311.6.4 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

1.7 Ensembles particuliers . . . . . . . . . . . . . . . . . . . . . . . . 361.8 Exemple de modélisation ensembliste . . . . . . . . . . . . . . . . 401.9 Construction de structures inductives . . . . . . . . . . . . . . . . 431.10 Démonstration par récurrence . . . . . . . . . . . . . . . . . . . . 431.11 Opérations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

1.11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 471.11.2 Expression préconditionnée . . . . . . . . . . . . . . . . . 481.11.3 Définition des opérations . . . . . . . . . . . . . . . . . . 481.11.4 Évaluation des opérations . . . . . . . . . . . . . . . . . . 501.11.5 Propagation des préconditions . . . . . . . . . . . . . . . 52

1.12 Conclusion et remarques bibliographiques . . . . . . . . . . . . . 56

Page 10: Structures de données et méthodes formelles ||

xii Structures de données et méthodes formelles

2 Spécifications + Fonction d’abstraction + Calcul = Programme 592.1 Cadre général de la démarche . . . . . . . . . . . . . . . . . . . . 592.2 Formalisme pour les types – Exemple . . . . . . . . . . . . . . . . 612.3 Calcul des opérations – Exemple . . . . . . . . . . . . . . . . . . 64

2.3.1 Calcul d’une représentation de l’opération plus_n . . . . 662.3.2 Calcul d’une représentation de l’opération inf_n . . . . . 68

2.4 Induction, support et renforcement . . . . . . . . . . . . . . . . . 712.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

3 Étude de quelques structures outils 773.1 Listes finies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

3.1.1 Présentation informelle . . . . . . . . . . . . . . . . . . . 783.1.2 Ébauche de construction . . . . . . . . . . . . . . . . . . . 793.1.3 Opérations sur les listes . . . . . . . . . . . . . . . . . . . 823.1.4 Notation linéaire . . . . . . . . . . . . . . . . . . . . . . . 82

3.2 Arbres finis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833.3 Arbres non ordonnés . . . . . . . . . . . . . . . . . . . . . . . . . 85

3.3.1 Introduction : les arbres non ordonnés non étiquetés . . . 853.3.2 Arbres non ordonnés étiquetés . . . . . . . . . . . . . . . 85

3.4 Arbres planaires . . . . . . . . . . . . . . . . . . . . . . . . . . . 873.4.1 Introduction : les arbres planaires non étiquetés . . . . . . 873.4.2 Arbres planaires étiquetés . . . . . . . . . . . . . . . . . . 87

3.5 Arbres n-aires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 883.5.1 Introduction : les arbres n-aires non étiquetés . . . . . . . 883.5.2 Les arbres binaires étiquetés . . . . . . . . . . . . . . . . . 89

3.6 Arbres binaires partiellement étiquetés : les arbres externes . . . 963.6.1 Présentation informelle . . . . . . . . . . . . . . . . . . . 963.6.2 Ébauche de construction . . . . . . . . . . . . . . . . . . . 973.6.3 Opérations sur les arbres externes . . . . . . . . . . . . . 983.6.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . 98

3.7 Sacs finis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003.7.1 Présentation informelle . . . . . . . . . . . . . . . . . . . 1003.7.2 Ébauche de construction . . . . . . . . . . . . . . . . . . . 1013.7.3 Opérations sur les sacs . . . . . . . . . . . . . . . . . . . . 1023.7.4 Propriétés des sacs . . . . . . . . . . . . . . . . . . . . . . 103

3.8 Conclusion et remarques bibliographiques . . . . . . . . . . . . . 104

4 Analyse d’algorithmes 1074.1 Notations asymptotiques . . . . . . . . . . . . . . . . . . . . . . . 1084.2 Analyse classique de la complexité

de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1134.2.1 Passage du texte d’une fonction à une équation

récurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144.2.2 Complexité la meilleure, la pire, moyenne . . . . . . . . . 1164.2.3 Résolution d’équations récurrentes . . . . . . . . . . . . . 1174.2.4 Contourner ou simplifier certaines étapes

intermédiaires . . . . . . . . . . . . . . . . . . . . . . . . . 120

Page 11: Structures de données et méthodes formelles ||

Table des matières xiii

4.2.5 Conclusion et remarques bibliographiques . . . . . . . . . 1224.3 Analyse amortie de la complexité –

la méthode du potentiel . . . . . . . . . . . . . . . . . . . . . . . 1234.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 1234.3.2 Fondements théoriques de la méthode du potentiel . . . . 1254.3.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1264.3.4 Conclusion et remarques bibliographiques . . . . . . . . . 128

5 Exemples 1295.1 Premier exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

5.1.1 Spécification du type abstrait . . . . . . . . . . . . . . . 1295.1.2 Définition du support concret . . . . . . . . . . . . . . . . 1305.1.3 Définition de la fonction d’abstraction . . . . . . . . . . . 1305.1.4 Spécification formelle des opérations . . . . . . . . . . . . 1315.1.5 Calcul de la représentation des opérations . . . . . . . . . 1315.1.6 Complexités de l’opération suc_l . . . . . . . . . . . . . . 1355.1.7 Conclusion et remarques bibliographiques . . . . . . . . . 138

5.2 Second exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1395.2.1 Spécification du type abstrait ensnat . . . . . . . . . . . 1395.2.2 Définition du support concret . . . . . . . . . . . . . . . . 1395.2.3 Définition de la fonction d’abstraction . . . . . . . . . . . 1405.2.4 Spécification des opérations concrètes . . . . . . . . . . . 1405.2.5 Calcul d’une représentation de l’opération eAjout_l . . . 1405.2.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . 143

II Structures de données fondamentales :spécification et mises en œuvre 145

6 Ensembles de clés scalaires 1476.1 Présentation informelle . . . . . . . . . . . . . . . . . . . . . . . . 1476.2 Spécification du type abstrait ensabst . . . . . . . . . . . . . . . 1486.3 Méthodes arborescentes : les arbres binaires de recherche . . . . . 150

6.3.1 Définition du support concret . . . . . . . . . . . . . . . . 1506.3.2 Définition de la fonction d’abstraction . . . . . . . . . . . 1516.3.3 Spécification des opérations concrètes . . . . . . . . . . . 1516.3.4 Calcul de la représentation des opérations concrètes . . . 1516.3.5 Conclusion et remarques bibliographiques . . . . . . . . . 168

6.4 Méthodes de hachage . . . . . . . . . . . . . . . . . . . . . . . . . 1696.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 1696.4.2 Définition du support concret . . . . . . . . . . . . . . . . 1716.4.3 Définition de la fonction d’abstraction . . . . . . . . . . . 1726.4.4 Spécification des opérations concrètes . . . . . . . . . . . 1726.4.5 Calcul de la représentation des opérations concrètes . . . 1726.4.6 Fonction de hachage . . . . . . . . . . . . . . . . . . . . . 1756.4.7 Autres méthodes de hachage . . . . . . . . . . . . . . . . 1756.4.8 Conclusion et remarques bibliographiques . . . . . . . . . 177

6.5 Méthodes arborescentes : les arbres externes de recherche . . . . 178

Page 12: Structures de données et méthodes formelles ||

xiv Structures de données et méthodes formelles

6.5.1 Définition du support concret . . . . . . . . . . . . . . . . 1786.5.2 Définition de la fonction d’abstraction . . . . . . . . . . . 1796.5.3 Spécification des opérations . . . . . . . . . . . . . . . . . 1796.5.4 Calcul de la représentation des opérations concrètes . . . 1796.5.5 Renforcement du support par décomposition de la fonction

max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1876.5.6 Conclusion et remarques bibliographiques . . . . . . . . . 190

6.6 Méthodes équilibrées : les Avl . . . . . . . . . . . . . . . . . . . 1916.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 1916.6.2 Définition et propriétés du support concret . . . . . . . . 1926.6.3 Définition de la fonction d’abstraction . . . . . . . . . . . 1966.6.4 Spécification des opérations concrètes . . . . . . . . . . . 1966.6.5 Rotations . . . . . . . . . . . . . . . . . . . . . . . . . . . 1976.6.6 Calcul de la représentation des opérations concrètes . . . 2026.6.7 Renforcement du support par décomposition du rayon . . 2136.6.8 Conclusion et remarques bibliographiques . . . . . . . . . 214

6.7 Méthodes équilibrées : les B-arbres . . . . . . . . . . . . . . . . . 2166.7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2166.7.2 Définition du support concret . . . . . . . . . . . . . . . . 2186.7.3 Définition de la fonction d’abstraction . . . . . . . . . . . 2276.7.4 Spécification des opérations concrètes . . . . . . . . . . . 2286.7.5 Calcul de la représentation des opérations concrètes . . . 2286.7.6 Conclusion et remarques bibliographiques . . . . . . . . . 243

6.8 Structures autoadaptatives et analyse amortie :les arbres déployés . . . . . . . . . . . . . . . . . . . . . . . . . . 2456.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2456.8.2 Principe de l’insertion dans un arbre déployé . . . . . . . 2456.8.3 Support concret et fonction d’abstraction . . . . . . . . . 2466.8.4 Calcul de l’opération eAjout_ad . . . . . . . . . . . . . . 2476.8.5 Analyse amortie de l’opération eAjout_ad . . . . . . . . 2516.8.6 Conclusion et remarques bibliographiques . . . . . . . . . 257

6.9 Méthodes aléatoires : les treaps randomisés . . . . . . . . . . . . 2586.9.1 Définition du support concret . . . . . . . . . . . . . . . . 2586.9.2 Définition de la fonction d’abstraction . . . . . . . . . . . 2596.9.3 Spécification des opérations concrètes . . . . . . . . . . . 2606.9.4 Calcul de la représentation des opérations concrètes . . . 2606.9.5 Renforcer ou non le support ? . . . . . . . . . . . . . . . . 2686.9.6 Treaps randomisés . . . . . . . . . . . . . . . . . . . . . . 2686.9.7 Conclusion et remarques bibliographiques . . . . . . . . . 270

7 Ensembles de clés structurées 2737.1 Ensembles de chaînes, représentation par tries . . . . . . . . . . . 273

7.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2737.1.2 Définition des supports concrets . . . . . . . . . . . . . . 2747.1.3 Définition des fonctions d’abstraction . . . . . . . . . . . 2767.1.4 Spécification des opérations concrètes . . . . . . . . . . . 2777.1.5 Calcul de la représentation des opérations concrètes . . . 277

Page 13: Structures de données et méthodes formelles ||

Table des matières xv

7.1.6 Variantes des tries . . . . . . . . . . . . . . . . . . . . . . 2867.1.7 Conclusion et remarques bibliographiques . . . . . . . . . 291

7.2 Ensembles de couples, représentation par kd-arbres . . . . . . . . 2937.2.1 Ensembles de couples, spécification abstraite . . . . . . . 2937.2.2 Ensembles de couples, introduction aux kd-arbres . . . . . 2957.2.3 Définition du support concret . . . . . . . . . . . . . . . . 2967.2.4 Définition de la fonction d’abstraction . . . . . . . . . . . 2987.2.5 Spécification des opérations concrètes . . . . . . . . . . . 2987.2.6 Calcul d’une représentation des opérations concrètes . . . 2997.2.7 Conclusion et remarques bibliographiques . . . . . . . . . 309

8 Files simples 3138.1 Présentation informelle des files simples . . . . . . . . . . . . . . 3138.2 Spécification du type abstrait fileabst . . . . . . . . . . . . . . 3148.3 Mise en œuvre « chaînée » . . . . . . . . . . . . . . . . . . . . . . 315

8.3.1 Définition du support concret . . . . . . . . . . . . . . . . 3188.3.2 Définition de la fonction d’abstraction . . . . . . . . . . . 3188.3.3 Spécification formelle des opérations . . . . . . . . . . . . 3188.3.4 Calcul de la représentation des opérations concrètes . . . 3188.3.5 Complexité de la mise en œuvre chaînée . . . . . . . . . . 3228.3.6 Conclusion et remarques bibliographiques . . . . . . . . . 324

9 Files de priorité 3279.1 Présentation informelle . . . . . . . . . . . . . . . . . . . . . . . . 3279.2 Spécification du type abstrait fpabst . . . . . . . . . . . . . . . 3289.3 Méthodes équilibrées : les tas . . . . . . . . . . . . . . . . . . . . 329

9.3.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3299.3.2 Conclusion et remarques bibliographiques . . . . . . . . . 331

9.4 Méthodes équilibrées : les files binomiales . . . . . . . . . . . . . 3319.4.1 Définition des supports concrets . . . . . . . . . . . . . . 3339.4.2 Définition des fonctions d’abstraction . . . . . . . . . . . 3359.4.3 Spécification des opérations concrètes . . . . . . . . . . . 3369.4.4 Calcul de la représentation des opérations concrètes . . . 3399.4.5 Renforcement du support par décomposition du rayon . . 3589.4.6 Conclusion et remarques bibliographiques . . . . . . . . . 360

9.5 Méthodes autoadaptatives : les minimiers obliques (skew heaps) . 3619.5.1 Définition du support concret . . . . . . . . . . . . . . . . 3629.5.2 Définition de la fonction d’abstraction . . . . . . . . . . . 3639.5.3 Spécification des opérations concrètes . . . . . . . . . . . 3639.5.4 Calcul d’une représentation des opérations concrètes . . . 3639.5.5 Analyse amortie de l’opération fus . . . . . . . . . . . . . 3689.5.6 Conclusion et remarques bibliographiques . . . . . . . . . 373

10 Tableaux flexibles 37710.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37710.2 Flexibilité faible à droite : présentation informelle . . . . . . . . . 37810.3 Flexibilité faible : spécification du type abstrait . . . . . . . . . . 37810.4 Flexibilité faible : mise en œuvre par arbres de Braun . . . . . . 378

Page 14: Structures de données et méthodes formelles ||

xvi Structures de données et méthodes formelles

10.4.1 Flexibilité faible : définition du support concret . . . . . . 38110.4.2 Flexibilité faible : définition de la fonction d’abstraction . 38210.4.3 Flexibilité faible : spécification des opérations concrètes . 38410.4.4 Flexibilité faible : calcul des opérations concrètes . . . . . 38510.4.5 Décomposer la fonction w ? . . . . . . . . . . . . . . . . . 39110.4.6 Conclusion et remarques bibliographiques . . . . . . . . . 391

10.5 Flexibilité forte : présentation informelle . . . . . . . . . . . . . . 39410.6 Flexibilité forte : spécification du type abstrait tsabst . . . . . . 39510.7 Flexibilité forte : mise en œuvre par minimiers . . . . . . . . . . 395

10.7.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39510.7.2 Conclusion et remarques bibliographiques . . . . . . . . . 398

Annexes – Répertoire de propriétés 401

A Propriétés générales des ensembles 403

B Propriétés des relations binaires 405

C Propriétés des fonctions 411

D Propriétés des entiers 413

E Opérateurs et priorités 415

Bibliographie 417

Index 425

Page 15: Structures de données et méthodes formelles ||

Avant-propos

Un de plus ! Un ouvrage de plus sur les structures de données ! Mais pour-quoi diable ? Tout a été dit et écrit dans ce domaine. En témoignent les centainesde livres publiés depuis l’avènement de l’informatique. C’est peut-être la réflexionque se fait le lecteur en ce moment. Pourtant il lui suffit de feuilleter l’ouvragequ’il tient entre ses mains pour constater que le présent livre se démarque de laplupart de ses homologues : il est émaillé de nombreuses formules, de démons-trations, de programmes qui ne sont rédigés ni en C ni en Java ni en Perl. C’estque l’informatique logicielle est engagée depuis quelques décennies déjà dans unprocessus irréversible de rationalisation. Elle a d’ores et déjà acquis le statut descience. C’est particulièrement visible à travers les avancées régulières de ce qu’ilest convenu d’appeler les « méthodes formelles pour le génie logiciel ». Cetteapproche de l’informatique a déjà fait de nombreux adeptes dans l’industrie,notamment pour la réalisation de systèmes critiques (transports, énergie, méde-cine, télécommunications, etc.). En ce qui concerne l’enseignement, en général lesformations du supérieur incluent dans leur offre pédagogique un module sur cethème. Nous sommes donc engagés sur la bonne voie, mais nous pouvons main-tenant aller plus loin. Les méthodes formelles peuvent et doivent sortir de leurGhetto. L’esprit et la lettre des méthodes formelles sont aujourd’hui à mêmed’être diffusés dans la quasi-totalité des domaines de l’informatique logicielle.C’est ce que nous tentons de démontrer ici pour ce qui concerne les structuresde données.

Trois engagementsJouons carte sur table. Cet ouvrage sur les structures de données est fondé

sur un certain nombre de partis pris et n’est pas neutre didactiquement parlant.Mais nous sommes convaincu que celui qui décide d’adhérer aux principes quisont défendus ici sera rapidement récompensé et trouvera autant de plaisir quel’auteur à les pratiquer puis à les transmettre.

De la spécification à la représentation

Le premier principe vers lequel nous nous sommes engagé est celui d’uneséparation entre la notion de spécification et celle de représentation (ou miseen œuvre) des structures de données et des algorithmes qui les accompagnent.Certes ceci n’est pas nouveau. Beaucoup d’auteurs manifestent un intérêt pour

Page 16: Structures de données et méthodes formelles ||

2 Structures de données et méthodes formelles

distinguer le « quoi » du « comment ». Il suffit pour s’en convaincre de consulterla plupart des ouvrages portant sur le même sujet pour y découvrir un premierchapitre, ou une annexe, consacré à la présentation de la logique des prédicats età la théorie des ensembles, outils de base à l’expression du « quoi ». Et puis. . . Etpuis en général cela s’arrête là. Comme si ces auteurs pressentaient l’importancede ces notions et de leurs liens intimes avec le domaine des structures de donnéesmais ne souhaitaient pas, ou ne parvenaient pas à les exploiter dans la pratique.Notre approche est beaucoup moins timide puisque nous ne proposons rien demoins que de calculer (ou dériver) la représentation des algorithmes à partird’une spécification qui est essentiellement ensembliste.

Le modèle fonctionnel pour les structures de données

Le second engagement que nous prenons dépend d’une certaine façon dupremier. Il s’agit de l’utilisation du modèle fonctionnel de programmes et dedonnées. La démarche calculatoire est connue et appliquée depuis longtemps enprogrammation impérative (cf. [30, 31, 45, 24]). Le mariage du modèle fonction-nel avec l’approche calculatoire fait émerger une synergie appréciable tant pourla simplicité et le naturel des calculs réalisés que pour la qualité des programmesproduits.

La perspective chronologique

« Qui ignore l’histoire est condamné à la revivre » affirme un philosophedu XIXe siècle. Cela reste vrai même pour la petite histoire des structures dedonnées. Celle-ci peut être observée à travers le prisme d’une course-poursuiteentre recherche d’efficacité et recherche de simplicité. La période des pionniers vades origines de la programmation (aux alentours des années 1950) jusqu’au tour-nant des années 1960. Elle voit la naissance des structures de données « naïves »,(pour lesquelles d’ailleurs l’histoire n’a que rarement daigné retenir l’identité desdécouvreurs). En ce qui concerne le cas particulièrement caractéristique de la re-présentation des ensembles, on voit apparaître la structure fondamentale qu’estl’arbre binaire de recherche, mais aussi les tables de hachage. La seconde périodeva des années 1960 jusqu’à la fin des années 1970. La pensée dominante est in-carnée par la devise « des structures de données de plus en plus complexes pourune efficacité de plus en plus grande ». C’est l’époque des structures explicite-ment équilibrées. L’obtention d’une efficacité systématique est garantie par uneréorganisation opérée lors des mises à jour et permise par une information ad hocintégrée à la structure et portant sur son état d’équilibre. C’est le règne des Avl,des B-arbres, et de bien d’autres structures semblables dont l’intérêt perdure. Lesdeux périodes suivantes, bien que différentes sur un plan technique, constituentun retour vers la simplicité des origines, retour qui s’accompagne cependant d’unsouci réaffirmé envers de bonnes performances. En quelque sorte on recherchele meilleur des deux premières périodes. À la fin des années 1970, sans doutelassés des gains en efficacité qui s’amenuisent, et qui en outre se payent par unedifficulté inversement proportionnelle à mettre au point des programmes opé-rationnels, des chercheurs entament une double révolution : celle des structures

Page 17: Structures de données et méthodes formelles ||

Avant-propos 3

autoadaptatives et celle de l’analyse amortie de la complexité. Elle se fonde sur leconstat suivant : restructurer systématiquement et aveuglément une structure dedonnées peut parfois permettre d’obtenir une bonne efficacité moyenne, à condi-tion que celle-ci porte sur une séquence d’appels à une opération. C’est le débutde la troisième période, qui voit par exemple l’avènement des arbres déployés(splays trees) ou encore, pour les files de priorité, des minimiers obliques (skewheaps). La quatrième période débute en 1989, par la publication de la premièrestructure de données aléatoires 2 [105]. Certes la notion d’algorithme aléatoireest, à cette date, loin d’être une idée nouvelle. Il semble cependant que personnen’ait précédemment songé à administrer une dose d’aléatoire aux structures dedonnées afin de leur garantir un bon équilibre avec une forte probabilité. Il enrésulte des algorithmes très simples et le plus souvent très efficaces.

Le troisième engagement que nous nous efforçons de respecter est celui del’histoire de la discipline. Les quatre périodes évoquées ci-dessus ont encore ànous apprendre. D’une certaine façon elles se poursuivent toutes les quatre et sesuperposent en partie. Nous avons évité soigneusement d’exposer un cataloguede structures de données. La perspective historique nous permet d’étudier deséchantillons variés autant qu’intéressants de structures de données typiques.

Ces trois engagements transparaissent clairement à travers la lecture de l’ou-vrage et sa structuration. La distinction spécification/représentation est appli-quée à chaque structure de données étudiée. Chacun des cinq types de donnéesétudiés est spécifié formellement. C’est la spécification abstraite. Chacune desstructures de données qui les mettent en œuvre est spécifiée (c’est la spécificationconcrète). Le passage de la spécification concrète des opérations à leur représen-tation s’effectue en utilisant un modèle fonctionnel de calcul. Enfin, pour ce quiconcerne la perspective historique, elle transparaît à travers le choix progressifdes différentes représentations concrètes étudiées.

Motivations

Le corps de cet ouvrage constitue depuis plusieurs années la substance d’uncours sur les structures de données, cours dispensé en première année du cycled’études lsi (Logiciel et Systèmes Informatiques) à l’Enssat (École NationaleSupérieure de Sciences Appliquées et de Technologie, Université de Rennes 1 etUniversité européenne de Bretagne), école d’ingénieurs localisée à Lannion. Cetenseignement a marqué une rupture avec l’approche plus traditionnelle pratiquéeprécédemment. De l’avis des nombreux intervenants, il a aussi constitué uneavancée à travers plusieurs aspects : fondements solides, démarche rigoureuse etprogressive, choix motivés, séparation claire entre ce qui relève de la stratégie etce qui revient au calcul, etc. (cf. [49]). Aucun des enseignants impliqués dans cerenouveau ne souhaite revenir à la situation précédente.

Il nous a semblé intéressant de faire profiter la communauté de notre expé-rience et, sans prétention excessive, de contribuer à faire progresser l’enseigne-ment de cette discipline.

2. Si l’on exclut les techniques de hachage qui, par certains côtés, peuvent se classer danscette catégorie.

Page 18: Structures de données et méthodes formelles ||

4 Structures de données et méthodes formelles

Spécification, raffinement et calculÉtudier les structures de données et les algorithmes qui s’y rattachent fait

depuis toujours partie de la formation de base de l’informaticien. Les approchesclassiques rencontrées dans les ouvrages s’y consacrant se limitent souvent àrépertorier les représentations usuelles, en réservant un chapitre aux listes, unsecond aux arbres, un troisième aux piles, etc.

Pourtant cette forme de présentation ne fait qu’entretenir la confusion quipeut exister entre « type abstrait » (ou spécification de structures de donnéesabstraites) et « type concret » (ou mise en œuvre, ou encore raffinement). Untype de structure de données se construit à partir d’un type (a priori) plusbasique : une file peut se construire à partir d’une liste (ou d’un tableau), unefile de priorité peut se construire à partir d’un arbre binaire, etc. Le type ultimeà partir duquel s’implantent tous les autres est la (les) mémoire(s) adressable(s).

Ce principe est le plus souvent et, à juste titre, ignoré de l’utilisateur. Ill’est aussi parfois, hélas, du développeur. Pourtant nul ne devrait aujourd’huisous-estimer le bénéfice qu’il est possible de retirer de cette connaissance. Enexploitant la relation qui lie un type concret au type abstrait qui lui sert deréférence, il est possible de guider la recherche d’une représentation pour lesopérations accompagnant la structure de données proprement dite et d’obtenirainsi des programmes qui, par construction, sont conformes à leur spécification.C’est l’approche défendue dans cet ouvrage.

Le lecteur déjà familiarisé avec les langages les plus récents peut constater queceux-ci offrent, à travers de volumineuses bibliothèques, un accès à une grandevariété de structures de données dont l’utilisation, à travers des « api » 3, estimmédiate. Pourquoi alors introduire l’étude des structures de données dans lescursus informatiques ? Trois raisons au moins peuvent être avancées :

– En informatique comme ailleurs, la meilleure façon de comprendre les fonc-tionnalités d’un outil est probablement d’en façonner un exemplaire. Lescapacités de l’outil mais aussi ses limites deviennent alors évidentes.

– Malgré le soin que peut prendre le concepteur de la bibliothèque d’un lan-gage à choisir ses structures de données fondamentales, il lui est impossiblede les répertorier toutes. Une nouvelle structure de données se définit par-fois comme la composition de structures de données existantes (tableauflexible de files, files de priorité de tableaux flexibles, etc.). Là, le travail deconception est aisé, celui d’une mise en œuvre efficace ne l’est pas toujours(cf. les ensembles de chaînes du chapitre 7). Mais le plus souvent une nou-velle structure de données est complètement originale ou étend par son jeud’opérations une structure de données préexistante. Il est alors nécessairede faire un travail de définition abstraite et de mise en œuvre concrètesemblable à celui qui est effectué tout au long de cet ouvrage.

– Les structures de données génériques disponibles en bibliothèque sontcertes fonctionnellement bien identifiées. Par contre, en l’absence de normesconcernant les performances, l’utilisateur doit parfois déchanter. Il lui reste

3. api : Application Programming Interface. Sigle consacré pour dénommer l’ensemble desprocédures et des fonctions disponibles pour consulter ou modifier l’état d’une structure dedonnées, d’une application, d’un système d’exploitation, etc.

Page 19: Structures de données et méthodes formelles ||

Avant-propos 5

alors à faire œuvre de concepteur et de développeur. Les connaissances pré-sentées dans cet ouvrage se révèlent alors bien utiles.

Calcul de programmes

Alain dit à sa fille de 8 ans : « Dans deux ans je serai exactement quatre foisplus âgé que toi. Quel est mon âge ? » Voilà un exercice typique de calcul posé enclasse de CM2 et pour la résolution duquel le maître laisse en général libre courtà l’imagination de l’élève. Qui d’entre nous n’a pas été tout à la fois émerveilléet fasciné d’apprendre, quelques années plus tard, qu’il existe une démarchequi, après avoir « mis en équation » l’énoncé et moyennant la connaissance dequelques règles de calcul, permet de répondre sans effort à la question posée ?

C’est en quelque sorte à la prolongation de cette aventure scientifique que cetouvrage nous invite, appliquée à l’informatique et plus précisément aux struc-tures de données. . . Les articles [64, 41, 42] constituent de ce point de vue unbon complément au contenu du présent ouvrage.

Programmation et structures fonctionnelles

Revenons à présent sur l’un des choix qui conditionnent la méthodologieutilisée ici : la programmation fonctionnelle et, par ricochet, les structures dedonnées fonctionnelles. Le principe de la programmation fonctionnelle consisteà considérer qu’exécuter un programme (réaliser un calcul) s’identifie à évaluerdes fonctions (au sens mathématique de ce terme). Les notions classiques d’étatet de changement d’état, qui se traduisent en programmation impérative par lesnotions de variable et d’affectation n’ont donc pas cours.

Strictement parlant, les programmes fonctionnels ne « manipulent » pas de(structures de) données. Ils peuvent les consulter pour en extraire des infor-mations, ils peuvent également les prendre comme argument pour délivrer unenouvelle version, mais ils ne modifient ni ne détruisent une structure de donnéesexistante.

Pour quelles raisons avons-nous réalisé ce choix ? De nombreux argumentspourraient être avancés en sa faveur ou à son encontre. Celui qui a été décisif estla facilité avec laquelle il permet le calcul de programmes. Ce choix a néanmoinsd’autres conséquences que nous passons en revue. Tout d’abord la persistance.La persistance est la propriété que possèdent les programmes fonctionnels de nepas détruire les versions préexistantes d’une donnée tout en rendant disponiblela nouvelle version. Illustrons ce propos à travers l’exemple de la « mise à jour »d’une liste triée, par adjonction d’un élément. Considérons tout d’abord le casclassique des structures éphémères (non persistantes). Soit l la liste triée suivantedans laquelle nous souhaitons insérer la valeur 6 :

•• 2 • 4 • 7 • 9 /l

Passons sur l’aspect algorithmique pour en arriver au résultat : la valeur 6 aété insérée et la cellule qui désignait la valeur 7 a été modifiée, elle désignemaintenant la cellule nouvellement créée. La liste désignée par l est toujourstriée.

Page 20: Structures de données et méthodes formelles ||

6 Structures de données et méthodes formelles

• 2 • 4 • 7 • 9 /

6 •

l

Regardons à présent ce qui se passe si l’opération est réalisée de manière fonc-tionnelle. La liste de départ est identique au cas de la solution impérative. Parcontre la structure obtenue en résultat est la suivante :

• 2 • 4 • 7 • 9 /

2 • 4 • 6 •

l

Bien que la liste initiale soit intacte, elle est devenue inaccessible puisque l dé-signe à présent la nouvelle liste. Il suffirait cependant d’une pincée de program-mation impérative pour préserver, dans une variable annexe lV ieux, l’ancienneliste qui resterait alors consultable ou même modifiable. La structure est deve-nue persistante. En l’absence d’un tel artifice, les anciennes cellules contenantles valeurs 2 et 4 seraient inaccessibles. La disponibilité d’un ramasse-miettes(garbage collector) est alors appréciable pour restituer ces deux cellules au « potcommun » de la mémoire libre (le « tas »).

Nous remarquons que pour obtenir la nouvelle liste il est nécessaire de dupli-quer tout ou partie (selon la position d’insertion) de la liste initiale en créant denouvelles cellules, entraînant un surcoût en temps d’exécution. Dans l’exempleci-dessus ce surcoût peut sembler rédhibitoire : nous recopions la moitié de laliste. Imaginons un instant qu’au lieu d’une liste nous disposions d’un arbre.L’adjonction d’une valeur va certes entraîner là aussi une duplication de cer-tains nœuds. Mais cette fois la proportion des nœuds dupliqués est (en général)négligeable par rapport au nombre total de nœuds de l’arbre.

Imaginons à présent que la structure de données soit constituée d’un tableauque nous cherchons à mettre à jour. Le principe de la programmation fonction-nelle, qui interdit de modifier une structure existante, va conduire à dupliquerla totalité du tableau. Cette fois le coût par rapport à une méthode qui autoriseles modifications in situ est incomparablement plus élevé. Cependant, puisqu’ilne s’agit pas d’une impossibilité logique, nous admettons et utilisons l’approchefonctionnelle, y compris pour les structures comprenant des tableaux. Néanmoinsil faut être conscient qu’une étape de raffinement ultime est alors nécessaire pouratteindre l’efficacité souhaitée.

La persistance des structures de données est une notion intéressante en soi :elle permet de mettre en œuvre des bases de données temporelles ou des sau-vegardes en ligne, qui autorisent l’accès aux états passés d’un système. Elle estégalement à l’origine d’applications en géométrie calculatoire et en calcul paral-lèle. Pour notre part le seul cas où nous l’exploitons est celui de la mise à jourdes arbres Avl (cf. section 6.6), afin de connaître l’état d’équilibre passé pourétablir un nouvel équilibre sans être obligé de mémoriser celui-là dans chacun des

Page 21: Structures de données et méthodes formelles ||

Avant-propos 7

nœuds de l’arbre. Dans l’ouvrage [71], le chapitre « Persistent data structures »de H. Kaplan est consacré à l’étude des structures persistantes.

Le mode de passage de paramètres utilisé pour l’application d’une fonctionà ses arguments est décrit au chapitre 1. Il correspond à celui connu sous le nomde passage par valeur (tous les arguments sont évalués une fois, lors de l’appel).L’ouvrage [93] étudie l’influence des modes de passage sur les différentes formesde complexité.

Plan et guide de lecture

Cet ouvrage s’adresse à toute personne désireuse de faire évoluer sa connais-sance et sa pratique des structures de données ainsi que de leurs liens avecles méthodes formelles. Il devrait donc intéresser les professionnels déjà expé-rimentés mais qui souhaitent s’ouvrir à des approches plus rigoureuses, ou quisouhaitent rafraîchir et restructurer leurs bagages. Bien évidemment il s’adresseégalement aux enseignants et aux étudiants en informatique. Il peut servir d’ou-vrage de référence à un cours de premier ou de second cycle universitaire sur lesstructures de données. Compte tenu de son orientation, qui met l’accent sur unedémarche de conception au détriment parfois de la couverture du domaine, ilpeut être complété, pour un enseignement de troisième cycle, par des ouvragesspécialisés sur l’algorithmique des graphes, sur les techniques de hachage, sur lacomplexité, etc. L’ouvrage de D. Knuth [75] par exemple et les ouvrages de lasérie constituent de bons compléments.

Plan de l’ouvrage

Le livre est organisé en deux parties qui se déclinent en dix chapitres. Lapremière partie est consacrée aux bases nécessaires à l’étude de la seconde par-tie. Cette dernière développe cinq structures de données parmi les plus fonda-mentales. Le choix de ces cinq structures est d’une certaine façon arbitraire.Pourquoi écarter de ce référentiel des structures importantes comme les graphesou les structures de partition ? Pourquoi classer, par exemple, les arbres dansles structures outils ? Il n’y a pas de réponse définitive à ce type de question,seul l’intérêt pratique prime et le lecteur confronté à des impératifs différents estinvité à construire son propre référentiel. Le même type de remarque peut êtreformulé à propos des opérations accompagnant chaque type abstrait, où seuls les« constructeurs » sont incontournables. La contrainte la plus forte est l’existenced’une structure concrète de nature fonctionnelle pure ou semi-fonctionnelle (au-torisant les tableaux).

Chaque section est accompagnée d’une conclusion dans laquelle un certainnombre de commentaires de nature bibliographique et de remarques sont formu-lés.1. Le chapitre 1 regroupe les connaissances mathématiques nécessaires à la

spécification et à la mise en œuvre des structures de données, depuis lathéorie des ensembles jusqu’aux structures génériques nécessaires à desréalisations efficaces. Ce chapitre emprunte beaucoup à la méthode B.

Page 22: Structures de données et méthodes formelles ||

8 Structures de données et méthodes formelles

2. Le chapitre 2 présente la méthodologie de développement utilisée toutau long de l’ouvrage. Son titre (Spécification abstraite + Spécificationconcrète + Fonction d’abstraction + Calcul = Programme) résume parfai-tement son contenu. La notion de fonction d’abstraction, qui décrit formel-lement comment une structure concrète représente une structure abstraite,est essentielle pour la suite.

3. Le chapitre 3 s’arrête sur trois structures de données particulières que nouscroisons régulièrement dans les différentes mises en œuvre de la partie II :les listes finies, les arbres finis et les sacs finis.

4. Le chapitre 4 est entièrement consacré aux notions liées à l’analyse dela complexité d’algorithmes. Il s’agit d’un chapitre court, de nombreuxouvrages sont consacrés à ce thème, nous n’avons pas jugé utile de le déve-lopper excessivement. De par sa relation privilégiée avec les structures dedonnées, la complexité amortie (et en particulier la méthode du potentiel)a cependant été l’objet d’une attention particulière.

5. Le chapitre 5 achève la première partie en développant, selon la démarcheintroduite au chapitre 2, deux exemples simples.

6. La partie II débute par le chapitre 6 qui est consacré à la représentation desensembles finis de scalaires. Ce chapitre est long. Le sujet le mérite. Septtypes de représentations sont étudiés, dans un ordre « chronologique »,depuis la méthode des arbres binaires de recherche jusqu’aux méthodesaléatoires.

7. Le chapitre 7 étend en quelque sorte le champ d’étude du chapitre précé-dent pour s’intéresser aux ensembles composites, qu’il s’agisse de chaînesou d’ensembles de couples. Ce dernier cas résiste pour l’instant aux assautsdes informaticiens lancés dans la course à l’efficacité et constitue de ce faitun thème ouvert et un défi intéressant. . .

8. Le chapitre 8 est dédié aux files simples. Ce chapitre est bref. À cela deuxraisons : les mises en œuvre naïves sont très efficaces et connues de tous,en outre elles ne sont pas fonctionnellement pures (elles exigent la mani-pulation de pointeurs ou font usage de tableaux). Nous avons cependantmis l’accent sur une représentation particulière qui dans notre contexteprésente des caractéristiques intéressantes : la représentation (chaînée) pardouble liste. D’une part c’est une solution très élégante et efficace ; d’autrepart elle constitue, par sa simplicité, une porte d’entrée abordable dansl’univers de la complexité amortie.

9. Le chapitre 9 est consacré à une structure de données qui est l’objet debeaucoup d’attentions de la part des spécialistes : les files de priorité.Cela s’explique par le large éventail d’applications où elles interviennent.Trois mises en œuvre sont présentées. Elles couvrent un large spectre desméthodes et connaissances dispersées dans le reste de l’ouvrage.

10. Enfin le chapitre 10 traite des tableaux flexibles. Un sujet habituellementplutôt discret. Serait-ce en raison de l’intégration de cette fonctionnalitédans beaucoup de langages récents ou de l’efficacité relative des mises enœuvre par réallocation ? Qu’importe, les réalisations proposées sont trèsintéressantes pédagogiquement parlant, qu’il s’agisse des arbres de Braun,aussi astucieux qu’efficaces, ou de l’implantation par des minimiers.

Page 23: Structures de données et méthodes formelles ||

Avant-propos 9

Parcours

Le chapitre 5 donne au lecteur pressé un bon aperçu de l’ensemble de l’ou-vrage. Selon le niveau de l’enseignement visé, plusieurs types de parcours peuventêtre proposés à l’utilisation de cet ouvrage. Nous préconisons cependant à chaquefois de débuter ou de faire précéder l’enseignement en question par, grosso modola matière du chapitre 1, c’est-à-dire par une initiation aux mathématiques dis-crètes, aux notations de la théorie des ensembles et aux techniques de preuvequi l’accompagnent. Parmi celles-ci, insistons sur les démonstrations par récur-rence/induction, qui doivent être maîtrisées.

Pour un cours d’initiation aux structures de données, sur une base de 30heures environ, qui se limiterait aux structures élémentaires, nous conseillons leschapitres 2, 5, 6 (restreint aux cinq premières sections de ce chapitre) et 8.

Pour un cours de second cycle, d’une durée comprise entre 60 et 100 heures,l’ensemble des chapitres doit être abordé. Un choix peut être réalisé parmi lesstructures étudiées dans le détail. Il n’est pas indispensable par exemple d’appro-fondir toutes les structures équilibrées ni toutes les structures autoadaptatives.

Pour un cours avancé, l’accent peut être mis sur la méthodologie (chapitres 1et 2, et section 4.3 du chapitre 4) et sur quelques structures de données parmiles plus récentes (structures autoadaptatives, aléatoires, arbres de Braun, etc.).

À l’exception de ce dernier parcours, il est bien entendu indispensable que lecours soit accompagné d’enseignements dirigés et pratiques. Les nombreux exer-cices proposés à la fin de la plupart des sections constituent une source à laquelleil est possible de s’approvisionner. Les enseignements pratiques doivent bien en-tendu conduire à mettre en œuvre les structures de données, mais ils doiventaussi être l’occasion de mettre en pratique un cycle complet de développementdepuis la spécification informelle jusqu’au produit final accompagné d’une docu-mentation de type « rapport de développement » et « guide de l’utilisateur ».

Le langage de programmation utilisé à l’occasion des enseignements pratiquespeut être quelconque, depuis un langage algorithmique comme Pascal, Ada ouC, jusqu’aux langages fonctionnels (voire logiques) tel que ML, CAML, Haskellou Lisp, en passant par les langages objet. Il est même tout à fait possible, d’uneséance à la suivante, de faire varier le niveau de langage. Ceci peut contribuer àune meilleure compréhension des mécanismes de la programmation fonctionnelle.Bien entendu l’effort de traduction manuel est proportionnel au degré de proxi-mité avec le langage de description utilisé dans ce livre. Standard ML constitueprobablement l’un des optimums.

Ainsi que nous l’avons annoncé ci-dessus, l’organisation de la partie II permetun parcours différent, orthogonal à une lecture séquentielle. Pour les personnesintéressées, il est possible d’adopter une lecture par thèmes selon une progres-sion chronologique : les structures naïves de la première période, les structureséquilibrées, les structures autoadaptatives et les structures aléatoires.

Avertissements

Il est important d’avertir les étudiants des contraintes inhérentes au modèlefonctionnel : l’utilisation de tableaux traditionnels est coûteuse, la manipula-tion directe de pointeurs est interdite (excluant certaines implantations clas-

Page 24: Structures de données et méthodes formelles ||

10 Structures de données et méthodes formelles

siques comme les files avec pointeurs de tête et de queue, les listes circulaires, leslistes doublement chaînées, les arbres inverses, etc.), la notion d’état n’est paspertinente. Si la durée du module d’enseignement le permet, il est possible deconsacrer une fraction du temps à des exercices sur la traduction des structures(persistantes) obtenues en structures éphémères classiques, à l’introduction dela notion d’état par le remplacement des fonctions par des procédures et par lasuppression des appels récursifs terminaux (cf. [24] et [61] pour des exemples).

La pratique de la démarche prônée dans cet ouvrage va naturellementconduire un étudiant standard à s’imaginer que la difficulté de la démarche résidedans les calculs. L’enseignant devra sans doute déployer quelques efforts pourle convaincre que les vraies difficultés se situent dans les choix stratégiques quirégentent le calcul et surtout dans la découverte des bonnes structures concrètes.

Prérequis

Cet ouvrage ne s’adresse pas à l’informaticien débutant. Pour en tirer pro-fit, il est nécessaire d’avoir préalablement acquis une expérience d’au moins 30heures en programmation classique et de maîtriser les mathématiques dispenséesen première année d’un enseignement supérieur scientifique. Une expérience enrécursivité est souhaitable. Une connaissance de base portant sur les structuresde données les plus élémentaires et les pointeurs peut être appréciable.

Terminologie

Nous présentons ici une définition de quelques termes fréquemment utilisésdans le reste de l’ouvrage.

Calcul de programmes : méthode formelle qui permet d’obtenir un pro-gramme exécutable à partir de sa spécification en décomposant le déve-loppement en étapes de calculs élémentaires. Type de méthode fondé surl’application de règles, de stratégies et d’heuristiques issues des propriétéssémantiques des constructions utilisées. On parle également de dérivationde programmes. Le calcul de programmes s’applique aussi bien à la pro-grammation impérative qu’à la programmation fonctionnelle comme c’estle cas ici.

Fonction d’abstraction : il s’agit d’un terme propre à la méthode exposéedans cet ouvrage (cf. [56, 101, 28] cependant). Une fonction d’abstractionexplicite comment une structure de données concrète réalise une structurede données abstraite. Par exemple, c’est une fonction d’abstraction qui per-met d’obtenir un ensemble (structure abstraite) à partir d’une liste (struc-ture concrète). Les fonctions d’abstraction n’ont pas à être implantées, leurutilité se limite à la spécification concrète et au calcul des opérations.

Méthode formelle : terme employé en informatique et en génie logiciel en par-ticulier. Ensemble de techniques basées sur les mathématiques discrètes quipermettent de spécifier, de prouver et de développer des systèmes compre-nant des composants logiciels.

Page 25: Structures de données et méthodes formelles ||

Avant-propos 11

Opération : ce terme est utilisé pour qualifier les opérateurs s’appliquant auxvaleurs d’un type de données. Du point de vue informatique, les opéra-tions se présentent soit sous la forme de procédures (ou de routines) soitsous la forme de fonctions. Pour ce qui nous concerne, ce terme recouvreuniquement des fonctions. Nous distinguons les opérations de la spécifica-tion abstraite, celles de la spécification concrète et la mise en œuvre de cesdernières (appelées représentations).

Programmation fonctionnelle : paradigme de programmation qui assimiletout calcul à l’application d’une fonction à des arguments. Un des pluspopulaires parmi les nombreux paradigmes existants (cf. [57] pour unesynthèse de quatre d’entre eux). Il est possible de simuler ce style de pro-grammation en utilisant un langage impératif (c’est-à-dire avec variables),il suffit d’appliquer rigoureusement la règle de codage qui stipule qu’« onne modifie jamais une structure existante. » Les structures de données ob-tenues sont qualifiées de fonctionnelles.

Raffinement : appliqué au développement informatique, ensemble de mé-thodes permettant de passer de la spécification d’un système à sa réali-sation, en intégrant graduellement des détails de plus en plus fins.

Spécification : texte (formalisé ou non) qui explicite les propriétés d’un sys-tème. Pour notre part, nous distinguons la spécification abstraite (cf. ci-dessous la notion de « structure de données » dans sa première acception)de la spécification concrète, qui établit les relations existant entre proprié-tés abstraites et concrètes à travers la fonction d’abstraction.

Structure de données : selon C. Okasaki (cf. [93]), ce terme couvre au moinsquatre significations différentes que le contexte permet en général de dis-tinguer :1. Un type de données accompagné des opérations (de consultation ou

de mise à jour) qui lui sont associées. Les termes algèbre, type, spé-cification abstraite, spécification algébrique, abstraction de donnéespeuvent en général lui être substitués.

2. Une réalisation concrète d’une spécification abstraite, que nous appe-lons aussi parfois implantation, implémentation, représentation. C’estl’entité obtenue à l’issue de la mise en œuvre d’une spécification abs-traite.

3. Une instance d’une réalisation concrète, qui est créée à un instant t0et qui évolue au cours des mises à jour jusqu’à sa disparition.

4. Dans le cadre de structures persistantes, les différentes versions qui sesuccèdent au cours de l’évolution de la structure. C. Okasaki utilisele terme d’identité persistante.

Ajoutons à cette liste la configuration d’une instance à un moment donné.C’est dans ce sens qu’il est utilisé lorsque nous écrivons : « la structure dedonnées contient la valeur 6. »

Type de données : c’est l’ensemble (fini ou non) des valeurs que peuventprendre les entités placées sous cette dénomination. Le type de donnéesentiers naturels s’identifie à {0, 1, 2, . . .}. Un type de données est en géné-ral indissociable des opérations qui permettent de manipuler les valeurs de

Page 26: Structures de données et méthodes formelles ||

12 Structures de données et méthodes formelles

l’ensemble en question. Le terme est à rapprocher de structure de donnéesdans la première acception mentionnée ci-dessus.

Convention de styleDes soucis d’homogénéité de style conduisent certains auteurs à adopter sys-

tématiquement l’un des types de formulation suivant, à l’exclusion des deuxautres : « Je . . . », « Nous . . . », « On . . . ».

Notre choix est différent. « Nous », sous sa forme sylleptique, est utilisélorsque nous évoquons une décision, une argumentation personnelle de l’auteur,comme dans « Nous allons étudier les rotations . . . » (comprendre « l’auteur apris la décision d’étudier les rotations à ce moment-là du discours »). « On » estutilisé pour introduire des considérations d’ordre général comme dans « Il estrare que l’on utilise des ensembles de files » (comprendre « quiconque dans lacommunauté des informaticiens n’utilise que rarement des ensembles de file »).

RemerciementsNous tenons à exprimer nos sincères remerciements à l’Enssat et à son person-

nel, ainsi qu’à Pierre-Noël Favennec et à Henri Habrias. Qu’il nous soit égalementpermis de citer les personnes suivantes en témoignage de leur influence, de leursoutien ou de leur amitié : J.-R. Abrial, P. Alain, C. Attiogbé, J.-P. Banâtre,P. Bosc, J. Courtin, A. Delhay, A. Hadjali, D. Herman, H. Jaudoin, P. Quin-ton, D. Lolive, G. Mercier, L. Miclet, J.-F. Monin, T. Napoléon, J.-C. Pettier,D. Rocacher, C. Roussel, M.D. Sadek, J. Seguin, J. Siroux, G. Smits, M. Tréhel,L. Trilling, J. Wolf. Nous remercions également les étudiants du cycle lsi del’Enssat pour leur contribution involontaire.

Page 27: Structures de données et méthodes formelles ||

Première partie

Les bases

Page 28: Structures de données et méthodes formelles ||

Chapitre 1

Mathématiques pour laspécification et les structuresde données

1.1 Introduction

Il est communément admis, dans toutes les disciplines de l’ingénieur,qu’après avoir couché sur le papier, en français, les caractéristiques du systèmeque l’on souhaite réaliser, il est nécessaire de modéliser (on dit aussi spécifier)formellement ces caractéristiques avant de passer à la réalisation effective. C’estvrai dans l’automobile, l’aviation ou le génie civil. Les avantages sur une approchepurement empirique sont connus mais méritent d’être rappelés : le modèle formeln’est pas ambigu, il peut servir de « contrat » entre les parties prenantes ; il per-met de démontrer les propriétés recherchées avant de passer à l’étape suivante ;il facilite l’utilisation d’outils (notamment informatiques) pour « donner vie »au modèle, il autorise la détection de problèmes ou d’erreurs avant d’avoir tropinvesti dans le développement. Pour les activités industrielles sus-citées, spéci-fier formellement signifie utiliser l’outil mathématique (et notamment le calculinfinitésimal).

De ce point de vue, la mise en œuvre de systèmes informatiques (ou compre-nant des composants logiciels) ne devrait pas s’écarter du schéma traditionnel.Pourtant, bien que les pionniers ne s’y soient pas trompés (cf. [85] sur l’utilisationpar A. Turing de la logique enrichie de l’arithmétique pour réaliser la démonstra-tion de la correction d’un programme), la nature discrète et immatérielle de ladiscipline informatique a pu en troubler quelques-uns. Certains ont même accré-dité l’idée d’une « exception informatique » qui ferait de la programmation unediscipline expérimentale ! Spécifier s’est longtemps limité à produire un texte enfrançais. Une première brèche a été ouverte à la fin des années 1960 avec l’usagede la logique des prédicats comme moyen de spécification. Celle-ci (enrichie del’arithmétique, de l’égalité, de la notion de tableau) a été utilisée dans les pre-miers travaux influents sur la preuve de programmes ou sur la construction de

Page 29: Structures de données et méthodes formelles ||

16 Structures de données et méthodes formelles

programmes corrects (cf. [55, 30, 31]), avec à la clé un effet pervers imputable àla difficulté de transposer ces méthodes à des applications industrielles. Cet effetpervers a conduit certains à jeter le bébé avec l’eau du bain. Au cours des années1970 sont apparues des méthodes graphiques semi-formelles 1 telles que le mo-dèle entité-relation, Merise, ssadm, etc. et dont la postérité est aujourd’hui bienimplantée. Pourtant, à bien y regarder, ces méthodes ne sont ni plus ni moinsque des avatars notationnels de la (nous devrions dire d’une) théorie des en-sembles. Pourquoi alors ne pas utiliser directement cette théorie ? C’est le choixréalisé par la méthode B [3] (ainsi que par son successeur, la méthode Event-B[5]) pour ce qui concerne la modélisation des données et la preuve. En raison deses nombreuses qualités, nous avons décidé d’adopter la théorie des ensemblesdéclinée dans le formalisme des méthodes B/Event-B en tant que support formelde notre démarche. Avant de présenter le principe de la preuve et la démarcheensembliste de B, comparons, sur un exemple, les trois formes de spécificationmentionnées ci-dessus : informelle, prédicative et ensembliste.

Considérons le « système » constitué d’un échiquier 8 × 8 sur lequel sontplacées huit reines qui ne se menacent pas mutuellement, comme dans le schémaci-dessous :

80Z0L0Z0Z7Z0Z0Z0L060ZQZ0Z0Z5Z0Z0Z0ZQ40L0Z0Z0Z3Z0Z0L0Z02QZ0Z0Z0Z1Z0Z0ZQZ0

a b c d e f g h

Ceci constitue la caractérisation du système en question. Elle est concise etcompréhensible par toute personne maîtrisant le français. . . et les règles du jeud’échec. Incidemment, ce schéma nous offre l’occasion de nous interroger surles avantages et inconvénients des schémas en tant qu’outils de spécification.Un schéma est incontestablement plus parlant qu’un texte ou qu’une formulemathématique. À l’inverse, un schéma n’est le plus souvent qu’un exemple pos-sible du système à réaliser (c’est particulièrement clair ici puisqu’il existe biend’autres configurations acceptables), qui de ce fait peut induire en erreur. Unschéma interdit également toute forme de raisonnement rigoureux. Pour ces dif-férentes raisons, nous ne considérons un schéma que comme un complément àune description rigoureuse (cf. encadré page 199 pour un développement de cetteopinion).

Utilisons à présent la logique des prédicats pour formaliser cette spécification.Cela exige de préciser deux points.

1. Pour lesquelles la syntaxe est formalisée, la sémantique ne l’est pas.

Page 30: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 17

– La « structure de données » : un tableau de 8× 8 booléens r tel que r(i, j)vaut true si et seulement s’il existe une reine en position (i, j).

– L’absence de menace : s’il existe une reine en position (i, j), alors il n’y apas d’autres reines sur la ligne i ni sur la colonne j. Il n’y a pas non plusd’autres reines sur les deux diagonales se croisant à la position (i, j).

En admettant que l’échiquier r soit représenté par la déclaration r ∈ (1 .. 8)×(1 .. 8)→ bool qui définit r comme un tableau de booléens de 8 lignes et de 8colonnes (contrairement à la tradition échiquéenne, les colonnes sont ici identi-fiées par des nombres et non par des lettres), la spécification se traduit par laformule prédicative suivante :

∀i, j ·(1 ≤ i ∧ i ≤ 8 ∧ 1 ≤ j ∧ j ≤ 8 ∧ r(i, j) = true⇒¬∃k ·(1 ≤ k ∧ k ≤ 8 ∧ k = i ∧ r(k, j) = true)∧¬∃k ·(1 ≤ k ∧ k ≤ 8 ∧ k = j ∧ r(i, k) = true)∧

¬∃k, l ·

⎛⎜⎜⎜⎜⎜⎜⎝1 ≤ k ∧ k ≤ 8∧1 ≤ l ∧ l ≤ 8∧k = i∧l = j ∧k + l = i+ j ∧r(k, l) = true

⎞⎟⎟⎟⎟⎟⎟⎠ ∧ ¬∃k, l ·

⎛⎜⎜⎜⎜⎜⎜⎝1 ≤ k ∧ k ≤ 8∧1 ≤ l ∧ l ≤ 8∧k = i∧l = j ∧k − l = i− j ∧r(k, l) = true

⎞⎟⎟⎟⎟⎟⎟⎠)

∧∀i ·(1 ≤ i ∧ i ≤ 8⇒∃j ·(1 ≤ j ∧ j ≤ 8 ∧ r(i, j) = true))

Il est pour l’instant inutile de chercher à comprendre cette formule dans le détail.Notons cependant qu’elle se présente sous forme conjonctive (c’est-à-dire sousla forme de deux formules reliées par une conjonction ∧). Le premier conjointspécifie l’absence de menace mutuelle. Ce conjoint n’implique pas qu’il existe huitreines sur l’échiquier, d’où le second conjoint qui affirme que chaque ligne estdotée d’au moins une reine. La complexité de cette formule est manifeste. Cela estcertes imputable au fait qu’elle capte une connaissance complexe mais aussi aufait qu’elle s’exprime dans un langage de bas niveau. Cependant, contrairementà la spécification informelle, nous sommes en principe capables par exemple dedéduire de cette formule qu’il existe une reine sur chaque colonne de l’échiquier.

Venons-en à présent à une spécification ensembliste dans le style de celle quiest utilisée au sein de la méthode B. L’échiquier est représenté par une relationq entre deux instances de l’intervalle 1 .. 8 telle que (i, j) ∈ q si et seulements’il existe une reine à l’intersection de la ligne i et de la colonne j. La formulesuivante représente une spécification ensembliste possible :

q ∈ 1 .. 8�� 1 .. 8∧λi ·(i ∈ 1 .. 8 | i+ q(i)) ∈ 1 .. 8� 2 .. 16∧ (1.1.1)λi ·(i ∈ 1 .. 8 | i− q(i)) ∈ 1 .. 8�−7 .. 7

Le premier conjoint précise que la relation q est en fait une fonction bijectivetotale qui de ce fait capte l’absence de prise mutuelle sur les lignes et colonnes.Les deux derniers conjoints modélisent, grâce à deux fonctions injectives totales,l’absence de prise mutuelle sur les diagonales.

Page 31: Structures de données et méthodes formelles ||

18 Structures de données et méthodes formelles

La confrontation entre spécification prédicative et spécification ensemblisteest édifiante, abondance de quantificateurs d’un côté, concision de l’autre.

Formaliser les caractéristiques d’un système ne signifie pas contraindre lemodèle de façon à minimiser le nombre de solutions. Au contraire, il est pré-férable de laisser un certain degré de liberté pour les étapes ultérieures. Ainsi,pour reprendre l’exemple de l’échiquier, il nous faut les moyens linguistiquesde préciser que nous recherchons un échiquier quelconque qui satisfasse la for-mule 1.1.1. C’est l’objectif des expressions qui sont ci-dessous qualifiées de nondéterministes.

Dans la suite de ce chapitre, nous précisons les caractéristiques de la théoriedes ensembles sur laquelle nous nous appuyons (cf. [3, 5]). Les aspects preuvesont basés sur le calcul des séquents, qui est présenté à la section 1.2. Les sec-tions 1.3 à 1.7 sont celles qui concernent plus précisément la théorie des en-sembles et le noyau autour duquel elle est construite. La section 1.9 s’intéresseaux structures inductives, celles-ci sont au cœur des mises en œuvre de beaucoupde structures de données. La section 1.10 traite du cas particulier de l’inductiondans l’ensemble N des entiers naturels. La section 1.11 détaille le formalisme desopérations.

Dans ce chapitre, nos objectifs sont moins ambitieux que ceux manifestésdans [5] et surtout dans [3]. Il ne s’agit pas pour nous de construire la théorie desensembles mais d’utiliser sa richesse et d’exploiter les résultats qui en découlent.En conséquence nous nous limitons à rappeler les principes généraux, sauf bienentendu dans les rares cas où nous étendons la théorie ou bien ses notations.Concernant les preuves réalisées à partir du chapitre 4, nous veillons à utiliserautant que faire se peut les propriétés de la théorie (cf. annexes, page 403 etsuivantes). Le style utilisé pour réaliser les preuves est souvent plus relâché quedans les deux ouvrages mentionnés ci-dessus.

Exercices

Exercice 1.1.1 Soit un échiquier et une collection de n reines. n est aussi grand qu’on lesouhaite. Spécifier la situation dans laquelle un nombre minimum de reines contrôle toutes lescases. Fournir une version purement prédicative et une version ensembliste.

Exercice 1.1.2 Un carré magique normal d’ordre n est un tableau de n lignes et de n colonnescontenant toutes les valeurs de l’intervalle 1 ..n2, tel que la somme des valeurs de chaque ligne,de chaque colonne et de chacune des deux grandes diagonales est identique. Spécifier de manièretotalement prédicative puis ensembliste un tel objet.

1.2 RaisonnementArrêtons-nous un instant sur la méthodologie utilisée pour construire une

théorie mathématique comme la théorie des ensembles. La première décision àprendre concerne le choix du langage dans lequel s’expriment les conjectures,les théorèmes, etc. Une solution possible est de choisir les séquents. Un séquentse présente sous la forme H B. H est appelé hypothèses et B but. B est une

Page 32: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 19

construction que nous appelons prédicat tandis que H est une collection finie,éventuellement vide, de prédicats. Intuitivement H B représente l’idée que laconjonction des hypothèses de H entraîne B. Prenons un exemple simple : unséquent permet d’exprimer que le but (1 .. 8 ∩ 3 .. 10) = ∅ est réalisé sous leshypothèses 5 ∈ 1 .. 8 et 5 ∈ 3 .. 10 :

5 ∈ 1 .. 8, 5 ∈ 3 .. 10 (1 .. 8 ∩ 3 .. 10) = ∅ (1.2.1)

La syntaxe d’un séquent respecte les règles présentées ci-dessous. La syntaxe dela catégorie prédicat est pour l’instant indéfinie.

séquent : := listePréd prédicat || prédicat

listePréd : := prédicat ||prédicat, listePréd

La seconde décision concerne le choix des règles d’inférence. Une règle d’in-férence est la brique de base du raisonnement formel. Elle se présente sous la

formeA

Coù A est une collection finie, éventuellement vide, de séquents ap-

pelée antécédent, et C un séquent appelé conséquent. Une règle d’inférence dontl’antécédent est vide s’appelle axiome.

Un séquent s est prouvé s’il existe une règle d’inférence dont le conséquents’identifie à s et si tous les séquents de l’antécédent sont prouvés. Il est faciled’en déduire une stratégie élémentaire de preuve. On recherche une règle dont leconséquent s’identifie au séquent. Si la règle est un axiome, le séquent est prouvé,sinon on effectue la preuve de tous les séquents de l’antécédent. Illustrons cedernier point en considérant les cinq règles ci-dessous :

A : 5 ∈ 1 .. 8 B : 5 ∈ 4 .. 6 C : 5 ∈ 4 .. 6 5 ∈ 3 .. 10

D : 5 ∈ 1 .. 8 , 5 ∈ 3 .. 10

5 ∈ 1 .. 8, 5 ∈ 3 .. 10 5 ∈ (1 .. 8 ∩ 3 .. 10)

E :5 ∈ 1 .. 8, 5 ∈ 3 .. 10 5 ∈ (1 .. 8 ∩ 3 .. 10)5 ∈ 1 .. 8, 5 ∈ 3 .. 10 (1 .. 8 ∩ 3 .. 10) = ∅

L’ensemble de ces règles d’inférence constitue une théorie. Les règles A et B n’ontpas d’antécédent, ce sont des axiomes. Un théorème de la théorie peut se dé-montrer en appliquant le principe décrit ci-dessus jusqu’à atteindre des axiomes.L’ensemble de la démonstration se présente sous la forme d’un arbre fini dont laracine est le séquent à prouver. Chaque nœud de l’arbre de démonstration estconstitué d’un séquent et de la règle utilisée pour le démontrer. La démonstrationde la formule 1.2.1 dans la théorie ci-dessus se présente sous la forme :

Page 33: Structures de données et méthodes formelles ||

20 Structures de données et méthodes formelles

5 ∈ 1 .. 8, 5 ∈ 3 .. 10 (1 .. 8 ∩ 3 .. 10) = ∅

E

5 ∈ 1 .. 8, 5 ∈ 3 .. 10 5 ∈ (1 .. 8 ∩ 3 .. 10)D

5 ∈ 1 .. 8A

5 ∈ 3 .. 10C

5 ∈ 4 .. 6B

Il s’agit maintenant d’exploiter ces notions (séquent, règle d’inférence, dé-monstration) pour construire par étapes une théorie. La première étape consisteà définir une théorie minimale captant le raisonnement mathématique de base.Ceci peut se faire en proposant les trois règles d’inférence suivantes (présentéeshorizontalement) :

Antécédent Conséquent Ident.

H, P P (1.2.2)H Q H, P Q (1.2.3)H P , H, P Q H Q (1.2.4)

La première règle rend compte du fait que si dans un séquent le but fait partiedes hypothèses alors le séquent est un théorème. La règle 1.2.3 capte le fait que siH Q est un théorème, alors en ajoutant n’importe quelle hypothèse on obtienttoujours un théorème. Enfin, la troisième règle, appelée règle de coupure, nousapprend que pour démontrer Q sous les hypothèses H, il suffit de démontrer Qsous les hypothèses H, P et de montrer P sous les hypothèses H.

Une théorie donnée peut être étendue en enrichissant la syntaxe des prédi-cats constituant les séquents. Deux cas de figure peuvent alors survenir : soit lesextensions constituent de simples facilités de notation, auquel cas il faut sim-plement définir les nouvelles notations à partir des notations existantes ; soitil s’agit de nouvelles constructions, indépendantes des précédentes. Il faut alorscompléter la théorie existante par des règles d’inférence destinées à donner unsens à ces nouvelles notations.

Exercice

Exercice 1.2.1 (inspiré de [58]) Considérons la théorie suivante où les formules sont constituéesdes symboles �, |, + et =.

Page 34: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 21

Antécédent Conséquent

� x+ |= x |� x+ y = z � x+ y |= z |

Les lettres x, y et z représentent des séquences de longueur finie du symbole |.1. Prouver la formule suivante : �||| + ||=|||||.2. Développer un prouveur pour cette théorie.

1.3 Calcul propositionnelTrois opérateurs et un nouveau symbole sont ajoutés à la théorie de base

pour constituer le langage propositionnel. Le symbole ⊥ représente une formulequi n’est pas un théorème (une formule improuvable). Les opérateurs ∧, ⇒ et ¬se dénomment conjonction, implication et négation. Syntaxiquement le langageinitial s’étend comme le montrent les règles grammaticales suivantes :

prédicat : := ⊥ ||prédicat ∧ prédicat ||prédicat⇒ prédicat ||¬prédicat(prédicat)

L’attribution de priorités 2 et l’usage de parenthèses permettent de lever lesambiguïtés véhiculées par cette grammaire. Dans la suite nous utilisons sou-vent les espaces autour d’un opérateur afin de souligner une plus faible priorité.La théorie minimale présentée à la section 1.2 s’enrichit des règles d’inférencesuivantes, qui rendent compte du comportement de chacun des nouveaux opé-rateurs :

Antécédent Conséquent Ident.

H,⊥ P (1.3.1)H P , H ¬P H ⊥ (1.3.2)

H P , H Q H P ∧Q (1.3.3)H, P,Q R H, P ∧Q R (1.3.4)

H, P,Q R H, P, P ⇒Q R (1.3.5)H, P Q H P ⇒Q (1.3.6)

H,¬Q P H,¬P Q (1.3.7)H, P ⊥ H ¬P (1.3.8)

Une extension purement notationnelle consiste à introduire les opérateurspropositionnels ∨ et ⇔, ainsi que la notation �. La grammaire s’enrichit de lamanière suivante :

2. L’annexe E précise la priorité des différents opérateurs.

Page 35: Structures de données et méthodes formelles ||

22 Structures de données et méthodes formelles

prédicat : := . . . ||� ||prédicat ∨ prédicat ||prédicat⇔ prédicat

La définition des nouveaux symboles est donnée par le tableau suivant :

Notation Définition� ¬⊥P ∨Q ¬P ⇒Q

P ⇔Q (P ⇒Q) ∧ (Q⇒ P )

Le lecteur étant supposé familiarisé avec la logique propositionnelle, les pro-priétés de celle-ci sont utilisées sans démonstration ni rappel dans la suite del’ouvrage.

1.4 Calcul des prédicats

1.4.1 Quantification universelleLe langage des prédicats enrichit le langage propositionnel de trois no-

tions : la notion de variable, celle de prédicat quantifié universellement et celled’expression. Débutons par la notion d’expression. La syntaxe d’une expressionse limite pour le moment à ce que permet la grammaire ci-dessous, mais elle estdestinée à s’enrichir notablement à la section 1.6.

expression : := variable ||expression �→ expression ||(expression, expression) ||(expression)

variable : := identificateur

Ainsi, les formules suivantes : x, x �→ y, (x, y), x �→ (y �→ z) sont des expressions.Dans la suite, le terme formule est un terme générique qui regroupe prédicat etexpression. x �→ y est appelé couple, (x, y) est une notation alternative pourx �→ y. Alors que les prédicats sont destinés à être prouvés, les expressionsreprésentent un objet (un entier, un ensemble, etc.). La dernière règle décrivantla catégorie syntaxique expression exprime le fait qu’à l’instar des prédicats, ilest toujours possible de parenthèser une expression.

La syntaxe des prédicats quantifiés universellement est fournie par :

prédicat : := . . . ||∀ listeVar · prédicat

listeVar : := variable ||variable, listeVar

Page 36: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 23

En supposant que la formule suivante est un prédicat (il faut pour cela attendrela section sur la « théorie » des entiers naturels) : (x ∈ N∧y ∈ N⇒x ≤ y∨x ≥ y),les formules

– ∀x ·(x ∈ N ∧ y ∈ N⇒ x ≤ y ∨ x ≥ y),– ∀x, y ·(x ∈ N ∧ y ∈ N⇒ x ≤ y ∨ x ≥ y),– ∀z ·(x ∈ N ∧ y ∈ N⇒ x ≤ y ∨ x ≥ y),

sont des prédicats quantifiés universellement. Notons que les variables de quan-tification de chaque listeVar doivent être différentes deux à deux, par contreelles ne sont pas obligatoirement présentes dans la formule ainsi que l’illustre ladernière formule.

L’introduction de prédicats quantifiés enrichit notablement la puissance d’ex-pression du langage propositionnel. Ceci se traduit par l’extension du jeu desrègles d’inférence disponibles. Deux notions préalables liées à celle de variablesont nécessaires à la définition des nouvelles règles d’inférence : celle d’occurrencede variable non libre dans un prédicat et celle de substitution d’une variable parune expression dans un prédicat. Ces notions sont définies rigoureusement dans[3]. Nous effectuons ici un rappel informel.

Soit x une variable et P un prédicat. Toutes les occurrences de x sont libresdans toutes les sous-formules non quantifiées de P . Si P est une formule quan-tifiée, toutes les occurrences de x sont libres si x n’apparaît pas dans la listede quantification, aucune occurrence n’est libre si x apparaît dans la liste dequantification. Ainsi la formule :

y = 5 ∧ ∀y ·(y ∈ N⇒ y ≥ 0) ∧ ∀z ·(z ∈ N⇒ z < y)

comporte deux occurrences libres de y. La première se situe dans le premierconjoint et la seconde dans le dernier. Les occurrences de y du second conjointne sont pas libres car elles sont dominées par la quantification. Si x ne présenteaucune occurrence libre dans un prédicat P , x est dite non libre dans P et l’onnote x\P . Les notions d’occurrence libre ou non libre s’étendent naturellementaux autres quantificateurs que nous rencontrerons, ainsi qu’aux expressions.

Substitution. Une substitution est destinée à transformer une formule donnée(prédicat ou expression) en une autre formule. Elle se note [x := E]F , où x estune variable, E une expression et F une formule. Le résultat de la substitutionest la formule F dans laquelle toute occurrence libre de x est remplacée par E.Ainsi par exemple :

[x := y]x+ 5= Définition de la substitution

y + 5

ou encore :

[x := y + 3](2 · x = z ∧ ∀x ·(x ∈ N⇒ x > z))⇔ Définition de la substitution2 ·(y + 3) = z ∧ ∀x ·(x ∈ N⇒ x > z)

Page 37: Structures de données et méthodes formelles ||

24 Structures de données et méthodes formelles

Dans ce dernier cas, le respect de la priorité des opérateurs exige l’introductionde parenthèses.

Les deux nouvelles règles d’inférence nécessaires au raisonnement sur les pré-dicats quantifiés universellement sont :

Antécédent Conséquent Condition Ident.

H, ∀x ·P, [x := E]P Q H, ∀x ·P Q (1.4.1)H P H ∀x ·P x\H (1.4.2)

Les prédicats quantifiés existentiellement, définis syntaxiquement par :

prédicat : := . . . ||∃ listeVar · prédicat

constituent une extension des notations du langage des prédicats. Ils se défi-nissent par :

Notation Définition∃x ·P ¬∀x · ¬P

Exemples. La section 1.1 nous a déjà donné l’occasion d’utiliser le langagedes prédicats pour caractériser un système (celui des huit reines sur un échi-quier). Afin d’enrichir notre expérience, complétons cet exemple par deux autresexemples ayant trait à un tableau 3 d’entiers naturels t défini sur l’intervalle 1 ..n(n ≥ 0). Exprimons tout d’abord que dans t, toutes les occurrences de la valeur7 sont avant toutes les occurrences de la valeur 23 :

∃l ·

⎛⎝1 ≤ l ∧ l ≤ n+ 1 ∧

⎛⎝ ∀i ·(1 ≤ i ∧ i < l⇒ t(i) = 23)∧

∀j ·(l ≤ j ∧ j ≤ n⇒ t(j) = 7)

⎞⎠⎞⎠Soit en paraphrasant : il existe (au moins) une frontière l en deçà de laquelleil n’y a pas d’occurrence de la valeur 23 et à partir de laquelle il n’y a pasd’occurrence de la valeur 7.

Formalisons maintenant la proposition qui affirme que les valeurs 7 et 23alternent dans t :

∀i, j ·

⎛⎝⎛⎝ 1 ≤ i ∧ i < j ∧ j ≤ n∧

t(i) = 7 ∧ t(j) = 7

⎞⎠⇒∃k ·(i < k ∧ k < j ∧ t(k) = 23)

⎞⎠∧

∀i, j ·

⎛⎝⎛⎝ 1 ≤ i ∧ i < j ∧ j ≤ n∧

t(i) = 23 ∧ t(j) = 23

⎞⎠⇒∃k ·(i < k ∧ k < j ∧ t(k) = 7)

⎞⎠Soit encore : s’il existe (au moins) deux occurrences de la valeur 7, alors il y aau moins un 23 entre les deux, et réciproquement.

3. La notion de tableau ne fait pas pour l’instant partie de notre langage. Elle est introduiteen tant que fonction à la section 1.6.3.

Page 38: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 25

1.4.2 Deux nouveaux types d’expressions

Nous devons à présent étudier deux extensions pour les expressions : lesexpressions conditionnelles et les expressions let.

Les expressions conditionnelles

Elles se définissent de la manière suivante :

expression : := . . . ||if listeExpGardées fi

listeExpGardées : := expressionGardée ||expressionGardée | listeExpGardées

expressionGardée : := prédicat → expression

Le lecteur est supposé familiarisé avec les structures de contrôle classiques eten particulier avec l’alternative. Cependant l’expression conditionnelle (appeléeparfois plus simplement conditionnelle), que nous utilisons tout au long de cetouvrage, présente quelques caractéristiques qui méritent d’être précisées.

Dans le contexte des conditionnelles, le prédicat est appelé garde. La sé-mantique intuitive d’une expression conditionnelle est la suivante : une garde« vraie 4 » quelconque est sélectionnée, l’expression correspondante est évaluéeet sa valeur est délivrée. S’il y a plusieurs gardes vraies, l’une quelconque d’entreelles est choisie arbitrairement 5. Si aucune garde n’est vraie, le programme s’ar-rête en erreur. Le choix d’une telle construction est justifié ici par le fait qu’ellepermet un développement indépendant des expressions gardées et donc un dé-veloppement itératif des opérations. Elle permet également de tirer profit dessituations symétriques afin d’abréger les développements.

Le tableau ci-dessous définit la notion de substitution dans les expressionsgardées et dans les conditionnelles. Ainsi que le montre le fragment de grammaireci-dessus, les expressions gardées ne sont donc pas des expressions « autonomes »,il s’agit d’une notion auxiliaire pour définir les conditionnelles.

Substitution Définition Ident.

[x := E](G→ F ) [x := E]G⇒ [x := E](G→ F ) = [x := E]F (1.4.3)

[x := E]

⎛⎜⎜⎜⎜⎜⎜⎜⎝

if G1 →F1

| G2 →F2

fi

⎞⎟⎟⎟⎟⎟⎟⎟⎠

[x := E](G1 → F1) ∧ [x := E](G2 → F2) (1.4.4)

4. « Garde démontrable » serait plus approprié. Nous admettons cet abus de langage dansla suite.

5. Il ne s’agit pas d’un choix aléatoire mais d’un choix non déterministe. Il n’est par exemplepas question d’utiliser ce type d’alternative pour effectuer un tirage aléatoire. Le mode de miseen œuvre dans un compilateur est en général une version « déterminisée » de la spécification.

Page 39: Structures de données et méthodes formelles ||

26 Structures de données et méthodes formelles

Les expressions let

Elles se définissent par :

expression : := . . . ||let listeRemp in expression end

listeRemp : := listeVar := listeExplisteExpr : := expression ||

expression, listeExpr

Une expression let permet d’introduire un identificateur auxiliaire et de luiattribuer une valeur. Les éléments de listeV ar et de listeExp se correspondenten nombre et en type. Il convient de ne pas confondre les variables de la listeRempavec des variables telles qu’elles existent en programmation impérative dans lamesure où, ici, aucune variable ne change de valeur. Il s’agit plutôt de constantesdont la valeur est déterminée au cours de l’exécution. Cette construction a pourobjectif d’éviter d’évaluer plusieurs fois une même sous-expression apparaissantdans l’expression entre in et end.

Le tableau ci-dessous fournit la définition d’une expression de type let.

Notation Définition

let x := E in F end [x := E]F

1.5 ÉgalitéCette section étend à nouveau le langage des prédicats en introduisant l’éga-

lité entre deux expressions. Syntaxiquement ceci revient à ajouter la règle sui-vante à la catégorie syntaxique prédicat :

prédicat : := . . . ||expression = expression

Cette extension exige d’introduire les nouvelles règles d’inférence suivantes :

Antécédent Conséquent

[x := F ]H, E = F [x := F ]P [x := E]H, E = F [x := E]P

[x := E]H, E = F [x := E]P [x := F ]H, E = F [x := F ]P

Les cas particuliers (réflexivité, égalité de deux couples, d’expressions compre-nant une conditionnelle) sont traités comme des notations par le biais des défi-nitions suivantes :

Notation DéfinitionE = E �(E �→ F ) = (G �→ H) E = G ∧ F = H

E = (P → F ) P ⇒ E = F

E = (if F | G fi) E = F ∧ E = G

Page 40: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 27

Montrons sur l’exemple 5 = if x = 5 → x+ 3 | x > 12 → 2 · x fi commentse traduit une égalité comportant une conditionnelle :

5 = if x = 5→ x+ 3 | x > 12→ 2 · x fi⇔ Définition de = pour les conditionnelles5 = (x = 5→ x+ 3) ∧ 5 = (x > 12→ 2 · x)

⇔ Définition de = pour les expressions gardéesx = 5 ⇒ 5 = x+ 3 ∧ x > 12 ⇒ 5 = 2 · x

La démonstration de cette dernière formule repose sur l’utilisation des règlesd’inférence pour l’égalité.

L’opérateur = est une extension de notation qui se définit comme la négationd’une formule avec égalité. Cette définition n’est pas formalisée ici, pas plus quela négation des autres opérateurs relationnels traditionnels (comme /∈ pour lesensembles).

1.6 Théorie des ensemblesLe langage de la théorie des ensembles étend le langage des prédicats en

autorisant des prédicats conformes à la syntaxe suivante :

prédicat : := . . . ||expression ∈ expression

où l’expression à droite du symbole ∈ (symbole d’appartenance) représente unensemble. Les trois constructions de base permettant d’obtenir des ensemblessont décrites syntaxiquement par :

expression : := . . . ||expression× expression ||P(expression) ||{listeVar · prédicat | expression}

Ces constructions représentent respectivement le produit cartésien, l’ensembledes parties et la définition en compréhension. Avant d’aborder l’aspect axio-matique de ces nouvelles constructions, fournissons quelques exemples intuitifs.Bien qu’elles ne soient pas formellement définies pour l’instant, nous supposonsdisponibles les notions d’ensembles définis en extension, l’égalité d’ensembles etla notation ∅ d’ensemble vide. Si s = {1, 2, 3} et t = {a, b, c}, alors :

s× t = {1 �→ a, 2 �→ a, 3 �→ a, 1 �→ b, 2 �→ b, 3 �→ b}P(s) = {∅, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}{x ·x ∈ s | x+ 1} = {2, 3, 4}

Pour l’opérateur de définition en compréhension, il existe une notation abrégéedans le cas où l’expression est réduite à la variable x comme dans {x ·P | x}.Dans ce cas, on adopte la notation {x | P}. Les trois constructions ci-dessus sont

Page 41: Structures de données et méthodes formelles ||

28 Structures de données et méthodes formelles

définies pas trois axiomes. Cependant, pour respecter l’esprit de la méthode Bet contrairement à ce que nous avons pratiqué jusqu’à présent, ces trois axiomessont exprimés comme des extensions notationnelles du langage des prédicats« pur ». Il en résulte que la démonstration d’un prédicat « ensembliste » sefait en traduisant ce dernier dans une formule du langage prédicatif pur, avantd’effectuer la preuve en logique des prédicats.

Axiome Traduction Condition Ident.

E �→ F ∈ S × T E ∈ S ∧ F ∈ T (1.6.1)E ∈ P(S) ∀x ·(x ∈ E ⇒ x ∈ S) x\E, x\S (1.6.2)E ∈ {x ·P | F} ∃x ·P ∧ E = F x\E (1.6.3)

Montrons sur un exemple comment peut se prouver un prédicat ensembliste.En anticipant quelque peu, la notation classique s ⊆ t est définie par s ∈ P(t).Cherchons alors à prouver le séquent s ⊆ s. La définition de la notation ⊆fournit la traduction

s ∈ P(s)

Nous pouvons alors appliquer la règle 1.6.2 ci-dessus afin d’obtenir :

∀x ·(x ∈ s⇒ x ∈ s)

La règle d’inférence 1.4.2 du calcul des prédicats (page 24) nous permet desupprimer le quantificateur. Nous avons alors :

x ∈ s⇒ x ∈ s

La présence du symbole ∈ peut sembler gênante de prime abord : nous ne dispo-sons d’aucun moyen pour l’éliminer ni pour le transformer. Qu’à cela ne tienne !Il suffit de considérer toute formule de ce type comme une variable proposition-nelle. Cette transformation n’altère pas son caractère démontrable ou non. Donc,si nous posons P = x ∈ s, notre démonstration se réduit à prouver le séquent P ⇒ P . Cette preuve s’obtient par application de la règle 1.3.6, page 21, puisde l’axiome 1.2.2, page 20.

Nous venons d’étudier les trois opérateurs de construction d’ensembles. Nousn’en avons pas tout à fait terminé avec les bases de la théorie des ensembles. Ilnous reste à considérer deux axiomes : l’axiome de choix et l’axiome de l’égalité.La catégorie syntaxique expression s’enrichit de la règle suivante :

expression : := . . . ||choice(expression)

Et l’axiome de choix qui correspond à cette extension est défini par :

Axiome Condition

choice(S) ∈ S ∃x ·(x ∈ S) ∧ x\S

Page 42: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 29

Cet axiome précise que si un ensemble n’est pas vide, l’application de l’opérationchoice sur cet ensemble délivre l’un des éléments de cet ensemble. Cet axiometrouve son utilité notamment dans la définition d’expressions non déterministes(cf. section 1.6.2). L’axiome de l’égalité se présente sous la forme :

Axiome Traduction

S = T S ∈ P(T ) ∧ T ∈ P(S)

1.6.1 Opérations ensemblistes traditionnelles

Le reste de la section 1.6 est constitué d’extensions à la théorie de base quenous venons d’étudier. Nous allons donc principalement introduire et définir desnotations. La maîtrise de ces notations est fondamentale pour la compréhensiondu reste de l’ouvrage et pour son utilisation pratique. Tout d’abord, nous in-troduisons syntaxiquement l’opérateur relationnel ⊆, qui sert à construire desprédicats ensemblistes. Sa syntaxe est décrite par :

prédicat : := . . . ||expression ⊆ expression

Les deux expressions sont des expressions ensemblistes. Ainsi que nous l’avonsdit ci-dessus, cet opérateur se définit par :

Notation DéfinitionS ⊆ T S ∈ P(T )

Les opérations classiques d’union, d’intersection, de différence, de définitionen extension et l’ensemble vide se décrivent syntaxiquement par les règles sui-vantes :

expression : := . . . ||expression ∪ expression ||expression ∩ expression ||expression− expression ||{listeExpr} ||∅

Ainsi {3, 4+5, 8} est un ensemble défini en extension. Ces notations se définissentpar :

Notation Définition Ident.E ∈ S ∪ T E ∈ S ∨ E ∈ T (1.6.4)E ∈ S ∩ T E ∈ S ∧ E ∈ T (1.6.5)E ∈ {e1, e2 . . . , en} E = e1 ∨ E = e2 ∨ . . . ∨ E = en (1.6.6)E ∈ ∅ ⊥ (1.6.7)

Page 43: Structures de données et méthodes formelles ||

30 Structures de données et méthodes formelles

Les seules propriétés de ces notations exploitées ensuite sont celles de l’an-nexe A, regroupées dans le tableau dénommé « Propriétés des ensembles ».

De même que ∀ est le quantificateur qui généralise l’opérateur binaire ∧,de même

⋃(resp.

⋂) est le quantificateur qui généralise l’opérateur binaire

ensembliste ∪ (resp. ∩). La syntaxe de ces deux nouveaux quantificateurs sedéfinit par :

expression : := . . . ||⋃listeVar ·(prédicat | expression) ||⋂listeVar ·(prédicat | expression)

Ainsi par exemple⋃

i ·(i ∈ 1..3 | {i, i+1, i+2}) définit l’union des trois ensembles{1, 2, 3}, {2, 3, 4} et {3, 4, 5}. Cette expression est donc égale à {1, 2, 3, 4, 5}. Dela même façon

⋂i ·(i ∈ 1 .. 3 | {i, i+ 1, i+ 2}) est égal à l’intersection des trois

ensembles {1, 2, 3}, {2, 3, 4} et {3, 4, 5}, et vaut donc {3}. Ces deux notations sedéfinissent par les règles de traduction suivantes :

Notation Définition Condition

E ∈ ⋃ i ·(P | F ) ∃i ·(P ∧ E ∈ F ) i\EE ∈ ⋂ i ·(P | F ) ∀i ·(P ⇒ E ∈ F ) i\E

1.6.2 Choix dans un ensembleDans les chapitres qui suivent, il nous arrive fréquemment d’avoir à formaliser

une affirmation telle que « a est un élément quelconque d’un ensemble E », Eétant défini en compréhension. L’opérateur de choix et la notion d’ensemblesdéfinis en compréhension se marient au sein de la construction « choix dans unensemble » pour offrir cette possibilité. La syntaxe de cette construction est :

expression : := . . . ||any listeVar where prédicat then expression end

Ainsi par exemple l’expression

any e wheree ⊆ 1 .. 100∧(7 ∈ e ∨ 23 ∈ e)

thene− {49}

end

dénote un sous-ensemble de valeurs comprises entre 1 et 100 contenant 7 et/ou23 mais ne contenant pas 49. La règle de traduction pour cette expression estdonnée par :

Notation Définition

any E where P then F end choice({E ·P | F})

Page 44: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 31

Il existe une notation abrégée pour ce type d’expression : E : (P | F ). Parailleurs, dans le cas où E = F , la syntaxe se simplifie en any E where P end(dont la notation abrégée est E : P ). La traduction est donnée par :

Notation Définition

any E where P end any E where P then E end

1.6.3 Relations binaires

Cette section introduit les relations binaires. Notre langage exclut les rela-tions d’arité supérieure à 2, cependant une relation peut avoir comme ensemblesource ou destination une autre relation. Les règles suivantes introduisent les no-tions de relation entre deux ensembles (↔), de domaine (dom) et de codomaine(ran) d’une relation :

expression : := . . . ||expression↔ expression ||dom(expression) ||ran(expression)

Ces notations se définissent comme le montre le tableau suivant :

Notation Définitionr ∈ S ↔ T r ⊆ S × T

E ∈ dom(r) ∃y ·(E �→ y ∈ r)

E ∈ ran(r) ∃x ·(x �→ E ∈ r)

Le schéma suivant illustre ces trois notions, pour une relation r entre les en-sembles S et T :

×××

××

××

××

STrdom(r)

ran(r)

Les notations pour la relation inverse (r−1), la restriction (U � r), la cores-triction (r � V ), l’antirestriction (U �− r), l’anticorestriction (r �− V ) et l’imaged’un ensemble par une relation sont prises en compte syntaxiquement par lesrègles suivantes :

Page 45: Structures de données et méthodes formelles ||

32 Structures de données et méthodes formelles

expression : := . . . ||expression−1 ||expression� expression ||expression� expression ||expression�− expression ||expression�− expression ||expression[expression]

Elles se définissent comme suit :

Notation DéfinitionE �→ F ∈ r−1 F �→ E ∈ r

E �→ F ∈ S � r E ∈ S ∧ E �→ F ∈ r

E �→ F ∈ r � T F ∈ T ∧ E �→ F ∈ r

E �→ F ∈ S �− r E /∈ S ∧ E �→ F ∈ r

E �→ F ∈ r �− T F /∈ T ∧ E �→ F ∈ r

F ∈ r[U ] F ∈ ran(U � r)

Le diagramme sagittal ci-dessous illustre les notions de restriction et de cores-triction :

×××

××

××

××

S TU � rU

Restriction de r par U

×××

××

××

××

S Tr � V V

Corestriction de r par V

L’antirestriction et l’anticorestriction sont les opérations duales de la restrictionet de la corestriction comme le montre le schéma suivant :

×××

××

××

××

S TU �− rU

Antirestriction de r par U

×××

××

××

××

S Tr �− V V

Anticorestriction de r par V

Page 46: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 33

L’image d’un ensemble U par une relation r, notée r[U ], est constituée detous les points de l’ensemble destination atteints par les couples issus de U . Unexemple est fourni par le schéma suivant :

×××

××

××

××

S TU

Image de U par r

r r[U ]

La dernière série d’opérateurs ensemblistes purs est constituée des deux opé-rateurs de composition de relation que sont ; et ◦ et de l’opérateur de surcharge�−. Leur syntaxe est donnée par les règles suivantes :

expression : := . . . ||expression ; expression ||expression ◦ expression ||expression�− expression

l’opérateur ◦ est l’opérateur de composition classique, ; est une notation alter-native pour ◦ (r ; t = t◦r), tandis que la surcharge de la relation r par la relationt est constituée de l’ensemble des couples de t plus l’ensemble des couples de rdont l’origine n’est pas l’origine d’un couple de t.

Notation Définition ConditionE �→ F ∈ (f ; g) ∃x ·(E �→ x ∈ f ∧ x �→ F ∈ g) x\E, x\F, x\f, x\gE �→ F ∈ (g ◦ f) F �→ E ∈ (f ; g)E �→ F ∈ r �− t E �→ F ∈ (dom(t)�− r) ∪ t

Le schéma ci-dessous présente un exemple de composition entre deux rela-tions r et t.

×××

××

××

××

×××

××

S UTr t

×××

××

×××

××

S U

r; t

Composition des relations r et t

Page 47: Structures de données et méthodes formelles ||

34 Structures de données et méthodes formelles

La surcharge de r par t est illustrée par le diagramme sagittal suivant :

×××

××

××

××

S Ttr

×××

××

××

××

S Tr �− t

Les annexes A et B fournissent un catalogue de propriétés pour les opérateursétudiés dans la présente section. Ces propriétés sont utilisées régulièrement dansle développement de structures de données.

1.6.4 FonctionsLes fonctions sont des cas particuliers de relations (toute fonction est une

relation). Ainsi que nous l’avons vu dans l’exemple introductif de la section 1.1(le problème des huit reines), il convient de distinguer différentes catégories defonctions selon que leur domaine s’identifie à l’ensemble origine, le codomaineà l’ensemble destination, ou que la relation inverse est aussi une fonction. Lasyntaxe de ces différents cas est conforme aux règles suivantes :

expression : := . . . ||expression �→ expression ||expression→ expression ||expression �� expression ||expression� expression ||expression �� expression ||expression� expression ||expression�� expression

Le symbole de base est →. Trois signes diacritiques indépendants peuvent enri-chir cette notation pour donner l’un des six autres symboles ci-dessus. La barreverticale �→ signale que la fonction est partielle (son domaine est inclus dansl’ensemble origine), l’empennage � est la marque d’une fonction injective (larelation inverse est une fonction), la coiffe � désigne des fonctions surjectives(le codomaine est identique à l’ensemble de destination) 6. Par exemple à la sec-tion 1.1 nous avons écrit q ∈ 1 .. 8�� 1 .. 8 pour signifier que q est un élémentde l’ensemble des fonctions totales injectives et surjectives (bijectives donc) del’intervalle 1 .. 8 sur lui-même.

Afin d’éviter toute méprise, il convient d’insister sur le fait que si f ∈ E��Falors f ∈ E � F , que si f ∈ E � F alors f ∈ E → F , que si f ∈ E → F

6. La combinaison des trois diacritiques, qui symboliserait des bijections partielles, n’estpas autorisée par les règles syntaxiques ci-dessus.

Page 48: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 35

alors f ∈ E �→F , etc. Les sept types de fonctions définis ci-dessus sont de ce faitinterdépendants : la relation d’ordre partielle définit un treillis (cf. exercice 1.6.6).

Lambda abstractions

Les lambda abstractions constituent un moyen de définir des fonctions ano-nymes. Le principe consiste à préciser comment un élément du codomaine esten relation avec un élément du domaine, sans pour cela fournir la liste exhaus-tive des couples. Ainsi, si nous souhaitons définir une fonction qui, à chaqueélément de l’intervalle 1 .. 10 associe son double, nous pouvons écrire la lambdaabstraction suivante :

λi ·(i ∈ 1 .. 10 | 2 · i)

La syntaxe d’une telle construction se décrit par la règle syntaxique suivante :

expression : := . . . ||λlisteVar ·(prédicat | expression)

La définition est formalisée par la règle suivante :

Notation Définition Ident.E �→ F ∈ λi ·(P | G) [i, j := E,F ](P ∧ j = G) (1.6.8)

qui fournit la condition d’appartenance d’un couple à une lambda abstraction.

Évaluation de fonctions

L’évaluation de fonctions se décrit syntaxiquement par la règle suivante :

expression : := . . . ||expression(expression)

La définition d’une telle expression exige que la première expression soit unefonction et que la seconde, son argument, fasse partie du domaine de la fonction.On a alors :

Notation Définition Condition

F = f(E) E �→ F ∈ f E ∈ dom(f)

En reprenant la fonction définie par une lambda abstraction ci-dessus, nous avonsλi ·(i ∈ 1 .. 10 | 2 · i)(8) = 16.

Page 49: Structures de données et méthodes formelles ||

36 Structures de données et méthodes formelles

Remarque (à propos de l’ensemble R des réels). Cet ensemble n’est uti-lisé que lors des calculs de complexité. Les deux fonctions �x� (fonction plancher)et �x� (fonction plafond) définies sur R et à valeur dans Z sont les seules fonc-tions à argument réel utilisées dans la suite. Elles se définissent par :

Notation Définition Ident.�x� max({n | n ∈ Z ∧ n ≤ x}) (1.6.9)�x� max({n | n ∈ Z ∧ n ≥ x}) (1.6.10)

Certaines des propriétés des fonctions apparaissent dans les annexes A et Bconsacrées aux relations, d’autres sont présentées dans les annexes C ou D.

Exercices

Exercice 1.6.1 Fournir l’extension de l’ensemble suivant, décrit en compréhension : {i | i ∈1 .. 10 ∧ i+ 3 < 12}.

Exercice 1.6.2 Soit E = {1, 2} et F = {a, b, c}. Fournir l’extension de : (i) E×F, (ii) E→F,(iii) E � F, (iv) P(E), (v) P(E)× F, (vi) P(E × F ).

Exercice 1.6.3 Exprimer par une lambda abstraction la fonction suivante décrite par unensemble défini en extension : {1 �→ 4, 2 �→ 8, 3 �→ 12, 4 �→ 16}.

Exercice 1.6.4 Soit f la fonction suivante λi ·(i ∈ 1 .. 10 | i ∗ 3) �− {5 �→ 8, 7 �→ 4}. Évaluerf(6) puis f(5).

Exercice 1.6.5 Soit l’ensemble suivant défini en compréhension : {(i, j) | i ∈ 1 .. 10 ∧ j ∈N ∧ j = i+ 3}.

1. Fournir l’extension de cet ensemble.2. Cet ensemble est-il une fonction ? Si oui définir cet ensemble par une lambda abstrac-

tion.

Exercice 1.6.6 La relation d’inclusion sur les différents types de fonctions possibles (cf. sec-tion 1.6.4) induit une structure de treillis. Déterminer ce treillis.

1.7 Ensembles particuliers

Cette section introduit, de manière informelle, des ensembles particuliers dontnous aurons rapidement l’usage (c’est déjà fait pour les entiers naturels). Il s’agitprincipalement des entiers naturels N et relatifs Z, des booléens bool et desensembles de caractères char. Il convient de ne pas confondre les prédicats (quisont rappelons-le des entités que l’on démontre) et les booléens, qui ont le statutd’expression (que l’on évalue donc).

Page 50: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 37

expression : := . . . ||bool ||true ||false ||bool(prédicat)char ||′a′ ||′ b′ || . . . ||′ 9′ ||Z ||N ||N1 ||∞ ||0 || 1 || . . . ||+expression ||−expression ||expression+ expression ||expression÷ expression ||expression mod expression ||expression · expression ||expressionexpression

Dans la suite nous considérons que N et Z sont des ensembles finis dont leplus grand élément est représenté par ∞ (d’un point de vue programmationcette valeur peut en général être identifiée au plus grand entier représentablesur une machine). La plus petite valeur de l’ensemble Z est représentée par −∞qui s’identifie au plus petit entier représentable. L’ensemble bool est constituédes deux constantes true et false tandis que l’ensemble N1 est l’ensemble desentiers naturels privé de la valeur 0. L’opérateur ÷ (resp. mod) délivre le quotient(resp. le reste) de la division entière. La fonction bool convertit un prédicat enune expression booléenne. Elle est définie par :

Notation Définitionbool(⊥) false

bool(�) true

Concernant les entiers naturels ou relatifs, les opérateurs relationnels clas-siques (<, ≤, etc.) permettent de construire des prédicats. L’opérateur .. délivreun intervalle d’entiers, l’opérateur card appliqué à un ensemble renvoie le nombred’éléments présents dans cet ensemble. L’opérateur max (resp. min) appliqué àun ensemble d’entiers quelconque délivre le plus grand élément de cet ensemble.Adhérant en cela aux conventions adoptées dans [67] et dans [31], nous admet-tons que max(∅) = −∞ et que min(∅) =∞. Les règles de grammaire décrivantces expressions sont présentées ci-dessous.

Page 51: Structures de données et méthodes formelles ||

38 Structures de données et méthodes formelles

prédicat : := . . . ||expression ≤ expression ||expression < expression ||expression ≥ expression ||expression > expression

expression : := . . . ||expression .. expression ||card(expression) ||max(expression) ||min(expression)

Les opérateurs + (somme) et · (produit) se généralisent comme traditionnel-lement pour devenir les quantificateurs

∑et∏, selon la syntaxe :

expression : := . . . ||∑listeVar ·(prédicat | expression) ||∏listeVar ·(prédicat | expression)

Nous pouvons ainsi écrire la formule classique qui fournit la somme des n pre-miers entiers

∑i ·(i ∈ 1 .. n | i) = (n ·(n+ 1))÷ 2. Nous pourrons parfois noter

ce type de formule∑n

i=1 i =n ·(n+1)

2 ou encoren∑

i=1

i =n ·(n+ 1)

2.

Les opérateurs de translation �� et de décalage � s’appliquent respective-ment à un sous-ensemble de Z et à une relation dont l’ensemble origine estcontenu dans Z. Syntaxiquement ils se présentent par :

expression : := . . . ||expression�� expression ||expression� expression ||

L’opérateur �� permet de translater un sous-ensemble fini de relatifs d’un cer-tain nombre de positions. Ainsi par exemple l’ensemble {−6,−1, 4, 8, 10}��−2est égal à {−8,−3, 2, 6, 8}. L’opérateur � s’applique à une relation dont le do-maine est un sous-ensemble fini de Z. Dans la suite nous l’utilisons le plus sou-vent sur des tableaux (c’est-à-dire des fonctions totales définies sur un intervalle).Ainsi, si f = {3 �→ 7, 4 �→ 4, 5 �→ 5, 6 �→ 13}, f � 2 = {5 �→ 7, 6 �→ 4, 7 �→ 5, 8 �→13}, tandis que f �−2 = {1 �→ 7, 2 �→ 4, 3 �→ 5, 4 �→ 13}. Ces notations sedéfinissent de la manière suivante :

Notation Définition Condition Ident.

a�� v ran(λi ·(i ∈ a | i+ v)) a ∈ P(Z) ∧ v ∈ Z (1.7.1)f � v (λi ·(i ∈ dom(f) | i+ v))−1; f f ∈ Z↔ s ∧ v ∈ Z (1.7.2)

Page 52: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 39

Les tableaux de l’annexe D intitulés « Propriétés du décalage » et « Propriétésde la translation » regroupent un certain nombre de propriétés portant sur lesopérateurs � et ��.

Tableaux

Parmi les ensembles particuliers intéressants pour l’étude des structures dedonnées se trouvent les tableaux. Un tableau (à une dimension) est une fonctiontotale définie sur un intervalle fini (éventuellement vide) d’entiers relatifs et àvaleur dans un ensemble quelconque. tab(s) représente l’ensemble de tous lestableaux qu’il est possible de définir à valeur dans s.

expression : := . . . ||tab(expression)

Notation Définition Ident.

tab(s)⋃(i, j) ·(i, j ∈ Z× Z | i .. j → s) (1.7.3)

Le cas où la fonction qui définit le tableau est une fonction injective est un casparticulier que nous rencontrons parfois. Un tel tableau est qualifié de « tableausans doublon ».

Exercices

Exercice 1.7.1 Démontrer les propriétés répertoriées dans l’annexe D portant sur l’opérateurde décalage de fonction �.

Exercice 1.7.2 On considère l’opérateur de décalage de relation défini par la notation 1.7.2,page ci-contre, avec la restriction v ∈ N. Fournir une définition alternative inductive. Montrerl’équivalence de ces deux définitions.

Exercice 1.7.3 À quelle condition la surcharge d’un tableau t1 par un tableau t2 est-elleencore un tableau ? Effectuer la démonstration.

Exercice 1.7.4 Soit t1 ∈ 1 .. 3→ N et t2 ∈ 1 .. 4→ N deux tableaux. Soit t3 l’expressionsuivante :

t1 �− t2� card(t1)

1. Montrer que t3 est bien un tableau (cf. exercice 1.7.3).2. Calculer la valeur de t3 si t1 = {1 �→ 6, 2 �→ 8, 3 �→ 4} et t2 = {1 �→ 10, 2 �→ 9, 3 �→11, 4 �→ 5}.

Exercice 1.7.5 Montrer que si n ∈ N, 1 .. n+ 1− {n+ 1} = 1 .. n

Exercice 1.7.6 Soit t ∈ 1 .. 100→ N et v ∈ N.1. Exprimer le prédicat « v est l’une des valeurs du tableau t ».2. Exprimer le prédicat « v est dans la première moitié du tableau t ».

.

Exercice 1.7.7 Soit t un tableau défini par t ∈ 1 .. 100→ N. Simplifier quand c’est possibleles expressions ensemblistes suivantes :

Page 53: Structures de données et méthodes formelles ||

40 Structures de données et méthodes formelles

– 1 .. 50� (t�− {65 �→ 12, 30 �→ 17}),– (1 .. 50� t)�− {65 �→ 12, 30 �→ 17}.

Exercice 1.7.8 Soit n ∈ N1 et t le tableau défini par t ∈ 1 .. n→ Z. Exprimer le prédicat quiaffirme que tous les éléments de t sont identiques.

Exercice 1.7.91. Soit t défini par t ∈ 1 .. 100→ N. Exprimer que t est trié par ordre croissant.2. Soit s défini par s ∈ 1 .. 100� N. Exprimer que s est trié par ordre croissant.

Exercice 1.7.10 Soit n ∈ N1, m ∈ N1 et t le tableau défini par t ∈ 1 .. n×1 ..m→N. Spécifierl’opération qui délivre true si et seulement s’il existe au moins une « ligne » de t ne contenantque des zéros.

Exercice 1.7.11 Soit n ∈ N1 et soit t le tableau défini par t ∈ 1 .. n→ N.1. Spécifier que pour i et s donnés tels que i ∈ 1 .. n et s ∈ i .. n, le sous-tableau i .. s� t

est une succession d’entiers consécutifs.2. Spécifier l’ensemble des longueurs des sous-tableaux de t ne contenant que des entiers

consécutifs.3. Spécifier l’expression qui délivre la longueur du plus long sous-tableau de t contenant

des entiers consécutifs.

Exercice 1.7.12 Soit n ∈ N1 et soit t le tableau défini par t ∈ 1 .. n�N. Spécifier l’expressionqui délivre la somme des valeurs situées entre le plus grand et le plus petit élément de t.

Exercice 1.7.13 Soit n ∈ N et soit t le tableau défini par t ∈ 1 .. n→ Z. Spécifier la formulequi exprime la plus grande valeur que peut prendre la somme des éléments d’un sous-tableaulorsque l’on considère tous les sous-tableaux de t.

Exercice 1.7.14 Soit n ∈ N1 et soit t le tableau défini par t ∈ 1 .. n → Z. Soit p ∈ 1 .. net v ∈ Z. Pour chacune des expressions ci-dessous, dire si le résultat est ou non un tableau.Caractériser, par une phrase en français, la nature de ce résultat.

1. ((1 .. p� t) ∪ (p+ 1 .. n� t)� 1)�− {p+ 1 �→ v},2. (1 .. p� t)�n− p ∪ (p+ 1 .. n� t)�−p.

Exercice 1.7.15 Soit n ∈ N1 et soit t le tableau défini par t ∈ 1 .. n→ Z.1. On appelle décalage logique à droite de p positions (p ∈ 1 .. n) du tableau t l’opération

aboutissant au tableau débutant par p zéros suivis des éléments du tableau t situés entreles positions 1 et n− p. Spécifier formellement, en utilisant l’opérateur de décalage �,la notion de décalage logique à droite.

2. On appelle décalage circulaire à droite de p positions (p ∈ 1 ..n) du tableau t l’opérationaboutissant au tableau débutant par les p derniers éléments de t suivis des n−p premierséléments de t. Spécifier formellement, en utilisant l’opérateur de décalage �, la notionde décalage circulaire à droite.

1.8 Exemple de modélisation ensemblisteEn guise de bilan pour le début du chapitre 1 nous étudions une modélisa-

tion de la notion de tutelle. Avant d’aborder le cœur de la modélisation, nousdevons au préalable disposer des notions d’individu vivant (indiv), d’âge (age),de sexe (sexe), d’homme (homme), de femme (femme), de mineur (mineur),de majeur (majeur), de père (pere), de mère (mere) et de parents (parents).Une formalisation possible de cette modélisation est donnée par :

indiv ∈ N ∧

Page 54: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 41

age ∈ indiv→ 0 .. 130 ∧sexe ∈ indiv→{masc, fem} ∧homme = dom(sexe� {masc}) ∧femme = dom(sexe� {fem}) ∧mineur = dom(age� 0 .. 17) ∧majeur = indiv −mineur ∧pere ∈ indiv �→ homme ∧mere ∈ indiv �→ femme ∧parents = pere ∪ mere

Si nous souhaitons modéliser le fait que les parents sont plus âgés que leursenfants, nous pouvons écrire :

age−1 ; parents ; age ⊆ {i, j | i ∈ 0 .. 130 ∧ j ∈ 0 .. 130 ∧ i < j}

Cette formule se paraphrase en disant que la relation qui lie l’âge d’un individuà celui de ses parents est « croissante » (tout entier n’est en relation qu’avec desentiers supérieurs) ; ci-dessus l’ensemble défini en compréhension est une relationqui associe à tout élément de l’intervalle 0 .. 130 les entiers de cet intervalle quilui sont supérieurs.

Nous en arrivons aux notions relatives à la tutelle. Nous avons besoin desconcepts suivants :

– aPourTuteur, relation qui désigne le ou les tuteurs d’un individu (les deuxparents peuvent être tuteurs de leurs enfants) ;

– dechu, certains individus majeurs sont déchus de leurs droits, ils ne peuventêtre tuteurs ;

– incapable, selon le vocabulaire juridique, un individu sous tutelle (mineurou majeur) est appelé un incapable ;

– tuteurPot, (tuteur potentiel) il s’agit des individus qui peuvent légalementêtre tuteurs. Il s’agit des majeurs qui ne sont ni déchus ni incapables.

Ces notions peuvent être formalisées par :

aPourTuteur ∈ indiv↔majeur∧dechu ⊆ majeur∧incapable = dom(aPourTuteur)∧tuteurPot = majeur − (dechu ∪ incapable)

Les règles suivantes doivent être modélisées :1. Tout individu mineur a au moins un tuteur et certains individus majeurs

ont un tuteur.2. Un parent majeur, qui n’est ni déchu ni incapable, est tuteur de ses enfants

incapables (mineurs ou majeurs sous tutelle). Un individu peut donc avoirdeux tuteurs.

3. Si (au moins) l’un des parents est tuteur d’un individu, ce dernier ne peutavoir de tuteur « étranger ».

4. Un incapable orphelin, ou dont aucun des deux parents ne peut être tuteur,a comme unique tuteur un individu habilité à l’être.

5. Tout individu habilité à être tuteur peut être le tuteur d’un nombre quel-conque de personnes.

Page 55: Structures de données et méthodes formelles ||

42 Structures de données et méthodes formelles

Le point 1 se traduit par la formule :

mineur ⊆ incapable

La partie de la proposition qui affirme que certains individus majeurs ont un tu-teur n’a pas de formulation explicite. Le fait que l’on n’affirme pas quemineur =incapable laisse la possibilité à d’autres individus (les majeurs donc) d’être in-capables. Il ne faut surtout pas traduire ce point par majeur ∩ incapable = ∅qui signifierait qu’il existe toujours des majeurs incapables.

Le point 2 se formule par :

parents� tuteurPot ⊆ aPourTuteur

Autrement dit : un parent qui peut être tuteur est un tuteur de ses enfants.Le point 3 peut se formuler par :

dom(aPourTuteur ∩ parents) ∩ dom(aPourTuteur − parents) = ∅

qui signifie qu’il n’y a pas d’incapable qui aurait comme tuteurs un parent et unétranger.

Les points 4 et 5 se traduisent par :

aPourTuteur − parents ∈ indiv �→majeur

formule qui se paraphrase en affirmant qu’un tuteur qui n’est pas l’un des parentsest le seul tuteur pour l’individu considéré. La nature fonctionnelle de la relationrend compte du point 4 tandis que son caractère non injectif traduit la règle 5.

Exercices

Exercice 1.8.1 Introduire la notion d’orphelin dans l’exemple développé à la section 1.8. For-maliser l’affirmation qu’un orphelin mineur n’a qu’un seul tuteur. Démontrer cette affirmationà partir de la formalisation de la section 1.8.

Exercice 1.8.2 Dans l’exemple développé à la section 1.8, introduire la règle suivante quiconcerne les mineurs non orphelins : si tous les parents d’une telle personne sont sous tutellealors son tuteur est celui de l’un de ses parents.

Exercice 1.8.3 On considère la description géographique suivante :– il existe un ensemble de villes,– il existe un ensemble de pays,– une ville est située dans un et un seul pays,– tout pays possède une (et une seule) capitale,– les pays peuvent partager des frontières.

Modéliser cette description informelle. On s’assurera que l’on a bien spécifié que la capitaled’un pays est bien une ville de ce pays.

Page 56: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 43

1.9 Construction de structures inductivesLes structures construites en s’appuyant sur la théorie des ensembles sont en

général définies par induction. L’un des outils mathématiques les mieux adaptésest la théorie du point fixe (qui se conclut par les théorèmes de Knaster-Tarskiet le principe d’induction). Nous proposons de débuter cette section en passanten revue les éléments fondamentaux de cette théorie. Nous serons alors à mêmede l’appliquer à la construction de plusieurs structures intéressantes telles queles listes, certains arbres, les sacs (cf. chapitre 3). Des variantes de ces structuressont utilisées dans la partie II de l’ouvrage. Par contre, afin de ne pas alourdirle texte, ces variantes sont posées sans autres précautions, laissant au lecteurle soin de s’assurer de leur légitimité avant, s’il le souhaite, de les construire àpartir de la théorie des ensembles.

Soit T un ensemble non vide et soit f tel que f ∈ T → T . x ∈ T est unpoint fixe de f si x = f(x) (dans la suite la fonction f est appelée fonction« pivot »). Ainsi, −2 et 4 sont des points fixes de la fonction f ∈ Z→ Z définiepar f = λx ·(x ∈ Z | (x2 ÷ 2)− 4).

Pour notre propos, il est plus intéressant de considérer des fonctions f deP(T ) dans P(T ). Les arguments de f sont alors des ensembles et la conditionpour x d’être un point fixe peut se formuler par : x ⊆ f(x) ∧ f(x) ⊆ x. Soit φl’ensemble de tous les x tels que f(x) ⊆ x (φ = {x | x ∈ P(T ) ∧ f(x) ⊆ x}) etsoit fix(f) l’intersection généralisée de (tous les sous-ensembles de) φ : fix(f) =⋂

z ·(z ∈ φ | z). On montre (c’est l’un des deux théorèmes de Knaster-Tarski)que si f est monotone 7 alors fix(f) est un point fixe de f :

f ∈ P(T )→ P(T )∧∀(x, y) ·((x, y) ∈ P(T )× P(T ) ∧ x ⊆ y⇒ f(x) ⊆ f(y))

⇒f(fix(f)) = fix(f)

On montre en outre que fix(f) est le plus petit point fixe. On montre enfin (c’estle principe général d’induction) que pour prouver une propriété P pour tous leséléments de fix(f), il suffit de démontrer que :

f({x | x ∈ fix(f) ∧ P}) ⊆ {x | x ∈ fix(f) ∧ P}

En général, ce principe se simplifie selon la nature de la fonction f . Le chapitre 3offre plusieurs exemples de construction de structures inductives. Un cas fréquentimportant est celui des entiers naturels N. La section suivante lui est consacrée.

1.10 Démonstration par récurrenceLe terme français consacré pour l’induction sur N est « récurrence ». Bien

qu’il soit possible de construire N sur la théorie des ensembles selon les basesposées à la section précédente et d’en déduire des principes de récurrence (cf. [3]),nous supposons ici N donné (ou axiomatisé) et tenons pour acquis les principesde récurrence suivants :

7. f est monotone si et seulement si ∀(x, y) ·((x, y) ∈ P(T )× P(T ) ∧ x ⊆ y⇒ f(x) ⊆ f(y)).

Page 57: Structures de données et méthodes formelles ||

44 Structures de données et méthodes formelles

Théorème 1 (Principe de récurrence simple).[n := 0]P ∧∀n ·(n ∈ N ∧ P ⇒ [n := n+ 1]P )

⇒∀n ·(n ∈ N ⇒ P )

En pratique, démontrer P pour tout entier naturel n revient donc à décomposerla démonstration initiale en deux démonstrations a priori plus simples (appeléesrespectivement « étape de base » et « étape inductive ») :1. démontrer [n := 0]P ,2. démontrer [n := n+1]P sous les hypothèses P et n ∈ N (dites hypothèses

de récurrence).Il existe un principe de récurrence connu sous le nom de récurrence complète,

qui correspond au théorème suivant :

Théorème 2 (Principe de récurrence complète).∀n ·(n ∈ N ∧ ∀m ·(m ∈ N ∧m < n⇒ [n := m]P ) ⇒ P )

⇒∀n ·(n ∈ N ⇒ P )

À la différence du principe de récurrence simple (théorème 1), l’hypothèse Pporte ici sur toutes les valeurs de l’intervalle 0..n. Démontrer P pour tout n se faiten démontrant P sous les hypothèses n ∈ N et ∀m ·(m ∈ N∧m < n⇒[n := m]P ).Cette dernière hypothèse peut être instanciée pour toute valeur de m inférieureà n.

Prenons comme exemple de démonstration par le principe de récurrencesimple la propriété suivante :

P (n) =∑

j ·(j ∈ N ∧ j < n | 2j) = 2n − 1

(soit informellement 20+21+22+ · · ·+2n−1 = 2n−1). Nous avons à démontrerd’une part [n := 0]P et d’autre part [n := n+ 1]P sous les hypothèses n ∈ N etP . La démonstration de la base est triviale :

[n := 0](∑

j ·(j ∈ N ∧ j < n | 2j) = 2n − 1)⇔ Substitution∑

j ·(j ∈ N ∧ j < 0 | 2j) = 20 − 1⇔ Propriété de

∑et arithmétique

0 = 0⇔ Définition de l’égalité

Quant à la partie inductive de la démonstration, elle s’effectue de la manièresuivante :

[n := n+ 1](∑

j ·(j ∈ N ∧ j < n | 2j) = 2n − 1)⇔ Substitution∑

j ·(j ∈ N ∧ j < n+ 1 | 2j) = 2n+1 − 1⇔ n ∈ N et propriété de

Page 58: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 45

∑j ·(j ∈ N ∧ j < n | 2j) + 2n = 2n+1 − 1

⇔ Hypothèse d’induction P2n − 1 + 2n = 2n+1 − 1

⇔ Arithmétique2n+1 − 1 = 2n+1 − 1

⇔ Définition de l’égalité�

Récurrence et renforcementL’expérience montre que pour démontrer une proposition Q il est parfois

plus facile de démontrer une propriété plus forte P (P ⇒Q), puis d’en déduireQ, que de démontrer Q directement. Cette technique est particulièrement utilelorsqu’elle est utilisée conjointement avec un raisonnement par induction (ou parrécurrence). L’objectif de cette section est d’en fournir une illustration. Considé-rons l’exemple suivant de démonstration par récurrence (cet exemple est inspiréde [97], page 112). Soit à prouver pour tout n ∈ N la propriété P (n) définiepar 8 :

P (n) =n∑

i=0

i3 = (

n∑i=0

i)2

Ainsi que nous l’avons appris à travers le théorème 1, pour démontrer la propriétéP (n) pour tout n, il suffit d’une part de démontrer [n := 0]P (n) et d’autre partde démontrer [n := n + 1]P (n) sous les hypothèses n ∈ N et P (n). La base estfacile à démontrer. Arrêtons-nous sur la démonstration de [n := n+ 1]P (n) :

[n := n+ 1]P (n)⇔ Substitution

n+1∑i=0

i3 = (

n+1∑i=0

i)2

⇔ Propriété de∑

et hypothèse n ∈ Nn∑

i=0

i3 + (n+ 1)3 = (

n∑i=0

i+ (n+ 1))2

⇔ Arithmétique (identité remarquable)n∑

i=0

i3 + (n+ 1)3 = (

n∑i=0

i)2 + 2 ·(n+ 1) ·n∑

i=0

i+ (n+ 1)2

⇔ P (n) (hypothèse d’induction)n∑

i=0

i3 + (n+ 1)3 =

n∑i=0

i3 + 2 ·(n+ 1) ·n∑

i=0

i+ (n+ 1)2

⇔ Arithmétique

(n+ 1)3 = 2 ·(n+ 1) ·n∑

i=0

i+ (n+ 1)2

8. Le problème de savoir comment cette formule est conjecturée est largement développédans [97]. C’est également le thème sous-jacent à la notion d’induction constructive présentédans [17]. Il n’est par contre pas abordé ici.

Page 59: Structures de données et méthodes formelles ||

46 Structures de données et méthodes formelles

⇔ Arithmétique

2 ·(n+ 1) ·n∑

i=0

i = (n+ 1)3 − (n+ 1)2

⇔ Arithmétique

2 ·(n+ 1) ·n∑

i=0

i = (n+ 1)2 ·(n+ 1− 1)

⇔ Arithmétique

2 ·(n+ 1) ·n∑

i=0

i = n ·(n+ 1)2

⇔ Arithmétiquen∑

i=0

i =n ·(n+ 1)22 ·(n+ 1)

⇔ Arithmétiquen∑

i=0

i =n ·(n+ 1)

2

Appelons Q(n) cette dernière propriété. Le problème se réduit donc à démon-trer Q(n) pour tout n ∈ N. Il existe plusieurs façons d’atteindre ce but. Nouspourrions considérer que c’est un résultat connu. Nous pouvons aussi démontrerQ(n) en tant que lemme. Nous pouvons également tenter de démontrer non plusP (n) pour tout n mais P (n)∧Q(n) pour tout n. Cette dernière méthode consisteà renforcer la proposition initiale par le conjoint Q(n). C’est cette méthode quinous intéresse ici. Nous avons donc pour tout n ∈ N :

P (n) ∧Q(n) =

n∑i=0

i3 = (

n∑i=0

i)2 ∧n∑

i=0

i =n ·(n+ 1)

2

Bien entendu, si nous réussissons à démontrer P (n)∧Q(n) pour tout n nousaurons comme corollaire le théorème initial. Tentons cette démonstration. Labase [n := 0](P (n)∧Q(n)) est facile à démontrer. Démontrons [n := n+1](P (n)∧Q(n)) sous les hypothèses n ∈ N, P (n) et Q(n) (dans la suite, le calcul précédentn’est pas redéveloppé) :

[n := n+ 1](P (n) ∧Q(n))⇔ Substitution[n := n+ 1]P (n) ∧ [n := n+ 1]Q(n)

⇔ Calcul précédentn∑

i=0

i =n ·(n+ 1)

2∧ [n := n+ 1]Q(n)

⇔ Hypothèse Q(n) et calcul propositionnel[n := n+ 1]Q(n)

⇔ Substitution et arithmétiquen+1∑i=0

i =(n+ 1) ·(n+ 2)

2

⇔ Propriété de∑

et hypothèse n ∈ N

Page 60: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 47

n∑i=0

i+ (n+ 1) =(n+ 1) ·(n+ 2)

2

⇔ Hypothèse Q(n)n ·(n+ 1)

2+ (n+ 1) =

(n+ 1) ·(n+ 2)2

⇔ Arithmétique (non développé)(n+ 1) ·(n+ 2)

2=(n+ 1) ·(n+ 2)

2⇔ Définition de l’égalité

�Nous avons trouvé plus commode, pour démontrer un prédicat P , de dé-

montrer une proposition plus forte que P . C’est ce que, dans [97], G. Polyaappelle « le paradoxe de l’inventeur ». Le conjoint complémentaire Q(n) agit enquelque sorte comme un catalyseur : il facilite la démonstration de P (n) pourtout n avant d’être éliminé. Nous rencontrons au quotidien des professionnelsqui appliquent une technique similaire, sans que celle-ci nous apparaisse commeparadoxale. C’est par exemple le cas d’un entrepreneur en bâtiments, qui trouveplus pratique de construire une maison et un échafaudage en sachant pertinem-ment d’une part que l’échafaudage va faciliter les travaux et d’autre part qu’ilpourra aisément être démonté à la fin du chantier pour ne laisser voir que le ré-sultat attendu. Plus généralement, c’est le concept d’outil qui est exploité ici : ilest souvent plus rapide de perdre du temps à se forger un outil que de s’attaquerdirectement au problème.

À la section 2.4, nous revenons sur l’utilisation de cette technique appliquéeau renforcement de structures de données. Elle permet en particulier d’améliorerles performances de certaines opérations.

1.11 Opérations

1.11.1 IntroductionLes opérations sont destinées à construire les structures de données ou à

observer leur état. Le processus de développement exige de distinguer :– les opérations abstraites, qui interviennent dans la spécification abstraited’une structure de données ;

– les opérations concrètes, qui elles se définissent au sein d’une spécificationconcrète ;

– une opération particulière, qui apparaît dans la spécification concrète etqui fait le lien entre spécification concrète et spécification abstraite : lafonction d’abstraction.

Un critère complémentaire du précédent consiste à distinguer :– les opérations principales, accessibles depuis l’extérieur du type considéré ;– les opérations auxiliaires, qui sont des opérations outils uniquement desti-nées à faciliter l’expression des autres opérations.

Pour être complet, il convient de faire la distinction au sein des opérations prin-cipales, entre les opérations internes (qui délivrent une valeur du type considéré)et les autres, appelées opérations externes.

Page 61: Structures de données et méthodes formelles ||

48 Structures de données et méthodes formelles

Dans la suite de cette section, nous étudions tout d’abord un type parti-culier d’expression utilisé uniquement dans les opérations : les expressions pré-conditionnées. Nous définissons ensuite la notion d’opération avant d’examinercomment s’évalue une opération. Enfin nous étudions la propagation des précon-ditions au sein d’une opération. L’intérêt de ce dernier point se manifeste lorsdu calcul d’une opération : il est de déterminer les gardes des conditionnelles etde décider de la terminaison du développement.

1.11.2 Expression préconditionnée

La notion expressionPréc d’expression préconditionnée est nouvelle, elle estspécifique des opérations. Le concept est présenté et développé ci-dessous. Lesexemples des sections suivantes nous permettent de préciser informellement cer-tains aspects sémantiques.

expressionPréc : := preprédicat

thenexpression

end

Le tableau ci-dessous définit la substitution dans les expressions précondi-tionnées.

Substitution Définition Ident.

[x := E]

⎛⎜⎜⎜⎜⎜⎜⎜⎝

preP

thenF

end

⎞⎟⎟⎟⎟⎟⎟⎟⎠

[x := E]P ∧ [x := E]

⎛⎜⎜⎜⎜⎜⎜⎜⎝

preP

thenF

end

⎞⎟⎟⎟⎟⎟⎟⎟⎠

= [x := E]F (1.11.1)

Quant au tableau suivant, il définit les règles d’inférence pour les expressionspréconditionnées.

Antécédent Conséquent Ident.

H � P ∧ [x := F ]Q H � [x := pre P then F end]Q (1.11.2)

H � [x := pre P then F end]P H � P ∧ [x := F ]Q (1.11.3)

1.11.3 Définition des opérations

Malgré leur apparente diversité, les opérations présentent un caractère d’ho-mogénéité puisqu’il s’agit toujours de fonctions. Les principales différences avecles fonctions étudiées à la section 1.6.4 portent sur la notation et sur le faitqu’une opération peut être définie récursivement. Syntaxiquement une opéra-tion se présente sous la forme :

Page 62: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 49

opération : := function identificateur(listeVar) ∈ expression =expressionFonct

expressionFonct : := expression ||expressionPréc

Dans la première règle, la liste listeVar représente les paramètres formels del’opération et expression le type de la fonction (partielle, surjective, etc.). Lepassage de paramètres se fait « par valeur » ; ce point est précisé ci-dessous.

Exemples

function double(n) ∈ N→ N = 2 · n

L’opération double est une fonction totale dont le domaine de définition est N,l’ensemble de destination est également N. Cette fonction délivre le double del’argument n.

function applic(f, i) ∈ (1 .. 3→ N)× 1 .. 3→ N = f(i)

L’opération applic est une fonction qui a comme premier argument une fonctiontotale f de l’intervalle 1..3 dans N, comme second argument un entier naturel i del’intervalle 1 ..3 et qui délivre comme résultat la valeur résultant de l’applicationde f en i. applic({1 �→ 5, 2 �→ 45, 3 �→ 12}, 3) est un exemple d’application de lafonction applic qui s’évalue à 12.

Une expression préconditionnée (de la catégorie syntaxique expressionPréc)est destinée à préciser les contraintes imposées aux paramètres de la fonctionainsi que les relations qu’ils entretiennent. La précondition se comporte enquelque sorte comme un contrat entre le concepteur du programme et son uti-lisateur. Si la fonction est appliquée dans une situation où la précondition estsatisfaite, alors le concepteur de la fonction s’engage à ce qu’elle délivre bien lerésultat attendu. Dans le cas contraire, le contrat est rompu et le concepteurn’est pas engagé par ce qui peut survenir, comme un résultat dénué de sensou encore un débordement de la mémoire. La précondition doit permettre dedémontrer que tout appel à la fonction ne se fait que si la précondition est sa-tisfaite. L’exemple qui suit illustre la notion d’expression préconditionnée dansune opération.

Exemple

function divis(dd, ds) ∈ N× N �→ N =pre

ds = 0then

dd÷ dsend

Page 63: Structures de données et méthodes formelles ||

50 Structures de données et méthodes formelles

L’opération divis(dd, ds) est une fonction qui délivre le quotient de dd par ds àcondition que le diviseur ne soit pas nul. Toute application de cette fonction doits’assurer au préalable que la précondition est satisfaite. Par ailleurs, dès qu’uneopération est définie par une fonction partielle, elle doit être préconditionnée carle domaine d’application doit être précisé. Pour l’exemple ci-dessus, il aurait étépossible de définir plus simplement cette fonction par :

function divis(dd, ds) ∈ N× N1 → N = dd÷ ds

Il n’est cependant pas toujours possible de contraindre suffisamment l’ensembled’origine pour pouvoir se passer d’une précondition.

1.11.4 Évaluation des opérations

À la section précédente nous avons présenté informellement la notion d’éva-luation des opérations en un point. La présente section est destinée d’une partà formaliser cette notion et d’autre part à développer des exemples de diffi-culté croissante. La formule 1.11.4 ci-dessous dote l’évaluation d’une opérationd’une sémantique. Nous pouvons remarquer l’analogie entre la substitution d’uneexpression préconditionnée et celle d’une opération : dans les deux cas il s’agitd’une conjonction. Le typage des arguments dans une opération s’interprète donccomme une forme de précondition.

Notation Définition Ident.

function f(x) ∈ u �→ v = F [x := E]x ∈ u ∧ f(E) = [x := E]F (1.11.4)

Cette définition se généralise facilement au cas d’une opération à plusieurs ar-guments.

Ci-dessous nous illustrons, à travers trois exemples, l’évaluation formelled’opérations.

Exemples

Reprenons l’opération double de la section 1.11.3 afin d’évaluer sa va-leur au point 3. Appliquons la définition de l’évaluation d’une opération (for-mule 1.11.4) :

[n := 3]n ∈ N ∧ double(3) = [n := 3]2 · n⇔ Substitution3 ∈ N ∧ double(3) = 2 · 3

⇔ Arithmétique et calcul propositionneldouble(3) = 6

Pour le second exemple, reprenons cette fois l’opération divis de la sec-tion 1.11.3, page 48, appliquée au couple (4, 2). Instancier la formule 1.11.4 surcet exemple donne :

Page 64: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 51

⎧⎨⎩ [dd, ds := 4, 2]dd, ds ∈ N× N∧

divis(4, 2) = [dd, ds := 4, 2](pre ds = 0 then dd÷ ds end)⇔ Substitution sur le premier conjoint⎧⎨⎩ (4, 2) ∈ N× N

∧divis(4, 2) = [dd, ds := 4, 2](pre ds = 0 then dd÷ ds end)

⇔ Arithmétique et calcul propositionneldivis(4, 2) = [dd, ds := 4, 2](pre ds = 0 then dd÷ ds end) (1.11.5)

Arrêtons-nous sur le membre droit de cette égalité afin d’instancier la définitionde la substitution dans une expression préconditionnée (formule 1.11.1) :⎧⎪⎪⎪⎪⎨⎪⎪⎪⎪⎩

[dd, ds := 4, 2](ds = 0)∧⎧⎨⎩ [dd, ds := 4, 2](pre ds = 0 then dd÷ ds end)=

[dd, ds := 4, 2](dd÷ ds)⇔ Substitution⎧⎪⎪⎪⎪⎨⎪⎪⎪⎪⎩

2 = 0∧⎧⎨⎩ [dd, ds := 4, 2](pre ds = 0 then dd÷ ds end)=

[dd, ds := 4, 2](dd÷ ds)⇔ Arithmétique et calcul propositionnel[dd, ds := 4, 2](pre ds = 0 then dd÷ ds end) = [dd, ds := 4, 2](dd÷ ds)

⇔ Substitution[dd, ds := 4, 2](pre ds = 0 then dd÷ ds end) = 4÷ 2

⇔ Arithmétique[dd, ds := 4, 2](pre ds = 0 then dd÷ ds end) = 2

En reportant ce résultat dans la formule 1.11.5 nous obtenons :

divis(4, 2) = 2

Le troisième exemple considère l’opération f représentée par :

function f(v) ∈ N→ N =if v = 0 →1

| v > 0 →v · f(v − 1)

fi

Cette fonction est destinée à calculer la factorielle d’un entier naturel. Évaluonsf(3), pour cela instancions la formule 1.11.4, page ci-contre (qui fournit la défi-nition de l’évaluation d’une opération), pour f(3) :

Page 65: Structures de données et méthodes formelles ||

52 Structures de données et méthodes formelles

[v := 3]v ∈ N ∧ f(3) = [v := 3](if v = 0 → 1 | v > 0 → v · f(v − 1) fi)⇔ Substitution sur le premier conjoint3 ∈ N ∧ f(3) = [v := 3](if v = 0 → 1 | v > 0 → v · f(v − 1) fi)

⇔ Arithmétique et calcul propositionnelf(3) = [v := 3](if v = 0 → 1 | v > 0 → v · f(v − 1) fi) (1.11.6)

Arrêtons-nous sur le second membre de l’égalité pour appliquer la définition dela substitution dans les conditionnelles :

[v := 3](if v = 0 → 1 | v > 0 → v · f(v − 1) fi)⇔ Substitution dans les conditionnelles, formule 1.4.4, page 25[v := 3](v = 0 → 1) ∧ [v := 3](v > 0 → v · f(v − 1))

⇔ Substitution dans les expressions gardées, formule 1.4.3, page 25⎧⎨⎩ [v := 3]v = 0⇒ [v := 3](v = 0 → 1) = [v := 3]1∧

[v := 3]v > 0⇒ [v := 3](v > 0 → v · f(v − 1)) = [v := 3]v · f(v − 1)⇔ Substitution⎧⎨⎩ 3 = 0⇒ [v := 3](v = 0 → 1) = 1

∧3 > 0⇒ [v := 3](v > 0 → v · f(v − 1)) = 3 · f(3− 1)

⇔ Calcul propositionnel et arithmétique[v := 3](v > 0 → v · f(v − 1)) = 3 · f(2) (1.11.7)

Nous pouvons enfin reporter ce dernier résultat dans la formule 1.11.6. Nousobtenons : f(3) = 3 · f(2).

1.11.5 Propagation des préconditionsJusqu’à présent les seules préconditions que nous avons considérées sont celles

explicitées dans les expressions préconditionnées. Se pose tout naturellement leproblème de la propagation des préconditions au sein d’une opération. Au-delà deson intérêt théorique, cette préoccupation présente un intérêt pratique puisque,comme nous le voyons ci-dessous, c’est par cet intermédiaire que nous pouvonsavoir la garantie qu’une conditionnelle n’échoue pas faute d’une garde vraie.

En général une expression hérite de la précondition de l’expression englo-bante. Outre le fait que le typage d’une opération s’interprète comme une pré-condition, il existe trois exceptions à cet héritage simple. Elles sont représentéesdans le tableau 1.1 ci-dessous dans lequel prec(E) est la fonction qui délivre laprécondition d’une expression E. Selon la propriété 1.11.8, la précondition del’expression qui constitue le corps de l’opération est le typage des arguments.La formule 1.11.9 considère les expressions préconditionnées, elle nous apprendque la précondition est enrichie de la formule P de la rubrique pre. La pro-priété 1.11.10, qui traite du cas des expressions gardées, est similaire au cas desexpressions préconditionnées. Quant aux conditionnelles de la propriété 1.11.11,un héritage simple s’applique à toutes les expressions gardées. Enfin, dans le casdes expressions let de la propriété 1.11.12, l’héritage simple s’enrichit à partirde la construction présente entre les mots-clés let et in. Le cas général d’uneconditionnelle comportant plus de deux expressions gardées se déduit facilementde la propriété 1.11.11.

Page 66: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 53

Tableau 1.1 – Propagation des préconditions dans une opération.Ce tableau présente les propriétés de la propagation des préconditionsdepuis l’extérieur du texte d’une opération vers l’intérieur. Le cas desopérations, des expressions préconditionnées et gardées, des condition-nelles et des expressions let est considéré.

Propriété Condition Ident.

prec(function f(n) ∈ u �→ v = E)

=

n ∈ u

(1.11.8)

prec(E) = P ∧Q prec(pre P then E end) = Q (1.11.9)

prec(E) = P ∧G prec(G→ E) = P (1.11.10)

prec(CG1) = P ∧ prec(CG2) = P prec(if CG1 | CG1 fi) = P (1.11.11)

prec(F ) = P ∧ x = E prec(let x := E in F end) = P (1.11.12)

Exemple

Appliquons le principe de la propagation des préconditions à l’opérationmt(t, i) qui délivre le plus grand élément d’un tableau 1 .. i � t. Nous obte-nons l’opération ci-dessous. Le code est annoté par les préconditions, qui sontencadrées, et par les barres verticales, qui soulignent leur portée. Dans chaqueprécondition la partie non héritée apparaît en gras.

function mt(t, i) ∈ (1 .. 10→ N)× 1 .. 10 �→ N =⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐

P = (t, i) ∈ (1 .. 10→ N)× 1 .. 10if i = 1 →⏐⏐⏐⏐ P ∧ i = 1

t(1)| i > 1 →⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐

P∧ i > 1let m := mt(t, i− 1) in⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐

P ∧ i > 1 ∧ m = mt(t, i− 1)if m ≤ t(i) →⏐⏐⏐⏐⏐ P ∧ i > 1 ∧m = mt(t, i− 1) ∧ m ≤ t(i)

t(i)

| m ≥ t(i) →⏐⏐⏐⏐⏐ P ∧ i > 1 ∧m = mt(t, i− 1) ∧ m ≥ t(i)m

fiend

fi

Page 67: Structures de données et méthodes formelles ||

54 Structures de données et méthodes formelles

Ainsi que nous l’avons déjà dit, dans la suite de l’ouvrage nous calculons lecode des opérations. Ceci nous conduit fréquemment à raisonner sur des fonctionsdont la représentation est incomplète. En particulier, le calcul des conditionnellesest un processus itératif qui progresse expression gardée après expression gardée.Se posent alors deux problèmes :1. Quand arrêter le processus itératif de calcul des expressions gardées ?2. Étant donné une conditionnelle incomplète, quelle garde est candidate à la

poursuite du calcul ?La propriété du tableau ci-dessous (non démontrée) est destinée à fournir deséléments de réponse à ces deux interrogations.

Propriété Condition Ident.

P ⇒G1 ∨ · · · ∨Gn prec(if G1 → E1 | . . . | Gn → En fi) = P (1.11.13)

La précondition étant supposée connue et les premières gardes G1, . . ., Gi−1

déterminées, rechercher une nouvelle garde se fait en exhibant un prédicat Gi

qui contribue à satisfaire la propriété 1.11.13. Par ailleurs, le processus s’achèvequand la propriété 1.11.13 est satisfaite.

La pratique quotidienne de la programmation fonctionnelle est souvent plusempirique, mais nous ne pouvons que conseiller au lecteur de souscrire à cettedémarche.

Exemple

La médiane de trois entiers naturels est l’une des trois valeurs telle que l’unedes deux autres est inférieure ou égale et l’autre supérieure ou égale. Considé-rons l’opération med(v1, v2, v3) qui, partant de trois entiers naturels, délivre leurmédiane. Ainsi med(89, 4, 12) renvoie 12 tandis que med(5, 76, 5) s’évalue à 5.Supposons que le développement nous conduit à la version incomplète suivante :

function med(v1, v2, v3) ∈ N× N× N→ N =⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐

(v1, v2, v3) ∈ N× N× Nif v1 ≤ v2 →⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐⏐

(v1, v2, v3) ∈ N× N× N ∧v1 ≤ v2if v3 ≤ v1 →

v1| v3 ≥ v2 →

v2...

Concernant la construction de la conditionnelle interne, nous pouvons consta-ter que pour l’instant la propriété 1.11.13 n’est pas satisfaite : (v1, v2, v3) ∈N×N×N∧ v1 ≤ v2 � v3 ≤ v1 ∨ v3 ≥ v2. Quelle formule pourrait-on introduireen disjonction pour nous rapprocher de l’implication ? v1 ≤ v3 ∧ v3 ≤ v2 est unbon candidat. En outre la formule (v1, v2, v3) ∈ N × N × N ∧ v1 ≤ v2 ⇒ v3 ≤v1 ∨ v3 ≥ v2 ∨ (v1 ≤ v3 ∧ v3 ≤ v2) est un théorème (il y a même équivalence). Le

Page 68: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 55

développement des gardes de l’expression gardée la plus interne est maintenantachevé. Le prédicat v2 ≤ v1 est une garde convenable pour la prochaine expres-sion gardée externe. Des considérations de symétrie peuvent alors être utiliséespour compléter le code de l’opération. Nous obtenons :

function med(v1, v2, v3) ∈ N× N× N→ N =if v1 ≤ v2 →

if v3 ≤ v1 →v1

| v3 ≥ v2 →v2

| v1 ≤ v3 ∧ v3 ≤ v2 →v3

fi| v2 ≤ v1 →

if v3 ≤ v2 →v2

| v3 ≥ v1 →v1

| v2 ≤ v3 ∧ v3 ≤ v1 →v3

fifi

Exercices

Exercice 1.11.1 Évaluer les expressions suivantes pour t ∈ 1..10→N et i, j, k entiers naturels :1. pre i ∈ dom(t) then t(i) end = pre j = 0 then k ÷ j end2. pre

∃i ·(i ∈ 1 .. 10 ∧ t(i) = 0)then

j : (j ∈ N ∧ j ∈ 1 .. 10 ∧ t(i) = 0)end

3. prei ∈ N ∧ i ∈ 1 .. 3 ∧ i = 2

thenif i = 1 →3

| i = 3 →1

fiend

Exercice 1.11.2 Soit la fonction f représentée par :

function f(v) ∈ N→ N =if v ≥ 5 →4

| v ≤ 5 →9

fi

Page 69: Structures de données et méthodes formelles ||

56 Structures de données et méthodes formelles

Évaluer f(3) puis f(5). Conclusion ?

Exercice 1.11.3 Soit l’opération dz(t) spécifiée par :

function dz(t) ∈ (1 .. 100→ N)→ 1 .. 100 =precard(t� {0}) ≥ 10∧

thenq : (q ∈ 1 .. 100 ∧ t(q) = 0 ∧ card(1 .. q � t� 0) = 10)

end

1. En utilisant le tableau 1.1, page 53, calculer la précondition de l’expression entre then etend.

2. Fournir une représentation concrète de cette opération. Calculer la précondition desexpressions utilisées. En déduire s’il y a lieu que les conditionnelles satisfont la condi-tion 1.11.13, page 54.

Exercice 1.11.4 Soit l’opération trie3(v1, v2, v3) destinée à rendre les trois valeurs dans l’ordrecroissant. Cette opération est ébauchée par :

function trie3(v1, v2, v3) ∈ N× N× N→ N× N× N =if v1 ≤ v3 →

...fi

Compléter cette opération en calculant les gardes à partir de la propriété 1.11.13. Démon-trer que chaque conditionnelle satisfait cette propriété.

1.12 Conclusion et remarques bibliographiques

Ce chapitre pose les bases des mathématiques utilisées dans le reste de l’ou-vrage. L’importance du raisonnement par récurrence/induction est à souligner.La maîtrise des notations est indispensable, notamment celles se rapportant à lathéorie des ensembles.

À travers les notions de tableau et de structure inductive, ce chapitre fixeégalement le cadre dans lequel nous nous apprêtons à définir ce que nous appelonsle support d’une structure de données, c’est-à-dire l’ensemble sur lequel unestructure de données prend ses valeurs.

Clairement inspiré des ouvrages et articles de J.-R. Abrial (principalement[3, 5] mais aussi [6]), ce chapitre s’en écarte à plusieurs reprises. La raison prin-cipale est que notre approche du développement est fonctionnelle et que les opé-rations calculées sont en général récursives. Par contre, nous avons pris à notrecompte les principes de la méthode B qui consistent à séparer clairement la no-tion de prédicat et celle d’expression, et à ne nous préoccuper que de l’aspectdémonstration en négligeant complètement l’aspect vérité.

Les ouvrages [119] et [50] réalisent une présentation plus vulgarisée de laméthode B classique. De nombreux autres ouvrages traitent du thème de cettesection. Parmi ceux-ci citons l’ouvrage de J.-F. Monin [83] qui présente un pano-rama des outils mathématiques pour les méthodes formelles. L’ouvrage d’A. Ar-nold et I. Guessarian [9] élargit sa thématique à l’ensemble des mathématiques

Page 70: Structures de données et méthodes formelles ||

1. Mathématiques pour la spécification et les structures de données 57

utiles à l’informaticien. Dans [51], H. Habrias, M. Frappier et les coauteurs réa-lisent un tour d’horizon comparatif des principales méthodes formelles, qui sontappliquées sur le même exemple. Pour les lecteurs plus attirés par la théorie,nous pouvons citer les deux ouvrages [77] et [76]. Le premier est tourné vers lalogique et ses applications, tandis que le second est uniquement dédié à la théoriedes ensembles.

Page 71: Structures de données et méthodes formelles ||

Chapitre 2

Spécifications + Fonctiond’abstraction + Calcul =Programme

Ce chapitre présente les principes qui sont appliqués dans le reste del’ouvrage pour concevoir et mettre en œuvre des structures de données de ma-nière rigoureuse. La première section fixe le cadre général de la démarche. Dansla seconde section nous nous intéressons à la structure des unités constituant untype abstrait ou concret. Un premier exemple complet est présenté. La troisièmesection montre comment parvenir au code des opérations d’un type concret. Iljustifie à lui seul le titre du chapitre. La section 2.4 développe un point qui, danscertains cas, est à la base de la dernière étape du développement : le renforcementde support.

2.1 Cadre général de la démarche

Dans cet ouvrage, le principe conduisant à la réalisation de structures dedonnées consiste, partant de la fourniture de leurs spécifications, à parvenir ra-tionnellement à des mises en œuvre (concrètes).

Spécifier, c’est fournir des propriétés, c’est dire le « quoi ? » ; mettreen œuvre, c’est au contraire répondre au « comment ? » À l’oppositionquoi/comment s’ajoute le fait que l’activité de mise en œuvre, contrairementà celle de spécification, a pour objectif d’atteindre une solution qui soit exécu-table, si possible efficacement.

Commençons par préciser ce que nous appelons structure de données. Unestructure de données est une forme d’algèbre (cf. encadré page suivante pour unrappel des notions d’algèbre et d’homomorphisme) constituée :

– d’un ensemble de valeurs possibles. Cet ensemble peut être défini en ex-tension ou en compréhension. Dans cet ouvrage, cet ensemble est appelésupport ;

Page 72: Structures de données et méthodes formelles ||

60 Structures de données et méthodes formelles

Algèbres et homomorphismes

Soit n ∈ N, soit s un ensemble et f tel que f ∈ sn �→ s. Le coupleS = (s, f) est appelé une algèbre.

Soit T = (t, o) et T ′ = (t′, o′) deux algèbres où o et o′ sont de mêmearité n. La fonction H, H ∈ t′→ t, est un homomorphisme de T ′ vers Tsi, pour tout n-uplet v′1, . . . , v

′n ∈ dom(o′) :

H(o′(v′1, . . . , v′n)) = o(H(v′1), . . . ,H(v′n))

Si H est une fonction bijective, elle est appelée isomorphisme.Par exemple, toute fonction f ∈ R∗+��R telle que f(a · b) = f(a)+f(b)

est un homomorphisme de (R∗+,×) vers (R,+) et puisque f est bijective,c’est un isomorphisme. De telles fonctions f sont appelées fonctions loga-rithmes. Dans la suite nous utilisons fréquemment une fonction f parti-culière, définie par f(2) = 1 appelée logarithme en base 2 (ou logarithmebinaire). Habituellement représentée sous la forme log2, dans la suite dulivre (sauf mention explicite de la base), elle est simplement notée log.

Les notions d’algèbre et d’homomorphisme s’étendent naturellementau cas où il existe un jeu d’opérations (et non plus une seule opération)dans chacune des structures, en relation biunivoque.

En informatique, il arrive fréquemment que des opérations intéres-santes dérogent à la définition ci-dessus dans le sens où, soit l’ensemblesource de l’opération peut contenir un support externe, soit l’ensembledestination est lui-même un support externe. Le terme d’algèbre de typeest parfois utilisé pour qualifier de telles algèbres et souligner la différenceavec les algèbres « strictes ». La notion d’homomorphisme s’étend natu-rellement aux algèbres de type. Soit T = (t, o) avec o ∈ e× t �→ t (e = t)et T ′ = (t′, o′) avec o′ ∈ e × t′ �→ t′, (e = t′) deux algèbres de type. Lafonction H, H ∈ t′→ t est un homomorphisme de T ′ vers T si, pour toutcouple (w, v′) tel que (w, v′) ∈ dom(o′) :

H(o′(w, v′)) = o(w,H(v′))

De même, soit T = (t, o) avec o ∈ tn �→ e, (e = t) et T ′ = (t′, o′) avec o′ ∈t′n → e (e = t′) deux algèbres de type. La fonction H, H ∈ t′→T est unhomomorphisme de T ′ vers T si pour tout n-uplet v′1, . . . , v

′n ∈ dom(o′) :

o′(v′1, . . . , v′n) = o(H(v′1), . . . ,H(v′n)).

– d’un ensemble fini d’opérations qui se présentent ici sous la forme de fonc-tions. L’un au moins des arguments et/ou le résultat de chaque fonctionappartient au support. Les opérations qui délivrent un résultat apparte-nant au support sont qualifiées d’internes. Les autres sont les opérationsexternes.

Page 73: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 61

Le concept de structure de données ainsi défini se démarque de celui de basede données, principalement par le fait que concevoir une base de données consisteen général à définir un ensemble de valeurs en compréhension, en se focalisantsur l’aspect normatif de sa structuration. Une autre différence tient au fait quedans les bases de données, la consultation se fait par l’intermédiaire d’un langagede requêtes générique et non par un jeu fini d’opérations ad hoc comme dans lecas des structures de données.

spécification abstraite

supportabstrait

opérationsabstraites

représentation concrète

supportconcret

spécificationdes

opérationsconcrètes

fonctiond’abstraction

représentationdes opérationsconcrètes

calcul

Figure 2.1 – Schéma de principe de la méthode.Ce schéma montre à partir de quelles informations nous calculons lesopérations concrètes d’une structure de données. La représentation abs-traite de la structure de données (sur la gauche) décrit le support abs-trait et spécifie les opérations abstraites. La représentation concrète (surla droite) définit le support concret, la fonction d’abstraction et la spé-cification des opérations concrètes. Ces informations permettent en gé-néral de calculer la représentation concrète des opérations.

La démarche de conception dont nous nous faisons l’avocat et que nous ap-pliquons dans cet ouvrage se décompose en quatre étapes :1. spécifier le type abstrait que l’on souhaite mettre en œuvre,2. spécifier un type concret cible du développement,3. calculer la représentation des opérations concrètes,4. effectuer un éventuel raffinement informel.

Cette démarche est illustrée à la figure 2.1 ci-dessus.

2.2 Formalisme pour les types – ExempleDans cette section nous présentons la syntaxe des notations utilisées pour la

spécification abstraite (abstractType) et pour le raffinement (concreteType).

Page 74: Structures de données et méthodes formelles ||

62 Structures de données et méthodes formelles

Ces notions sont illustrées à travers un exemple simple.Le texte d’une spécification abstraite est décrit conformément à la catégorie

syntaxique typeAbst suivante :

typeAbst : := abstractTypeprofil

useslisteIdentParam

constraintsprédicat

supportprédicat

operationslisteOpérations

auxiliaryOperationRepresentationslisteOpérations

end

listeIdent : := ident ||ident, listeIdent

listeIdentParam : := identParam ||identParam, listeIdentParam

identParam : := ident ||ident(listeIdent)

listeOpérations : := opération ||opération; listeOpérations

profil : := identParam = (identParam, (listeIdent), (listeIdent)) ||identParam = (identParam, (listeIdent), ())

Afin d’illustrer les formalismes utilisés et l’information qu’ils véhiculent, nousallons considérer l’exemple suivant. Le type abstrait entnat (cf. figure 2.2,page 64) vise à représenter l’ensemble des entiers naturels muni des deux opéra-tions plus et inf (correspondant aux opérations + et < traditionnelles). Cettefigure contient les rubriques suivantes :

– abstractType qui identifie le type abstrait considéré (entnat), le support(entNat 1), la liste des opérations internes (plus) et la liste des opérationsexternes (inf). Le nom du type abstrait peut être suivi d’un ou plusieursparamètres formels. Ceux-ci sont notés entre parenthèses et séparés pardes virgules. La rubrique constraints est destinée à typer ces paramètrespar un prédicat de typage ;

– uses qui mentionne les types utilisés pour décrire le type considéré. Si soncontenu est vide, cette rubrique n’est pas obligatoire ;

1. Nous adoptons la convention consistant à nommer le type par le même identificateur quele support, le premier étant écrit en petites capitales, le second non.

Page 75: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 63

– support qui définit l’ensemble qui sert de support au type considéré ;– operations qui spécifie les opérations de l’en-tête (internes et externes).Outre la rubrique constraints, la rubrique auxiliaryOperationRepresen-

tations n’est pas illustrée par la figure 2.2. Cette dernière rubrique correspondau cas où des opérations auxiliaires sont nécessaires à la spécification des opéra-tions principales (cf. section 8.2 pour un exemple).

La spécification concrète ainsi que le résultat du raffinement sont décrits parla catégorie syntaxique typeConc :

typeConc : := concreteTypeprofil

useslisteIdentParam

constraintsprédicat

refinesidentParam

auxiliarySupportsprédicat

supportprédicat

auxiliaryAbstractionFunctionlisteOpérations

abstractionFunctionopération

auxiliaryOperationSpecificationslisteOpérations

operationSpecificationslisteOpérations

auxiliaryOperationRepresentationslisteOpérations

operationRepresentationslisteOpérations

end

En guise d’exemple, le type entnat est raffiné par le type nat présenté àla figure 2.3, page 65. L’idée qui prévaut dans ce raffinement est de représenterles entiers naturels selon une approche « à la Peano ». Ceci se reflète dans larubrique support qui définit par induction l’ensemble dénommé nat.

Les rubriques que nous rencontrons sont les suivantes :– concreteType qui est l’homologue de la rubrique abstractType de ladescription précédente. Elle permet d’énumérer les mêmes informations :nom du type (nat), liste des opérations internes et liste des opérations

Page 76: Structures de données et méthodes formelles ||

64 Structures de données et méthodes formelles

externes. Pour éviter toute confusion, le nom des opérations est celui desopérations abstraites, enrichi d’un suffixe discriminant (_n pour nat ici) ;

– refines qui mentionne le type abstrait raffiné et ses éventuels paramètreseffectifs (cf. page 173 pour un exemple mentionnant un paramètre effectif) ;

– uses qui a le même sens que précédemment ;– support qui a déjà été commentée. Pour cet exemple, l’ensemble est définide manière inductive (cf. chapitre 3) ;

– abstractionFunction qui décrit la fonction d’abstraction dont le rôle estd’associer à chaque valeur concrète son homologue abstrait. Cette fonctioncalque en général sa structure sur celle du support concret. En particu-lier dans l’exemple considéré elle est définie par « induction structurelle »puisque le support concret est lui-même inductif. En outre, c’est une bijec-tion totale (qui définit donc un isomorphisme), d’où l’utilisation du sym-bole �� ;

– operationSpecifications qui possède la même signification que la ru-brique operations du type abstrait. La différence tient à ce qu’ici l’opé-ration est spécifiée par homomorphisme entre la structure concrète et lastructure abstraite (cf. encadré page 60 pour un rappel sur la notion d’ho-momorphisme).

La rubrique operationRepresentations décrit la représentation des opé-rations. Les calculs sont présentés à la section suivante.

abstractType entnat = (entNat, (plus), (inf))uses

bool,Nsupport

x ∈ N ⇔ x ∈ entNatoperations

function plus(x, y) ∈ entNat× entNat� entNat = x+ y;

function inf(x, y) ∈ entNat× entNat� bool = bool(x < y)end

Figure 2.2 – Spécification du type abstrait entnat.Exemple de spécification abstraite. Cette spécification fournit une illus-tration de la rubrique d’en-tête et des rubriques uses, support et ope-rations.

2.3 Calcul des opérations – Exemple

À la section précédente, la rubrique operationRepresentations de la fi-gure 2.3, page ci-contre, fournit, sans aucune justification, le code des deuxopérations plus_n et inf_n. L’intérêt et la puissance de la démarche que nouspréconisons est de construire (on dit aussi calculer ou dériver) ce code à par-tir de son environnement. C’est le point sur lequel nous nous focalisons ici, endéroulant ce calcul pour les deux opérations du type considéré.

Page 77: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 65

concreteType nat = (nat, (plus_n), (inf_n))uses bool

refines entnat

support1) zero ∈ nat2) x ∈ nat ⇒ suiv(x) ∈ nat

abstractionFunctionfunction A(x) ∈ nat�� entNat =if x = zero →0

| x = suiv(v) →plus(A(v), 1)

fioperationSpecifications

function plus_n(x, y) ∈ nat× nat� nat =v : (v ∈ nat ∧ A(v) = [x′, y′ := A(x),A(y)]plus(x′, y′))

;function inf_n(x, y) ∈ nat× nat� bool =[x′, y′ := A(x),A(y)]inf(x′, y′)

operationRepresentationsfunction plus_n(x, y) ∈ nat× nat� nat =if x = zero →

y| x = suiv(v) →

suiv(plus_n(v, y))fi

;function inf_n(x, y) ∈ nat× nat� bool =if y = zero →

false

| y = suiv(y′) →if x = zero →

true

| x = suiv(x′) →inf_n(x′, y′)

fifi

end

Figure 2.3 – Représentation du type concret nat.Exemple de représentation concrète. De même que pour le cas de laspécification abstraite (cf. figure 2.2, page ci-contre), on retrouve lesrubriques uses et support. La rubrique abstractionFunction éta-blit la correspondance entre le support abstrait et le support concret. larubrique operationSpecifications fournit une spécification concrètedes opérations. Enfin la rubrique operationRepresentations récapi-tule le résultat du calcul des différentes opérations.

Page 78: Structures de données et méthodes formelles ||

66 Structures de données et méthodes formelles

2.3.1 Calcul d’une représentation de l’opération plus_n

L’opération concrète plus_n est spécifiée par :

plus_n(x, y) = v : (v ∈ nat ∧ A(v) = [x′, y′ := A(x),A(y)]plus(x′, y′))

plus_n(x, y) est inconnu. L’expression en partie droite délivre un élément vquelconque de nat, tel que l’homologue abstrait de v est égal à l’expressionplus(x′, y′) dans laquelle A(x) (resp. A(y)) se substitue à x′ (resp. y′). La valeurabstraite correspondant à plus_n(x, y) est A(plus_n(x, y)). Entamons un calculà partir de cette dernière expression :

A(plus_n(x, y))= Spécification concrète

A(v : (v ∈ nat ∧ A(v) = [x′, y′ := A(x),A(y)]plus(x′, y′)))= Substitution

A(v : (v ∈ nat ∧ A(v) = plus(A(x),A(y))))= Propriété C.22

plus(A(x),A(y))= Spécification abstraite

A(x) +A(y)

Cette séquence de calculs est longue et fastidieuse. En outre, elle apparaîtsous une forme proche dans le calcul de chaque opération interne. Pour éviter dela répéter inutilement, d’une part nous supposons à l’avenir que la substitutionest systématiquement réalisée dès la spécification concrète (nous écrirons doré-navant plus_n(x, y) = A(v : (v ∈ nat ∧ A(v) = plus(A(x),A(y))))) et d’autrepart la séquence complète est maintenant intitulée « propriété caractéristique »,et s’abrège sous une forme équivalente à :

A(plus_n(x, y))= Propriété caractéristique

A(x) +A(y) (2.3.1)

Bien entendu, la détermination de l’inconnue plus_n(x, y) n’a pas encoreabouti. Partir de l’expression A(plus_n(x, y)) présente l’avantage de nous per-mettre de raisonner dans « l’espace abstrait ». Notre calcul nous a temporaire-ment conduit à l’expression (abstraite) A(x) + A(y) mais si nous parvenions àl’issue du calcul à une formule (éventuellement conditionnée par un prédicat) dutype A(exp), nous pourrions conclure qu’une solution possible à notre équationest plus_n(x, y) = exp.

Pour bien comprendre ce mode de résolution, considérons une fonction quel-conque f et soit v ∈ dom(f). v est solution de l’équation en x f(x) = f(v).Formalisée, cette propriété se présente de la manière suivante :

Page 79: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 67

Propriété 1 (de l’équation à membres identiques).

f ∈ s �→ t ∧ v ∈ dom(f) ⇒ v ∈ {x | x ∈ dom(f) ∧ f(x) = f(v)} (2.3.2)

Dans le cas où f est injective, v est l’unique solution. Pour comprendre l’inté-rêt de cette propriété dans le calcul de la représentation d’opérations concrètes,débutons par un exemple numérique simple. Considérons la fonction sin. sin ∈R � [−1 .. 1]. Nous savons que, sur R, sin n’est pas injective : étant donnée ∈ [−1 .. 1], l’équation trigonométrique sin(x) = e possède plusieurs (une in-finité en fait) solutions. Si l’on sait que sin(x) = sin( 17 · Π4 ), la propriété 2.3.2permet de conclure que x = 17 · Π

4 est solution. Compte tenu du caractère noninjectif de la fonction sin, la trigonométrie nous apprend que, sur R, x = Π

4 ,

x = 3 · Π4 , x = Π

4 + 2 ·Π, etc. sont aussi solutions de l’équation.Poursuivons notre calcul à partir de la formule 2.3.1. Nous pouvons difficile-

ment éviter de faire une hypothèse sur la structure de x et/ou celle de y. Nouschoisissons de procéder par induction sur la structure de x. Deux cas sont doncà considérer : x = zero et x = suiv(v). Nous débutons par le cas x = zero.

A(x) +A(y)= Hypothèse (x = zero)

A(zero) +A(y)= Définition de A0 +A(y)

= ArithmétiqueA(y)

Nous avons donc pour le cas x = zero :

A(plus_n(x, y)) = A(y)

D’après la propriété ci-dessus de l’équation à membres identiques, une solutionà l’équation en plus_n(x, y) A(plus_n(x, y)) = A(y) est y. Ceci nous fournit lapremière équation gardée de la représentation de la fonction plus_n :

x = zero →plus_n(x, y) = y

Le cas inductif (x = suiv(v)) se traite de la manière suivante, en reprenantla formule 2.3.1 ci-dessus :

A(x) +A(y)= Hypothèse (x = suiv(v))

A(suiv(v)) +A(y)= Définition de A

plus(A(v), 1) +A(y)= Définition de plus

A(v) + 1 +A(y)= Arithmétique

A(v) +A(y) + 1= Propriété caractéristique de l’opération plus_n

Page 80: Structures de données et méthodes formelles ||

68 Structures de données et méthodes formelles

A(plus_n(v, y)) + 1= Spécification de plus

plus(A(plus_n(v, y)), 1)= Définition de A (cas inductif)

A(suiv(plus_n(v, y)))

De même que ci-dessus (en appliquant la propriété de l’équation à membresidentiques, page précédente), suiv(plus_n(v, y)) est une solution de l’équationen plus_n(x, y) A(plus_n(x, y)) = A(suiv(plus_n(v, y))).D’où la seconde équation gardée de la représentation de la fonction plus_n :

x = suiv(v) →plus_n(x, y) = suiv(plus_n(v, y))

Au total, en intégrant les deux équations gardées au sein d’une notation tra-ditionnelle, nous avons calculé la représentation suivante de l’opération plus_n.

function plus_n(x, y) ∈ nat× nat� nat =if x = zero →

y| x = suiv(v) →

suiv(plus_n(v, y))fi

2.3.2 Calcul d’une représentation de l’opération inf_n

La trame générale du calcul de l’opération inf_n s’apparente à celle dévelop-pée ci-dessus. Cependant il s’agit cette fois d’une opération externe (elle délivreun booléen). Il n’est donc pas question d’appliquer la fonction d’abstraction àl’inconnue inf_n(x, y) :

inf_n(x, y)= Spécification concrète[x′, y′ := A(x),A(y)]inf(x′, y′)

= Substitutioninf(A(x),A(y))

= Spécification abstraitebool(A(x) < A(y))

De même que pour les opérations internes, la substitution est à l’avenir déportéedans la spécification concrète et le reste de la séquence est également dénommé« propriété caractéristique » :

inf_n(x, y)= Propriété caractéristique de l’opération inf_nbool(A(x) < A(y)) (2.3.3)

Nous poursuivons le calcul en procédant à une induction sur y. Deux cas sontdonc à envisager : y = zero et y = zero. Débutons par y = zero.

Page 81: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 69

bool(A(x) < A(y))= Hypothèse y = zerobool(A(x) < A(zero))

= Définition de Abool(A(x) < 0) (2.3.4)

Nous pouvons alors réaliser une induction incidente sur x. Nous constaterons plustard que le résultat est identique dans les deux branches du calcul. Débutonspar le cas x = zero.

bool(A(x) < 0)= Hypothèse x = zerobool(A(zero) < 0)

= Définition de Abool(0 < 0)

= Arithmétiquebool(⊥)

= Définition de boolfalse

Le cas x = zero se traite de la manière suivante. Si x = zero c’est donc que,d’après la définition du support nat, il existe un x′ tel que x = suiv(x′). Nousreprenons le calcul à partir de la formule 2.3.4 ci-dessus.

bool(A(x) < 0)= Hypothèsebool(A(suiv(x′)) < 0)

= Définition de Abool(plus(A(x′), 1) < 0)

= Définition de la fonction plusbool(A(x′) + 1 < 0)

A(x′) est un entier naturel, l’arithmétique nous apprend qu’il n’existe pas d’en-tier naturel qui, ajouté à 1, soit négatif. A(x′) + 1 < 0 est donc identique à⊥ :

bool(A(x′) + 1 < 0)= Remarque ci-dessusbool(⊥)

= Définition de boolfalse

Les gardes x = zero et x = zero conduisent donc au même résultat false. Lesdeux équations gardées fusionnent pour donner :

y = zero →inf_n(x, y) = false

Revenons sur la première induction en considérant le second cas, y = zero.Posons y = suiv(y′). Le développement reprend à partir de la formule 2.3.3,page ci-contre.

Page 82: Structures de données et méthodes formelles ||

70 Structures de données et méthodes formelles

bool(A(x) < A(y))= Hypothèsebool(A(x) < A(suiv(y′)))

= Définition de Abool(A(x) < plus(A(y′), 1))

= Définition de la fonction plusbool(A(x) < A(y′) + 1) (2.3.5)

Nous devons à nouveau procéder à une induction sur x. Débutons par le casx = zero.

bool(A(x) < A(y′) + 1)= Hypothèsebool(A(zero) < A(y′) + 1)

= Définition de Abool(0 < A(y′) + 1)

= Arithmétiquebool(�)

= Définition de booltrue

D’où l’équation gardée :

y = zero →x = zero →

inf_n(x, y) = true

Pour la partie inductive, x = zero, nous pouvons faire l’hypothèse que x =suiv(x′) puis repartir de la formule 2.3.5 ci-dessus.

bool(A(x) < A(y′) + 1)= Hypothèsebool(A(suiv(x′)) < A(y′) + 1)

= Définition de Abool(plus(A(x′), 1) < A(y′) + 1)

= Définition de la fonction plusbool(A(x′) + 1 < A(y′) + 1)

= Arithmétiquebool(A(x′) < A(y′))

= Propriété caractéristique de la fonction inf_ninf_n(x′, y′)

D’où l’équation gardée :

y = suiv(y′) →x = suiv(x′) →

inf_n(x, y) = inf_n(x′, y′)

Au total, nous avons calculé la représentation suivante de l’opération inf_n :

Page 83: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 71

function inf_n(x, y) ∈ nat× nat� bool =if y = zero →

false

| y = suiv(y′) →>if x = zero →

true

| x = suiv(x′) →inf_n(x′, y′)

fifi

Remarque. Soit t le support du type concret T . Soit s, s ∈ t la structurefaisant l’objet du calcul lors de la recherche de la représentation d’une opéra-tion. Il peut arriver que, momentanément, s n’appartienne plus au support t,mais appartienne à t′, sur-ensemble de t. Transformer s de façon à le faire ré-intégrer t exige en général de disposer d’une fonction d’abstraction A dont ledomaine de définition soit t′ et non t. Plusieurs exemples illustrant cette néces-sité apparaissent ci-dessous, en particulier dans les sections consacrées aux Avl(cf. section 6.6, page 191) et aux B-arbres (cf. section 6.7, page 216).

Exercices

Exercice 2.3.1 Démontrer la propriété de l’équation à membres identiques rappelée ci-dessous :

f ∈ s �→ t ∧ v ∈ dom(f) ⇒ v ∈ {x | x ∈ dom(s) ∧ f(x) = f(v)}

Exercice 2.3.2 Démontrer la propriété de l’équation à membres identiques dans le cas d’unefonction injective :

f ∈ s �� t ∧ v ∈ dom(f) ⇒ {v} = {x | x ∈ dom(s) ∧ f(x) = f(v)}

2.4 Induction, support et renforcement

Malgré leurs différences superficielles, l’identité profonde entre d’une part laréalisation d’une preuve par induction et d’autre part la construction de pro-grammes itératifs, récursifs ou encore la mise en œuvre de structures de donnéesa été remarquée et exploitée depuis longtemps (cf. [10, 11, 32, 33, 80] pour desapproches tirant directement profit du raisonnement par induction en program-mation impérative). Le tableau 2.1, page 73, rappelle la correspondance entre levocabulaire des mathématiques et celui de l’informatique.

Ainsi que le montre le tableau 2.1, pour des structures de données, le supportse comporte comme un invariant : les fonctions de construction, qui ont commecodomaine le support, ont pour rôle d’instaurer cet invariant ; les fonctions de

Page 84: Structures de données et méthodes formelles ||

72 Structures de données et méthodes formelles

Notations fonctionnelles

Le calcul et la manipulation des opérations d’un type donné nousconduisent à utiliser deux sortes de notation pour représenter des fonc-tions : la notation équationnelle et la notation traditionnelle (monoli-thique). Ces deux notations sont bien sûr équivalentes mais présententchacune des avantages dans leur contexte d’utilisation. À l’exception descas les plus simples, le calcul de la représentation des fonctions se fait demanière incrémentale, chaque étape produisant une « équation gardée ».La notation équationnelle est la représentation la plus naturelle pour pré-senter le résultat d’une étape de calcul. À l’issue du calcul il est alorspossible de regrouper l’ensemble des fragments obtenus sous la forme plusclassique d’une conditionnelle. Ci-dessous nous illustrons ces notations enprenant comme exemple la fonction pgcd (le plus grand commun diviseurentre deux entiers naturels, cet exemple est inspiré de [57]). Le calculfournit successivement les trois « équations gardées » suivantes :

x = y →pgcd(x, y) = x

x > y →pgcd(x, y) = pgcd(x− y, y)

x < y →pgcd(x, y) = pgcd(y, x)

Nous pouvons alors rassembler ces trois fragments au sein d’une re-présentation qui intègre l’en-tête de la fonction :

function pgcd(x, y) ∈ N× N→ N =if x = y →

x| x > y →

pgcd(x− y, y)| x < y →

pgcd(y, x)fi

Le cas de la spécification des opérations du type abstrait ainsi quecelui de la fonction d’abstraction se présentent différemment puisque cesfonctions sont données et non calculées. Seule la forme monolithique estalors utilisée. Une variante tabulaire de cette dernière notation est par-fois utilisée. Les informations y sont présentées en trois colonnes : nota-tion/définition/condition (cf. section 1.7).

Page 85: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 73

mise à jour 2 (dans lesquelles le support apparaît à la fois comme partie dudomaine de définition et comme codomaine) préservent l’invariant.

Qu’en est-il alors de la situation de la technique de renforcement étudiée à lasection 1.10 ? Nous aurons l’occasion de l’appliquer strictement dans le cadre deraisonnements de nature mathématique (cf. par exemple section 6.6) mais ce quinous intéresse le plus ici est sa transposition au cas des structures de données 3.

Tableau 2.1 – Raisonnement par induction et programmation.Équivalence approximative entre le vocabulaire utilisé dans une démons-tration par induction et le vocabulaire de l’informatique (constructionde boucles, récursivité et structures de données).

Rais. parinduction

Boucles RécursivitéStructuresde données

Base InitialisationArgumentsde l’appelinitial

Constructeur

Hypothèsed’induction

InvariantHypothèsed’induction

Support

Étapeinductive

ProgressionCorps del’opération

Opérationsde mise à jour

Renforcer le support d’une structure de données consiste en général à y intro-duire explicitement une information latente. Du point de vue méthodologique,cette information complémentaire n’a pas lieu d’être introduite dès la concep-tion du support, elle pourrait se révéler sans objet ou compliquer inutilementle calcul. C’est en général au cours du développement des opérations que l’onprend conscience de son intérêt. Le plus souvent cette information complémen-taire n’est autre que le résultat de l’évaluation d’une fonction particulière, quin’est encore qu’à l’état de spécification. Deux types de comportement sont alorsenvisageables :1. Soit on évalue cette fonction à chaque appel. Cette solution est toujours

possible mais elle peut se révéler coûteuse.2. Soit on introduit explicitement le résultat de l’évaluation dans la structure

de données. Accéder à la valeur recherchée est alors immédiat, mais ceci sefait au prix d’un accroissement de la place occupée et de la modification desopérations de mise à jour, qui doivent préserver l’intégrité de la nouvelleinformation. Pour se révéler compétitive, cette solution ne doit engendrerqu’un faible surcoût.

Prenons par exemple le cas d’une liste d’entiers naturels qui est mise à jourpar des opérations d’adjonction et de suppression.

2. Cette dénomination est abusive dans la mesure où un programme fonctionnel pur nemodifie pas les structures de données.

3. Pour le cas des boucles, on peut consulter par exemple [24, 30, 31, 66, 45]. Pour celuides opérations récursives, voir par exemple [14, 79].

Page 86: Structures de données et méthodes formelles ||

74 Structures de données et méthodes formelles

• 7 • 12 • 4 /

Supposons par ailleurs que parmi les opérations de consultation de la structurede données nous ayons besoin d’une fonction moy qui délivre la moyenne desvaleurs présentes dans une liste l non vide. Cette fonction s’exprime par :

function moy(l) ∈ liste �→ R =pre

l = [ ]then

somme(l)/#(l)end

où [ ] dénote la liste vide (cf. section 3.1 pour de plus amples développementssur les listes), somme(l) est la somme des valeurs présentes dans la liste, tandisque #(l) est la longueur de la liste. Si l’on s’interdisait de renforcer le support,la mise en œuvre de la fonction moy ne pourrait éviter (au moins) un parcours(coûteux) de la liste. Par contre, nous pouvons très bien enrichir la structure dedonnées (c’est-à-dire renforcer l’invariant) en y enregistrant les deux informationscomplémentaires, la somme et la longueur. Nous obtenons alors :

Le calcul de la moyenne s’en trouve notablement simplifié. Cependant, le supportayant été renforcé, les opérations d’initialisation et de mise à jour doivent tenircompte des nouveaux champs. En général, les modifications induites par le ren-forcement du support sont simples et n’exigent pas de recalculer les opérations.Dans les cas les plus complexes, un nouveau calcul peut se révéler nécessaire.

Parmi les formes de renforcement les plus utiles, nous allons nous arrêtersur celle qui est intitulée « décomposition d’une fonction sur la structure dedonnées ».

Décomposition d’une fonction sur la structure de données. L’exemplede la liste est particulièrement simple. Il arrive fréquemment que la fonction à labase du renforcement calque sa structure sur celle du support. Ça serait le cassi dans l’exemple de la liste nous avions besoin de connaître pour chaque cellulela somme des éléments du reste de la liste. Si nous souhaitons appliquer unetechnique de renforcement (pour cet exemple simple, il existe d’autres solutionstout aussi efficaces), il faut adjoindre un champ complémentaire à chaque celluleet y placer la valeur de la fonction. Toute mise à jour se fait alors en généralen utilisant le nouveau champ de la cellule suivante (si elle existe). Nous avonsdécomposé la fonction sur la structure de données 4.

4. Ce type de démarche s’apparente à la technique utilisée en programmation dynamiqueoù l’on enregistre les valeurs dans un tableau afin d’éviter de refaire des calculs inutiles.

3

23• 7 • 12 • 4 /

Page 87: Structures de données et méthodes formelles ||

2. Spécifications + Fonction d’abstraction + Calcul = Programme 75

• 16 7 • 4 12 • 0 4 /

Pour être efficace, cette technique ne doit décomposer que les fonctions O(1)-décomposables (cf. encadré page 188 et [68]).

La section 6.9 sur les treaps aléatoires fournit un exemple de renforcement(sans décomposition). Les sections 6.5, 6.6 et 9.4 illustrent la technique du ren-forcement par décomposition. D’autres exemples peuvent être rencontrés au fildes exercices.

2.5 Conclusion

Que faire du type concret obtenu à l’issue de la phase de raffinement formel ?En général, ce type peut être aisément traduit puis exécuté en utilisant un lan-gage fonctionnel tel que Caml, Scheme, Lisp, Haskell, etc. Une traduction dansun langage algorithmique classique à base de pointeurs (comme Pascal, Ada,etc.) ou à base d’objet (comme Ada ou Java) se révèle un peu plus délicate.Dans ce dernier cas, le principe qu’il convient d’appliquer à la lettre consiste às’assurer que l’on ne modifie jamais une structure (ou un objet) existant(e). Ilfaut systématiquement en créer de nouvelles.

En toute hypothèse, à ce stade du développement la version disponible esttoujours de nature fonctionnelle. C’est le moment de s’intéresser à la complexitédes opérations (cf. chapitre 4). En effet, d’une part la version disponible se prêtebien aux calculs de complexité et d’autre part les développements ultérieursn’ont en général pas d’incidence sur le coût asymptotique, la différence avec uneversion optimisée ne porte que sur un facteur multiplicatif.

Peut-on encore améliorer l’efficacité des opérations obtenues à l’issue desétapes précédentes ? Si la question sous-entend « en préservant la sémantiquedes opérations », la réponse est oui, mais la marge de manœuvre est étroite. Ilfaut se tourner vers des techniques de transformation comme la suppression de larécursivité, l’introduction des notions de variable, de pointeur, de séquentialité, latransformation de fonctions en procédures par l’ajout d’un paramètre de sortie,etc. tout en s’interdisant de modifier les structures de données existantes.

De telles manipulations peuvent se révéler insuffisantes quand, par exemple,les structures de données traitées contiennent des tableaux qui sont donc sys-tématiquement recopiés, entraînant un coût rédhibitoire. La solution est alorsd’utiliser une démarche de type « modification in situ » qui autorise à modifierdes structures de données existantes (cf. [57] pour une étude et une comparaisonde différents paradigmes de programmation). Le prix à payer est double. Toutd’abord, la sémantique des opérations change dans la mesure où la configurationde la structure de données telle qu’elle se présentait au début de l’opérationest définitivement perdue. Par ailleurs, il n’existe pas de techniques systéma-tiques pour passer du cadre « persistant » au cadre « éphémère » : chaque casest particulier. Un exemple particulièrement instructif est celui des mises à jourdans les Avl (cf. section 6.6, page 191). La solution fonctionnelle peut exploiter

Page 88: Structures de données et méthodes formelles ||

76 Structures de données et méthodes formelles

simultanément l’arbre initial et l’arbre en cours d’élaboration. La solution éphé-mère exige de gérer dans la structure de données des informations portant surla différence de rayon entre l’arbre initial (qui est perdu) et l’arbre en cours deconstruction.

Page 89: Structures de données et méthodes formelles ||

Chapitre 3

Étude de quelques structuresoutils

La recherche de mises en œuvre efficaces pour les structures de donnéesfondamentales conduit à raffiner celles-ci par des structures de données secon-daires. Comme par un système d’échafaudages, la réalisation de ce qui relève duniveau abstrait s’appuie sur des structures de données concrètes. S’il est impor-tant de définir avec précision ce que l’on veut réaliser (la structure de donnéesabstraite), il est tout aussi important de maîtriser les outils (les structures dedonnées concrètes) avant de se lancer dans le travail de mise en œuvre. C’estnotre objectif pour ce chapitre. En nous intéressant aux listes, aux arbres etenfin aux sacs, nous nous donnons les moyens, selon les cas, de spécifier ou d’im-planter des structures de données. Alors que les tableaux font partie intégrantede la théorie des ensembles, dont les principes élémentaires sont rappelés auchapitre 1 (un tableau à une dimension est une fonction totale définie sur unintervalle d’entiers), ce n’est a priori pas le cas des listes, des arbres ni des sacsqui résultent de l’ajout d’une « couche » supplémentaire qui enveloppe la théoriedes ensembles.

Il est bien entendu vain de chercher à répertorier toutes les structures dedonnées outils envisageables. C’est pourquoi dans ce chapitre nous limitons notreétude aux structures qui forment le substrat de la seconde partie de l’ouvrage.Concernant les arbres, nous nous arrêtons sur les trois catégories rencontréesen partie II : les arbres non ordonnés, les arbres planaires et les arbres n-aires(en insistant plus particulièrement sur deux variantes de ces derniers : les arbresbinaires et les arbres externes).

La construction de ces différentes structures de données se fait en appliquantla théorie du point fixe introduite à la section 1.9. Il en résulte un schéma d’or-ganisation qui s’appuie sur la théorie des ensembles et qui peut se représenterpar le « camembert » suivant :

Page 90: Structures de données et méthodes formelles ||

78 Structures de données et méthodes formelles

ensembles

listes

arbres

planaires

arbresbinaires

etarbres-feuilles

arbresnonordonnés

sacs

3.1 Listes finies

Les listes (ou listes linéaires) finies sont des structures qui peuvent servir soità spécifier, soit à implanter des structures fondamentales comme les ensembles,les files simples, etc.

3.1.1 Présentation informelle

Informellement, une liste finie est une succession (éventuellement vide) devaleurs de même nature. Chaque valeur peut être identifiée par sa position dansla liste, la première position (celle repérée par le nombre 1) désigne la tête deliste. La notation de base est la suivante pour une liste l1 constituée des valeurs3 (en tête) et 7 :

l1 = [3 | [7 | [ ]]]

Cette notation est appelée notation récursive. Il existe cependant une notation« linéaire » équivalente, plus agréable à l’œil 1 que nous définissons plus tard etqui permet de décrire l1 sous la forme [3, 7].

Trois opérations sont définies et étudiées : la concaténation de deux listes(notée par l’opérateur infixé ), l’inversion d’une liste (notée par l’opérateurpostfixé ) et la longueur d’une liste.

Si l2 = [7 | [12 | [4 | | [ ]]]], la liste ci-dessous est la concaténation de l1et de l2 :

l1 l2 = [3 | [7 | [7 | [12 | [4 | [ ]]]]]]

Notons qu’il est possible de rencontrer plusieurs fois la même valeur dans uneliste, c’est le cas de 7 dans l1 l2. La liste ci-dessous est l’inverse de la liste l2 :

l2˜ = [4 | [12 | [7 | [ ]]]]

L’expression #(l2) représente la longueur de la liste l2, soit 3.

1. Mais paradoxalement d’une pratique plus délicate.

Page 91: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 79

Listes et fichiers séquentiels

Les tambours et disques magnétiques sont apparus précocement surles ordinateurs – dès les années 1950 – en tant que supports externes d’in-formations. En dépit des avantages de ce type de support (liés à l’accèsdirect), de nombreux « gros systèmes » dotés exclusivement de bandesmagnétiques (qui, elles, se caractérisent par un accès séquentiel : pouraccéder à une valeur enregistrée sur la bande, il faut avoir accédé à toutesles valeurs qui précèdent !) ont subsisté jusqu’à la fin des années 1960.L’histoire se répète puisqu’à la fin des années 1970, les premiers micro-ordinateurs ne disposaient eux non plus que de supports séquentiels (deslecteurs-enregistreurs de cassettes en général) en tant que mémoires per-sistantes.

Les systèmes de fichiers à bandes magnétiques les plus rudimentairesdisposaient de six opérations de base pour la manipulation des données :trois opérations liées à la lecture – ouverture du fichier en lecture, détec-tion de la marque de « fin de fichier » et lecture d’un enregistrement –et enfin de trois opérations dédiées à l’écriture : ouverture du fichier enécriture, écriture d’un enregistrement et fermeture du fichier (provoquantl’écriture d’une marque de fin de fichier détectable à la lecture). Ces fonc-tionnalités subsistent dans les systèmes de gestion de fichiers actuels,même si en général les fichiers séquentiels sont implantés sur des sup-ports à accès direct.

Les informaticiens de l’époque ont dû déployer des trésors d’ingénio-sité pour réaliser, avec de tels supports, des applications aussi complexesque des systèmes d’information, des utilitaires de toutes sortes ou en-core des systèmes d’exploitation. Dans [75], vol. 2, D. Knuth décrit demanière encyclopédique des algorithmes contraints par ce type de limi-tations matérielles. Il porte un effort particulier sur les « tris par bandesmagnétiques », pierre angulaire des premiers systèmes d’information.

Les listes sont des structures proches des fichiers séquentiels. À la finde ce chapitre le lecteur trouvera plusieurs exercices qui empruntent le« style séquentiel » caractéristique des algorithmes destinés aux systèmes« à bandes magnétiques ».

3.1.2 Ébauche de construction

Nous allons, pour la première fois, appliquer la théorie du point fixe étudiée àla section 1.9 pour construire des listes sur l’ensemble T . Rappelons que le pointclé de la démarche est la recherche d’une fonction « pivot » f dont le plus petitpoint fixe est l’ensemble que l’on cherche à définir. La démarche de constructionse présente en six points (cf. [3] pour un développement et pour le détail desdifférentes démonstrations) :1. Définition formelle des notations (ici [ ] et [. . . | . . .]) utilisées pour faciliter

les manipulations.

Page 92: Structures de données et méthodes formelles ||

80 Structures de données et méthodes formelles

2. Définition de la fonction qui permet d’agrandir une structure existante (icic’est la fonction qui ajoute un élément en tête de liste, elle est notée [|]).

3. Définition de la fonction « pivot » f dont on recherche le plus petit pointfixe fix(f). Ce point fixe existe si (c’est une condition suffisante) f estmonotone. Il est donc important de s’assurer de cette propriété.

4. Attribution d’un nom au point fixe en question (ici ce sera liste(T )). Cenom dénote l’ensemble que l’on cherche à construire. Le fait qu’il s’agissed’un point fixe permet alors de caractériser cet ensemble.

5. Recherche d’une propriété caractéristique « inductive » de l’ensembleconstruit. Dans la seconde partie de l’ouvrage, ce type de propriété n’estpas systématiquement déduit mais est admis sans en développer la cons-truction.

6. Instanciation du principe d’induction. Ce principe se décline différemmentselon la nature de la structure de données.

Avant d’appliquer cette démarche, il nous faut décider de la représenta-tion ensembliste des listes sur T . Nous optons pour le choix suivant : uneliste sur T est une fonction partielle 2 de N1 dans T . Ainsi la liste l3 =[3 | [7 | [7 | [12 | [4 | [ ]]]]]] se représente par :

{1 �→ 3, 2 �→ 7, 3 �→ 7, 4 �→ 12, 5 �→ 4}

Déroulons à présent la démarche de construction :1. Les notations [ ] (liste vide) et [t | q] (liste dont le premier élément est t

et la queue q) se définissent par :

Notation Définition Condition

[ ] ∅

[t | q] {1 �→ t} ∪ q� 1 t ∈ T ∧ q ∈ N1 �→ T

2. La fonction [|](T ) qui construit une liste à partir d’un élément t et d’uneliste q se définit par :[|](T ) = λ(t, q) ·(t ∈ T ∧ q ∈ N1 �→ T | [t | q])

3. La fonction « pivot » f se définit alors par :f(T ) = λz ·(z ∈ P(N1 �→ T ) | {[ ]} ∪ [|](T )[T × z])

[|](T )[T ×z] est l’image par la fonction [|](T ) du produit cartésien T ×z. Ils’agit bien d’une fonction de P(N1→ T ) dans P(N1→ T ). De plus f(T )(z)est monotone en z. Cette dernière propriété résulte de la monotonie del’opérateur ∪, de celle de [|](T )[T × z] en T × z et enfin de la monotoniedu produit cartésien par rapport à son second argument. f possède doncun plus petit point fixe noté fix(f(T )).

4. Posons liste(T ) = fix(f(T )). Par définition nous avons alors :liste(T ) = {[ ]} ∪ [|](T )[T × liste(T )]

5. De l’égalité précédente nous déduisons les deux propriétés suivantes :1) [ ] ∈ liste(T )2) ∀(t, q) ·(t ∈ T ∧ q ∈ liste(T )⇒ [t | q] ∈ liste(T ))

2. Fonction dont le domaine est un intervalle 1 .. n.

Page 93: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 81

Remarque. Pour ce qui concerne la seconde propriété, dans la suite noussacrifions à la tradition en n’explicitant pas la quantification :

2) t ∈ T ∧ q ∈ liste(T )⇒ [t | q] ∈ liste(T )

6. Il est alors possible de décliner le principe d’induction sous une forme plustraditionnelle que celle présentée à la section 1.9 (la preuve est laissée enexercice) :[l := [ ]]P ∧∀l ·(l ∈ liste(T ) ∧ P ⇒ ∀t ·(t ∈ T ⇒ [l := [t | l]]P ))

⇒∀l ·(l ∈ liste(T ) ⇒ P )

Tableau 3.1 – Propriétés des listes.La propriété 3.1.1 établit que la liste vide [ ] est élément neutre à droitepour la concaténation. Depuis la définition de la concaténation noussavons déjà que [ ] est élément neutre à gauche. La proposition 3.1.2fournit une condition nécessaire et suffisante pour démontrer que laconcaténation de deux listes est la liste vide. La proposition 3.1.3 portesur l’associativité de la concaténation. La proposition 3.1.4 établit latransposition de la concaténation par inversion. La proposition 3.1.8montre que l’inversion est involutive tandis que la proposition 3.1.9montre que toute liste ne comportant qu’un seul élément est sa propreinverse. Enfin les deux propositions 3.1.11 et 3.1.12 portent sur la lon-gueur des listes. Ci-dessous l, a, b et c sont des listes sur T .

Propriété Condition Ident.

l [ ] = l (3.1.1)a = [ ] ∧ b = [ ] ⇔ a b = [ ] (3.1.2)((a b) c) = (a (b c)) (3.1.3)a b = (b˜a )˜ (3.1.4)a c = b c ⇔ a = b (3.1.5)c a = c b ⇔ a = b (3.1.6)(a b)˜ = b˜a˜ (3.1.7)

(a )˜ = a (3.1.8)[t | [ ]]˜ = [t | [ ]] t ∈ T (3.1.9)a˜ = b˜ ⇔ a = b (3.1.10)

#(a b) = #(a) + #(b) (3.1.11)#(a ) = #(a) (3.1.12)

[ ] = [t | l] t ∈ T (3.1.13)

Page 94: Structures de données et méthodes formelles ||

82 Structures de données et méthodes formelles

3.1.3 Opérations sur les listesLes opérations introduites à la section 3.1.1 peuvent maintenant être définies

rigoureusement comme suit :

Notation Définition Condition

[ ] l l l ∈ liste(T )

[t | q] l [t | q l] t ∈ T ∧ q ∈ liste(T ) ∧ l ∈ liste(T )

[ ]˜ [ ]

[t | q]˜ q˜[t | [ ]] t ∈ T ∧ q ∈ liste(T )

#([ ]) 0

#([t | q]) 1 + #(q) t ∈ T ∧ q ∈ liste(T )

Le tableau 3.1, page précédente, regroupe un certain nombre de propriétésdes listes en relation avec la liste vide, l’inversion, la concaténation et la longueur.La démonstration de ces propriétés fait l’objet de l’exercice 3.1.4.

3.1.4 Notation linéaireLa notation linéaire présentée ci-dessus se définit formellement de la manière

suivante :

Notation Définition Condition

[t] [t | [ ]] t ∈ T

[t, l] [t | [l]] t ∈ T ∧ [l] ∈ liste(T )

Exercices

Exercice 3.1.1 Ci-dessus nous avons fourni une construction inductive des listes. Proposer àprésent une construction directe.

Exercice 3.1.2 Convertir en notation linéaire les listes suivantes sur N :1. [12 | [17 | [15 | [ ]]]]2. [45 | [1 | [57 | [0 | [ ]]]]]

Exercice 3.1.3 Convertir en notation récursive les listes suivantes sur N :1. [6]2. [4, 6, 23]

Exercice 3.1.4 Démontrer les propriétés des listes répertoriées dans le tableau 3.1, pageprécédente.

Exercice 3.1.5 Cet exercice propose de définir et d’étudier des listes particulières sur N.1. Construire les listes listeSD(T ) sans doublon sur T .2. Construire les listes listeT triées sur N.3. Construire les listes listeTSD triées et sans doublon sur N.4. Soit l1 et l2 deux listes triées sans doublon, d’intersection vide. Définir la fonction union

qui délivre la liste triée sans doublon r représentant l’union des deux listes.

Page 95: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 83

5. Soit l1 et l2 deux listes triées sans doublon. Définir la fonction inter qui délivre la listetriée sans doublon r représentant l’intersection des deux listes.

Exercice 3.1.6 Considérons les listes définies sur N × N, triées sur le premier composant duproduit cartésien N× N. l = [4 �→ 25, [4 �→ 30, [5 �→ 6, [7 �→ 23, [ ]]]]] est un exemple d’une telleliste.

1. Construire l’ensemble correspondant listeT .2. Définir la fonction cumul qui délivre une liste r sans doublon telle qu’à chaque occur-

rence du premier composant est associée la somme des valeurs du second composant.Ainsi, pour la liste l, nous aurons r = [4 �→ 55, [5 �→ 6, [7 �→ 23, [ ]]]].

Exercice 3.1.7 Définir l’opérateur conc de concaténation généralisée tel que si l =[[7, 9], [1, 4, 6], [9, 5, 1]], conc(l) est la liste obtenue en concaténant toutes les listes qui consti-tuent l : conc(l) = [7, 9, 1, 4, 6, 9, 5, 1].

3.2 Arbres finis

Les arbres constituent des outils incontournables dans la recherche de repré-sentations concrètes efficaces pour des structures de données abstraites, telles quela représentation des ensembles, des files de priorité ou des tableaux flexibles.

La nomenclature que nous proposons ici est orientée vers les objectifs visés :nous n’étudions que les arbres utilisés comme structures de données secondairesdans la partie II. Le premier critère que nous considérons concerne l’organisationdes sous-arbres d’un nœud donné. Ceci nous conduit à distinguer, en allant desarbres les moins contraints vers les plus contraints :

– les arbres non ordonnés pour lesquels un nœud possède un ensemble desous-arbres ;

– les arbres planaires (ou ordonnés) pour lesquels les sous-arbres de chaquenœud sont organisés en listes ;

– les arbres n-aires (pour n donné, n > 0) pour lesquels les sous-arbres sontorganisés en tableaux de longueur n.

Les arbres non ordonnés sont dans la suite utilisés pour la représentation d’en-sembles de chaînes. Les arbres planaires permettent de représenter des files depriorité. Enfin les arbres n-aires, et en particulier les arbres binaires (n = 2),apparaissent dans la représentation concrète des ensembles, des files de prioritéet des tableaux flexibles.

Ce premier critère ne s’intéresse qu’à la structuration des sous-arbres. Cepen-dant, l’informaticien doit en général disposer d’informations associées à tout oupartie des nœuds d’un arbre. Le terme d’étiquette (label) est en général utilisépour désigner ces informations. Si la valeur de l’étiquette identifie le nœud oùelle apparaît, elle peut être appelée clé ou identifiant. Le second critère distingueles arbres pour lesquels tous les nœuds sont étiquetés de ceux pour lesquels seulscertains nœuds le sont. Les arbres totalement étiquetés sont les plus fréquentsmais les arbres partiellement étiquetés sont parfois utilisés avec quelques avan-tages dans la représentation des ensembles et des tableaux flexibles.

Quel que soit le critère retenu, nous ne nous intéressons dans la suite qu’auxarbres finis.

Page 96: Structures de données et méthodes formelles ||

84 Structures de données et méthodes formelles

En théorie des graphes, un arbre est défini comme un graphe acyclique sim-plement connexe 3. Ainsi, le graphe suivant :

••

••

••••

••

est un arbre. Notons que cette définition ne distingue aucun sommet en particu-lier et que les segments joignant deux sommets ne sont pas orientés, ce sont desarêtes.

Cette notion (aussi appelée arbre libre ou arbre non enraciné) doit être enri-chie pour se révéler utile à l’informaticien. En distinguant un nœud particulier,appelé racine de l’arbre, nous admettons du même coup une orientation desarêtes dans le sens racine/autre nœud, arêtes qui, dans la terminologie de lathéorie des graphes, deviennent des arcs. Ainsi, si dans le schéma ci-dessus nousdistinguons le sommet désigné par la flèche, nous obtenons l’arbre suivant

• •

• •

• •(1)

Ce type d’arbre est appelé arborescence dans la théorie des graphes et arbreenraciné (ou simplement arbre) par l’informaticien. Bien qu’il s’agisse toujoursd’un objet de la théorie des graphes (un graphe orienté acyclique connexe par-ticulier) il est plus intéressant pour l’informaticien de le construire (souvent parun procédé inductif) à partir de la théorie des ensembles. Les avantages que l’onen retire tiennent à ce que les définitions inductives se prêtent mieux aux dé-monstrations, ainsi qu’aux développements algorithmiques. En outre, en touterigueur, le passage par la théorie des graphes exige d’expliciter l’ensemble quisert de support aux sommets ; les constructions inductives permettent de s’enpasser.

Sans rechercher une formalisation excessive, nous pouvons à présent préciserquelques définitions utiles autour des arbres enracinés. Nous le savons déjà, lesommet distingué est la racine. Le terme nœud est un synonyme courant poursommet. Lorsque l’orientation n’est pas pertinente, un arc est appelé branche.Si le nœud b est relié au nœud a par un arc, b est un fils de a. Un nœud quine possède aucun fils est une feuille. Le nombre de fils que possède un nœud estson arité. Si b est un fils de a, l’arbre enraciné qui a comme racine b est un sous-arbre de a. Si le nœud c appartient à un sous-arbre de a, c’est un descendant

3. Il existe plusieurs propriétés caractéristiques alternatives. Nous supposons le lecteur fa-milier avec les rudiments de la théorie des graphes.

Page 97: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 85

de a. Le nombre de nœuds d’un arbre est son poids 4. Le nombre de branchesqui séparent un nœud b de la racine est la hauteur de b. La hauteur d’un arbreest la plus grande hauteur obtenue en considérant toutes les feuilles. Une forêtest un ensemble (structuré – ou non – en liste ou en tableau) d’arbres. Dans lesschémas ci-dessous le sens des arcs est omis. Par convention il va de haut en bas.

Nous allons à présent reprendre la nomenclature introduite ci-dessus afind’étudier chacun des types d’arbre.

3.3 Arbres non ordonnés

3.3.1 Introduction : les arbres non ordonnés non étiquetésInformellement, un arbre non ordonné est un arbre tel que, pour chaque

nœud a, les sous-arbres dépendant directement de a sont organisés en ensemble 5.L’ordre dans lequel ils apparaissent n’est donc pas pertinent. Ainsi, les deuxschémas ci-dessous

• •

• •

• •

(2)

représentent le même arbre non ordonné. Il ne sera donc pas possible de désignerun sous-arbre par une expression telle que « le deuxième sous-arbre du nœud a »dans la mesure où la notion d’ordre sur les sous-arbres n’est pas significative.Nous admettons que l’arbre suivant :

n’est pas un arbre non ordonné. Les sous-arbres de la racine ne constituent pasun ensemble puisque le sous-arbre doté d’un seul fils apparaît deux fois 6.

3.3.2 Arbres non ordonnés étiquetésL’intérêt des arbres non ordonnés s’accroît si l’on attribue une étiquette à

chaque nœud. C’est le type d’arbre que nous proposons d’étudier à présent.

4. Le terme taille est parfois utilisé. Nous préférons le terme poids, celui de taille présenteun risque de confusion avec celui de hauteur.

5. Une variante, proposée à l’exercice 3.3.1 consiste à organiser les sous-arbres en sac.

6. Une autre convention consisterait à admettre que cet arbre est identique à

•••

•••

• .

Page 98: Structures de données et méthodes formelles ||

86 Structures de données et méthodes formelles

Présentation informelle

La figure 3.1 ci-dessous montre, pour des arbres étiquetés sur N, trois exemplesdont un (l’arbre (3)) n’est pas un arbre non ordonné. Dans la suite, les arbresnon ordonnés servent de base à la notion d’arbre trie, notion qui est utilisée pourreprésenter des ensembles de chaînes.

7

4

12

1 14

8 9

2

8

9

10

7

3

4

11

12

5

8

9

10

7

3

4

11

9

10

(1) (2) (3)

Figure 3.1 – Arbres non ordonnés étiquetés.L’arbre (1) est une version étiquetée de l’arbre (2) ci-dessus. L’arbre (2)est un arbre non ordonné étiqueté tandis que, selon notre convention,l’arbre (3) n’est pas un arbre non ordonné étiqueté puisque deux dessous-arbres de la racine sont identiques.

Ébauche de construction

La construction d’un arbre non ordonné se fait en enracinant une forêt nonordonnée f à une racine v. Le résultat se note 〈v, f〉 et se définit formellementpar :

Notation Définition Condition

〈v, f〉 v �→ f v ∈ T ∧ f ∈ fnoe(T )

où fnoe(T ) représente l’ensemble des forêts non ordonnées sur T . Nous pouvonsremarquer que cette définition interdit les arbres non ordonnés vides.

La nature des arbres non ordonnés exige de définir simultanément (de manièrecroisée) les forêts non ordonnées (fnoe(T )) et les arbres non ordonnés (anoe(T )) :

Notation Définition

anoe(T ) {v �→ f | v ∈ T ∧ fnoe(T )}fnoe(T ) P({x | x ∈ anoe(T )})

Lorsque nous serons amené à utiliser les arbres non ordonnés, il sera né-cessaire de réaliser un choix d’implantation pour les forêts puisque celles-ci sedéfinissent comme des ensembles (cf. section 7.1).

Page 99: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 87

Exercice

Exercice 3.3.1 Nous avons défini formellement les arbres non ordonnés en considérant que lessous-arbres d’un nœud constituent un ensemble d’arbres. Proposer une structure d’arbres danslaquelle la collection de sous-arbres constitue un sac (cf. section 3.7 pour une introduction auxsacs).

3.4 Arbres planaires

3.4.1 Introduction : les arbres planaires non étiquetés

Informellement, un arbre planaire est un arbre dans lequel les sous-arbres dechaque nœud sont organisés en liste. Une telle liste est une forêt. Ainsi, l’arbre (3)suivant :

• • •

• •

•(3) (4)

est un arbre planaire. Cette fois l’ordre d’apparition est significatif, il est possiblede désigner un sous-arbre d’un nœud a par l’expression « le 2e sous-arbre dunœud a ». Et, si l’arbre (4) ci-dessus est également un arbre planaire, il estdifférent du premier.

3.4.2 Arbres planaires étiquetés

De même que dans le cas des arbres non ordonnés, il est possible d’apposerune valeur à chaque nœud de l’arbre.

Présentation informelle

La figure 3.2, page suivante, montre trois exemples d’arbres planaires étique-tés sur N. Dans la suite, les arbres planaires servent de base à la notion d’arbrebinomial, notion qui est utilisée pour représenter les files de priorité.

Ébauche de construction

La construction des arbres planaires est assez similaire à celle des arbresnon ordonnés. Elle se fait en enracinant une forêt planaire f à une racine v. Lerésultat se note 〈v, f〉 et se définit formellement par :

Notation Définition Condition

〈v, f〉 v �→ f v ∈ T ∧ f ∈ fple(T )

Page 100: Structures de données et méthodes formelles ||

88 Structures de données et méthodes formelles

où fple(T ) représente l’ensemble des forêts planaires sur T . De même que pourles arbres non ordonnés, nous pouvons remarquer que cette définition interditles arbres planaires vides.

La nature des arbres planaires exige de définir simultanément (de manièrecroisée) les forêts d’arbres planaires (fple(T )) et les arbres planaires (aple(T )) :

Notation Définition

aple(T ) {v �→ f | v ∈ T ∧ fple(T )}fple(T ) liste(aple(T ))

Lorsque nous serons amené à utiliser les arbres planaires (cf. section 9.4 parexemple), nous pourrons utiliser les représentations et les propriétés des listespour implanter les forêts planaires.

7

4

9

3

8 1 2

9

5

12

7

4

9

4

9

3

8 2

4

10

7

4

12

1 14

8 9

2

(1) (2) (3)

Figure 3.2 – Arbres planaires étiquetés.Les trois arbres sont des arbres planaires. Malgré l’existence dans

l’arbre (2) de deux sous-arbres identiques :4

9, il s’agit bien d’un

arbre planaire : la position relative de ces deux sous-arbres permet deles distinguer.

3.5 Arbres n-aires

3.5.1 Introduction : les arbres n-aires non étiquetésInformellement, un arbre n-aire est un arbre tel qu’à tout nœud est associé un

tableau de n sous-arbres (dont certains peuvent être vides). Ainsi, par exemple,pour n = 2, l’arbre (5) ci-dessous

• •

(5)

• •

(6)

est un arbre 2-aire (binaire). Il ne doit pas être confondu avec l’arbre (6) ci-dessus (qui est également binaire) puisque dans l’arbre (6) le nœud désigné parla flèche est tel que sa place gauche est un arbre vide. Dans un arbre binaire,un nœud qui ne possède qu’un seul fils est appelé point simple. La suite de cettesection est consacrée à l’étude des arbres binaires. Les résultats se généralisentfacilement aux arbres n-aires quelconques.

Page 101: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 89

3.5.2 Les arbres binaires étiquetésPrésentation informelle – Typologie

Dans le reste de l’ouvrage nous avons besoin de nommer quelques arbresbinaires particuliers, les quatre principaux étant les arbres filiformes, les arbrescomplets, les arbres pleins et les arbres parfaits. La figure 3.3 ci-dessous illustrechacun de ces types d’arbres. Un arbre filiforme est un arbre dont tous les nœudssont des points simples (à l’exception de l’unique feuille qui n’a pas de fils. . . ). Unarbre complet est un arbre qui ne possède pas de points simples. Un arbre pleinest un arbre complet dont toutes les feuilles sont situées à la même hauteur. Unarbre parfait est tel que : (i) toutes les feuilles sont situées sur au plus les deuxderniers (plus bas) niveaux, (ii) quand l’arbre parfait n’est pas un arbre plein(c’est-à-dire quand les feuilles sont effectivement réparties sur deux niveaux), lesfeuilles du dernier niveau sont groupées sur la gauche, (iii) il existe au plus unpoint simple, il est situé sur l’avant-dernier niveau.

• •

• •

• •

• •

• •

• •

• •

• •

(1) (2) (3) (4)

Figure 3.3 – Quelques types particuliers d’arbres binaires.L’arbre (1) est un arbre filiforme. L’arbre (2) est un arbre complet.L’arbre (3) est un arbre plein. L’arbre (4) est un arbre parfait à gauche :ses feuilles sont situées sur deux niveaux, il y a un point simple surl’avant-dernier niveau et les feuilles du plus bas niveau sont situées surla partie gauche. Notons que l’arbre (3) est également un arbre parfait(à gauche comme à droite), c’est aussi un arbre complet.

Ainsi que nous l’avons déjà écrit, en général l’informaticien associe à tout oupartie des nœuds une étiquette qui complète l’information purement structurellevéhiculée par un arbre non étiqueté. Le cas des arbres partiellement étiquetésest étudié séparément. Deux exemples d’arbres étiquetés sur N sont donnés parle schéma ci-dessous :

6

4

1 3

8

9

(7)

1

2

5 2

3

9

(8)

Dans un tel arbre, un nœud qui possède un fils gauche (resp. droit) mais pas defils droit (resp. gauche) est appelé point simple à gauche (resp. à droite). Dansl’arbre (7) ci-dessus, le nœud étiqueté 8 est un point simple à droite.

Citons deux classes importantes d’arbres binaires étiquetés : les arbres bi-naires de recherche (ou abr) et les minimiers (ou tournois). L’arbre (7) est un

Page 102: Structures de données et méthodes formelles ||

90 Structures de données et méthodes formelles

abr : pour tout nœud étiqueté n, le sous-arbre gauche (resp. droit) ne contientque des valeurs inférieures (resp. supérieures) à n. L’arbre (8) est un minimier :pour tout nœud n de l’arbre, n est un représentant de la plus petite valeurprésente dans l’arbre. Les structures étudiées ci-dessous sont, pour la plupart,fondées sur des variantes ou des extensions de l’un de ces deux types d’arbre(Avl, B-arbre, arbre binomial, etc.).

Ébauche de construction

Nous adoptons le mode de construction inductif déjà pratiqué pour la cons-truction des listes. Avant d’appliquer la démarche proposée à la section 3.1, nousdevons décider de la représentation ensembliste des arbres binaires étiquetés surT . Un arbre binaire étiqueté sur T se représente par une fonction définie sur deslistes (de g ou de d pour gauche ou droite) et à valeurs dans T . La liste représenteles directions, gauche ou droite, que l’on doit emprunter depuis la racine avantde rencontrer l’étiquette considérée. Ainsi l’arbre (7) ci-dessus est représenté parla fonction suivante :

{ [ ] �→ 6,[g] �→ 4,[d] �→ 8,[g, g] �→ 1,[g, d] �→ 3,[d, d] �→ 9

}

Développons à présent les six étapes de la démarche de construction pour lesarbres binaires étiquetés :

1. Les notations 〈〉 (arbre vide) et 〈l, v, r〉 (arbre dont la racine est v, le sous-arbre gauche l et le sous-arbre droit g) se définissent par :

Not. Définition Cond.

〈〉 ∅

〈l, v, r〉 ([ ] �→ v) ∪

⎛⎜⎝ (λf ·(f ∈ dom(l) | [g | f ]))−1 ; l

∪(λf ·(f ∈ dom(r) | [d | f ]))−1 ; r

⎞⎟⎠ (3.5.1)

La définition de 〈l, v, r〉 est soumise à la condition 3.5.1 suivante : l ∈liste({g, d}) �→ T ∧ r ∈ liste({g, d}) �→ T ∧ v ∈ T

2. La fonction 〈, , 〉 qui construit un nouvel arbre à partir de v, élément de Tet de deux arbres l et r se définit par :

〈, , 〉(T ) = λ(l, v, r) ·

⎛⎝ l ∈ liste({g, d}) �→ T ∧v ∈ T ∧r ∈ liste({g, d}) �→ T

∣∣∣∣∣∣ 〈l, v, r〉⎞⎠

Page 103: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 91

3. La fonction « pivot » f se définit alors par :

f(T ) = λ(l, r) ·(

l ∈ P(liste({g, d}) �→ T )∧r ∈ P(liste({g, d}) �→ T )

∣∣∣∣ {〈〉} ∪ 〈, , 〉(T )[l × T × r]

)〈, , 〉(T )[l × T × r] est l’image par la fonction 〈, , 〉(T ) du produit carté-sien l × T × r. Il s’agit bien d’une fonction de P(liste({g, d}) �→ T ) dansP(liste({g, d}) �→ T ). De plus f(T )(l, r) est monotone en l et r. Cettedernière propriété résulte de la monotonie de l’opérateur ∪, de celle de〈, , 〉(T )[l × T × r] en l × T × r et enfin de la monotonie du produit carté-sien. f possède donc un plus petit point fixe noté fix(f(T )).

4. Posons abe(T ) = fix(f(T )). Par définition nous avons alors :

abe(T ) = {〈〉} ∪ 〈, , 〉(T )[abe(T )× T × abe(T )]

5. De l’égalité précédente nous déduisons les deux propriétés suivantes :

1) 〈〉 ∈ abe(T )2) l ∈ abe(T ) ∧ v ∈ T ∧ r ∈ abe(T )⇒ 〈l, v, r〉 ∈ abe(T ))

qui caractérisent les arbres binaires étiquetés.6. Il est alors possible de décliner le principe d’induction sous une forme plus

traditionnelle que celle présentée à la section 1.9 (la preuve est laissée enexercice) :

[a := 〈〉]P ∧

∀(l, r) ·

⎛⎜⎜⎝⎛⎜⎜⎝

l ∈ abe(T )∧r ∈ abe(T )∧[a := l]P∧[a := r]P

⎞⎟⎟⎠ ⇒ ∀v ·(v ∈ T ⇒ [a := 〈l, v, r〉]P )

⎞⎟⎟⎠⇒

∀a ·(a ∈ abe(T ) ⇒ P )

Opérations sur les arbres binaires étiquetés

Le tableau 3.2, page suivante, fournit une définition formelle des principalesopérations sur les arbres binaires étiquetés. Intuitivement, moins un arbre esthaut, plus les opérations de consultation et de mise à jour sont efficaces. Cetteremarque sous-tend la recherche d’opérations tendant à diminuer la hauteurd’un arbre tout en préservant ses « bonnes » propriétés. Les rotations constituentl’archétype de telles opérations. rd, rg, rgd, rdg sont les principales opérations derotation rencontrées. Les rotations étant (en général mais pas toujours) destinéesà diminuer la hauteur, il nous faut définir formellement ce qu’est la hauteur d’unarbre, c’est le but de la fonction h. L’équilibre en hauteur est quant à lui défini àtravers le prédicat hEq. Préserver les bonnes propriétés d’un arbre par rotationconsiste souvent à s’assurer que les arbres avant et après la rotation représententla même liste d’éléments. L’obtention de ce type de liste est le rôle dévolu auxopérations prefixe, infixe, postfixe.

Ainsi que nous l’avons déjà dit ci-dessus, la hauteur d’un arbre est le nombrede branches qui séparent la racine de la feuille la plus éloignée de la racine. Lahauteur n’est donc pas définie pour un arbre vide. Cette définition est conforme

Page 104: Structures de données et méthodes formelles ||

92 Structures de données et méthodes formelles

à l’usage, ainsi qu’à la norme établie par le nist (cf. [2]). Cependant elle pré-sente l’inconvénient de se traduire par une fonction partielle (puisqu’elle n’estpas définie pour les arbres vides). Nous pouvons contourner cette limitation endéfinissant la notion de rayon 7 qui est utilisée quand nécessaire et en particulierjustement dans la définition de la hauteur puisque, quand la hauteur est définie,elle est égale au rayon moins 1.

Tableau 3.2 – Définitions portant sur les arbres binaires étiquetés.

Notation Définition

rd(〈〈gg, vg, dg〉, v, d〉) 〈gd, vg, 〈dg, v, d〉〉rg(〈g, v, 〈gd, vd, dd〉〉) 〈〈g, v, gd〉, vd, dd〉rgd(〈〈gg, vg, 〈ggd , vgd , dgd〉〉, v, d〉) 〈〈gg, vg, ggd〉, vgd , 〈dgd , v, d〉〉rdg(〈g, v, 〈〈gdg , vdg , ddg 〉, vd, dd〉〉) 〈〈g, v, gdg 〉, vdg , 〈ddg , vd, dd〉〉r(〈〉) 0

r(〈g, v, d〉) max({r(g), r(d)}) + 1prefixe(〈〉) [ ]

prefixe(〈g, v, d〉) [v] prefixe(g) prefixe(d)infixe(〈〉) [ ]

infixe(〈g, v, d〉) infixe(g) [v] infixe(d)postfixe(〈〉) [ ]

postfixe(〈g, v, d〉) postfixe(g) postfixe(d) [v]w(〈〉) 0

w(〈g, v, d〉) w(g) + 1 + w(d)

h(a) r(a)− 1 Si a n’est pas videhEq(〈〉) �

hEq(〈g, v, d〉) hEq(g) ∧ hEq(d)∧r(g)− r(d) ∈ −1 .. 1

La définition de la hauteur h est valide à condition que a ∈ abe(T )−{〈〉} (lahauteur n’est pas définie pour un arbre vide). Concernant les conditions pourles autres opérations, tous les g . . . et les d . . . sont des abe(T ), et tous les v . . .appartiennent à T .

Un équilibre parfait en hauteur n’est pas toujours possible (cf. exercice 3.5.3).C’est pourquoi nous considérons qu’un arbre binaire est (simplement) équilibré(nous disons h-équilibré) si, pour tout nœud de l’arbre, le rayon du sous-arbregauche diffère de celui du sous-arbre droit d’au plus 1 en valeur absolue.

7. Notion définie ici par analogie avec la notion de diamètre dans les graphes.

Page 105: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 93

Exemples. Dans les exemples qui suivent la valeur de déséquilibre de chaquenœud est apposée au nœud. 0 signifie que le nœud est parfaitement équilibré enhauteur et, pour i > 0, i (resp. −i) signifie qu’il existe un déséquilibre de i enfaveur du sous-arbre gauche (resp. droit).

• •

• •

• •

+1

+1

-1

0 +1

0

+1

0

-1

0 0

0 0

Un arbre h-équilibré

• •

• •

-1

-1

0 -1

0

-1

-1

0

-1

0 -1

0

Un arbre h-équilibré

• •

• •

• •

• •

0

+1

-1

0 +1

0

0

0 0

-2

0 +1

0

0 0

0

Un arbre qui n’est pas h-équilibré

Relation entre poids et rayon dans un arbre binaire. Pour un poids ndonné, il peut être intéressant de savoir entre quelles limites varie le rayon r d’unarbre binaire. En effet, beaucoup d’opérations sur les arbres binaires consistentà parcourir l’arbre à partir de la racine et à descendre jusqu’à une feuille oujusqu’à un nœud intermédiaire, en s’orientant à gauche ou à droite à chaqueétape. Le nombre de nœuds franchis est majoré par le rayon de l’arbre qui a étéparcouru.

Pour un rayon r donné, les arbres ayant le plus petit nombre de nœudssont des arbres filiformes. En effet, si nous supprimons un nœud d’un arbrefiliforme, soit son rayon diminue, soit la structure résultante n’est plus un arbre.Un arbre filiforme possède r = n nœuds, un arbre quelconque est donc tel quer ≤ n. Pour un rayon r donné, les arbres binaires ayant le plus grand nombre denœuds sont les arbres pleins. En effet, un tel arbre ne peut accueillir un nouveaunœud sans voir son rayon augmenter de 1. Or, dans un arbre plein, nous avons(cf. exercice 3.5.2) n = 2r − 1. Pour un arbre quelconque, nous avons doncn ≤ 2r − 1. D’où le calcul suivant :

n ≤ 2r − 1⇔ Arithmétique

n+ 1 ≤ 2r⇔ Propriété des logarithmes (base 2)log(n+ 1) ≤ r

Page 106: Structures de données et méthodes formelles ||

94 Structures de données et méthodes formelles

⇒ Propriété D.35�log(n+ 1)� ≤ r

Au total nous avons donc :

�log(n+ 1)� ≤ r ≤ n (3.5.2)

Cette formule nous apprend que la descente dans un arbre binaire de poidsn et de rayon r n’exige jamais moins de �log(n + 1)� et jamais plus de n com-paraisons. La limite supérieure (n = r) est, si possible, à éviter compte tenu ducoût qui en résulte. Nous reviendrons sur cette conclusion.

Parcours d’arbres binaires. Il est parfois souhaitable d’extraire toutes lesvaleurs associées aux nœuds dans un arbre étiqueté. Différentes stratégies deparcours existent : parcours en profondeur (on extrait toutes les valeurs d’unsous-arbre avant de parcourir en profondeur le sous-arbre frère), en largeur : oneffectue l’extraction par niveaux successifs en partant du niveau de la racine.Concernant la stratégie de parcours en profondeur, il est possible de distinguerle parcours gauche-droite du parcours droite-gauche. Pour le parcours gauche-droite, trois cas sont envisageables : (i) le parcours préfixé pour lequel on extraitla racine avant d’effectuer un parcours préfixé des deux sous-arbres, (ii) le par-cours infixé pour lequel on effectue un parcours infixé du sous-arbre gaucheavant d’extraire la racine puis d’effectuer un parcours infixé du sous-arbre droit,(iii) le parcours postfixé pour lequel on effectue un parcours postfixé des deuxsous-arbres avant d’extraire la racine.

Rotations. Cette notion de parcours infixé permet de définir une forme d’équi-valence entre arbres binaires : les arbres a et b sont équivalents si infixe(a) =infixe(b). Les opérations de rotation sont des opérations qui préservent cetteforme d’équivalence tout en permettant une restructuration de l’arbre. Dans lapratique, trois types d’usage sont exploités :1. monter une valeur à la racine,2. descendre une valeur jusqu’aux feuilles,3. rééquilibrer un arbre déséquilibré (typiquement un arbre dans lequel le

rayon de l’un des deux sous-arbres excède de 2 le rayon de l’autre).La première fonctionnalité (monter une valeur à la racine) trouve son utilitélorsque l’on effectue une insertion à la racine en commençant par une insertionaux feuilles (cf. page 161 et exercice 6.3.1, page 168). Le second usage (descendreune valeur aux feuilles) est exploité lors de la suppression dans un Avl. Latroisième fonctionnalité est mise à profit dans des structures de données tellesque les Avl, les arbres déployés, etc. Un effet secondaire des rotations peutsurvenir dans certaines situations : il s’agit de la diminution du rayon de l’arbre.

À la section 6.6, page 191, nous verrons que dans le cas des Avl, deuxtypes de rotation sont nécessaires pour couvrir toutes les situations exigeant unrééquilibrage : les rotations simples et les rotations doubles. Pour les rotationssimples, on distingue la rotation droite et la rotation gauche. La rotation droiterd se présente comme le montre le schéma suivant 8 :

8. La lecture de droite à gauche du schéma correspond à la rotation gauche.

Page 107: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 95

v

vg

gg dg

d

vg

gg v

dg d

rd

rg

Quant aux rotations doubles, on distingue la rotation gauche-droite et la rotationdroite-gauche. La rotation gauche-droite rgd se présente comme le montre leschéma suivant :

v

vg

gg vgd

gdg ddg

d

vgd

vg

gg gdg

v

ddg d

rgd

Ainsi que le montre de manière informelle le schéma ci-dessous, la rotationgauche-droite est la composition de deux rotations simples (une rotation gauchesuivie d’une rotation droite) ; d’où son nom.

v

vg

gg vgd

gdg ddg

d

v

vgd

vg

gg gdg

ddg

d

vgd

vg

gg gdg

v

ddg drg

rd

Il est bien sûr possible de définir directement la rotation rgd, c’est ce qui estréalisé dans le tableau des définitions 3.2, page 92. La définition indirecte – àpartir de rg et rd – présente l’avantage de simplifier les démonstrations.

Exercices

Exercice 3.5.1 Construire les quatre types d’arbres binaires présentés à la figure 3.3 : lesarbres filiformes, complets, pleins et parfaits à gauche.

Exercice 3.5.2 Démontrer que, pour tout arbre binaire étiqueté a, la rotation droite de apréserve le parcours préfixé, soit prefixe(a) = prefixe(rd(a)). Refaire la démonstration pourles autres rotations et les autres parcours.

Exercice 3.5.3 Fournir une condition nécessaire de l’équilibre parfait en hauteur d’un arbrebinaire.

Page 108: Structures de données et méthodes formelles ||

96 Structures de données et méthodes formelles

3.6 Arbres binaires partiellement étiquetés : lesarbres externes

3.6.1 Présentation informelle

Un arbre externe – aussi appelé arbre-feuille (leaf tree) – est un arbre par-tiellement étiqueté dans lequel les « étiquettes » apparaissent uniquement surles feuilles. En outre, un arbre externe ne possède pas de point simple : tous lesnœuds sont dotés soit de zéro soit de deux fils (les arbres externes sont donc desarbres complets).

Exemples. Ci-dessous sont présentés deux exemples d’arbres externes sur N :

7 •

12 8

4

13 3

14 7

5 21

19

(9) (10)

Intéressons-nous à présent aux limites entre lesquelles varie le rayon r d’unarbre externe binaire pour un nombre de feuilles f donné. Pour un rayon rdonné, les arbres externes qui contiennent le minimum de feuilles (cf. l’arbre (9)ci-dessus) sont des arbres externes tels que chaque nœud interne possède aumoins une feuille comme fils. Pour de tels arbres, r = f . En effet, tout arbreexterne doté de f − 1 feuilles a un rayon inférieur à r. Pour les arbres externesen général, nous avons donc r ≤ f . Pour un rayon r donné, les arbres externesqui contiennent le plus de feuilles sont des arbres pleins. En effet, ajouter unefeuille ne peut se faire qu’en augmentant le rayon. Pour de tels arbres, si r > 0,f = 2r−1. Pour les arbres externes en général, f ≤ 2r−1. D’où :

f ≤ 2r−1

⇔ Propriété des logarithmes (base 2)log f ≤ r − 1

⇒ Propriété D.35�log f� ≤ r − 1

⇔ Arithmétique�log f�+ 1 ≤ r

En rassemblant les deux inégalités nous avons :

�log f�+ 1 ≤ r ≤ f (3.6.1)

En comparant les formules 3.5.2 et 3.6.1, nous pouvons constater (ce n’est pasune surprise) que le nombre maximum de valeurs utiles f qu’il est possibled’enregistrer dans un arbre externe tend, quand r tend vers +∞, vers la moitiédu nombre maximum de valeurs n présentes dans un arbre binaire totalementétiqueté (puisque dans ce cas f = n−1

2 ).

Page 109: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 97

3.6.2 Ébauche de construction

De même que les arbres binaires étiquetés, les arbres externes sur T se re-présentent par une fonction définie sur l’ensemble des listes finies sur {g, d} et àvaleur dans T . L’arbre (9) ci-dessus se représente par la fonction suivante :

{ [g] �→ 7,[d, g, g] �→ 12,[d, g, d] �→ 8,[d, d] �→ 4

}

La qualité d’arbre externe se traduit par le fait que si le couple [X] �→ v estprésent dans la fonction, alors, ni [X, g, . . .] �→ v1 ni [X, d, . . .] �→ v2 n’appartientà la fonction. Nous appliquons à présent la démarche de construction présentéeà la section 3.1.2.

1. Les notations 〈v〉 (arbre externe minimal, ne contenant qu’un seul nœud)et 〈l, r〉 (arbre externe construit à partir de deux arbres externes l et r) sedéfinissent par :

Not. Définition Condition

〈v〉 {[ ] �→ v} v ∈ T

〈l, r〉(λf ·(f ∈ dom(l) | [g | f ]))−1 ; l

∪(λf ·(f ∈ dom(r) | [d | f ]))−1 ; r

l ∈ liste({g, d}) �→ T ∧r ∈ liste({g, d}) �→ T

2. La fonction 〈〉(T ) construit un arbre externe à partir d’un élément v, lafonction 〈, 〉(T ) construit un arbre externe à partir de deux arbres externes.Elles se définissent par :

〈〉(T ) = λv ·(v ∈ T | 〈v〉)〈, 〉(T ) = λ(l, r) ·(l ∈ liste({g, d}) �→ T ∧ r ∈ liste({g, d}) �→ T | 〈l, r〉)

3. La fonction « pivot » f se définit alors par :

f(T ) = λ(y, z) ·

⎛⎝ y ∈ P(liste({g, d}) �→ T )∧

z ∈ P(liste({g, d}) �→ T )

∣∣∣∣∣∣{〈〉(T )[T ]}

∪〈, 〉(T )[y × z]

⎞⎠〈〉(T )[T ] (resp. 〈, 〉(T )[y, z]) est l’image par la fonction 〈〉(T ) (resp. 〈, 〉(T ))de T (resp. du produit cartésien y × z). Il s’agit bien d’une fonction deP(liste({g, d}) �→ T ) dans P(liste({g, d}) �→ T ). De plus (exercice 3.6.3)f(T )(y, z) est monotone en y × z.

4. Posons abe(T ) = fix(f(T )). Par définition nous avons alors :

abe(T ) = {〈〉(T )[T ]} ∪ 〈, 〉(T )[abe(T )× T × abe(T )]

5. De l’égalité précédente nous déduisons les deux propriétés suivantes :

Page 110: Structures de données et méthodes formelles ||

98 Structures de données et méthodes formelles

1) v ∈ T ⇒ 〈v〉 ∈ abe(T )2) l, r ∈ abe(T ) × abe(T ) ⇒ 〈l, r〉 ∈ abe(T )

6. Il est alors possible de décliner le principe d’induction sous la forme sui-vante :

∀v ·(v ∈ T ⇒ [a := 〈v〉]P )∧

∀(l, r) ·

⎛⎝⎛⎝ l ∈ abe(T )∧r ∈ abe(T )∧[a := l]P ∧ [a := r]P

⎞⎠ ⇒ [a := 〈l, r〉]P

⎞⎠⇒

∀a ·(a ∈ abe(T ) ⇒ P )

3.6.3 Opérations sur les arbres externes

Le prédicat hEq et les opérations rg, rd, rgd, rdg, r, w et h se définissentcomme pour les arbres binaires étiquetés. L’opération parcours, qui renvoie laliste des feuilles rencontrées dans un parcours gauche-droite, est définie dans letableau ci-dessous.

Notation Définition Condition

parcours(〈v〉) [v] v ∈ T

parcours(〈l, r〉) parcours(l) parcours(r) 〈l, r〉 ∈ abe(T )

3.6.4 Conclusion

Il est à présent temps de répondre à une question que le lecteur ne peut man-quer de se poser : « À quoi peut servir un arbre externe ? D’une part, en termesde place, la comparaison des formules 3.5.2 et 3.6.1 ci-dessus suggère que lesarbres externes ne sont pas concurrentiels face aux arbres totalement étiquetés,d’autre part, face à une racine non étiquetée, il semble impossible de prendreune décision sur le sous-arbre à prendre en considération puisqu’on ne disposepas d’information portant sur les sous-arbres. » La réponse se fonde sur le faitque le développement d’algorithmes tel que nous le préconisons s’effectue en gé-néral en plusieurs étapes. Sans chercher pour l’instant à entrer dans les détailsde la démarche, que nous abordons au chapitre 5, imaginons que les étiquettessoient des entiers naturels et que nous ayons affaire à un arbre externe de re-cherche (le parcours gauche-droite produit une liste triée). Comment s’assurerde la présence d’un élément v dans l’arbre en question ? Il n’existe certes pasd’information explicite au niveau d’un nœud interne pour prendre une décisionmais il est possible de supposer disponible la fonction maxAbe qui délivre leplus grand élément d’un arbre externe et, face à une racine, nous pouvons com-parer la valeur v à la valeur maximale du sous-arbre gauche, afin d’orienter larecherche soit vers ce sous-arbre si v est inférieur ou égal au résultat de l’appelde la fonction soit rechercher dans le sous-arbre droit dans le cas contraire. Dansune phase ultérieure du développement, il est possible de placer la valeur de lafonction dans les nœuds internes de l’arbre externe, à condition que la fonction

Page 111: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 99

maxAbe soit O(1)-décomposable (cf. page 188 pour une définition de cette no-tion). Le caractère O(1) garantit que, ce faisant, la complexité asymptotique del’opération n’est pas affectée par le raffinement. Ainsi, par exemple, partant del’arbre externe de recherche :

3 •

7 9

10

l’étape d’implantation va conduire à placer à chaque nœud interne la plus grandevaleur du sous-arbre gauche (elle existe toujours), ce qui nous conduit à l’arbresuivant :

3

3 9

7

7 9

10

Un exemple plus complet est présenté à la section 6.5, page 187. Quels avan-tages retire-t-on de l’utilisation des arbres externes par rapport à celle des arbrestotalement étiquetés ? Ils sont de deux ordres. Tout d’abord, dans certains cas(cf. section 10, page 377 sur les tableaux flexibles), il peut être plus facile d’impo-ser et de préserver certaines formes d’équilibre. Le second avantage se manifestelorsque la structure de données est localisée sur un support secondaire. Prenonsle cas des arbres de recherche totalement étiquetés pour lesquels à chaque clé estassociée une information volumineuse (des millions de caractères). L’opérationde recherche va exiger de transférer en mémoire quantité d’informations inutilespour la recherche proprement dite (seul le dernier accès est de ce point de vueprofitable). Avec des arbres externes, seule la valeur utile pour l’orientation dela recherche va être transférée en mémoire centrale (cf. exercice 3.6.4). C’est surce type de raisonnement que les B+-arbres sont préférés aux B-arbres dans lamise en œuvre d’index dans les bases de données. Les B-arbres sont étudiés auchapitre 6, le développement des B+-arbres (version « externe » des B-arbres) yest proposé à l’exercice 6.7.5.

Un autre avantage des arbres externes est qu’il est facile (tout au moinsdans une approche non fonctionnelle des structures de données) de relier lesfeuilles entre elles dans une liste doublement chaînée. Le couple (arbre externe,liste) constitue alors le support idéal pour une organisation de fichier appelée« séquentiel indexé »(cf. encadré page 238). Par contre, un arbre externe telque défini ci-dessus ne peut être vide. Cette limitation est pénalisante pour,par exemple, représenter des ensembles finis par des arbres externes. Elle estcependant facile à contourner, il suffit de définir une structure abev(T ) par {〈〉}∪abe(T ).

Page 112: Structures de données et méthodes formelles ||

100 Structures de données et méthodes formelles

Exercices

Exercice 3.6.1 Dénombrer les arbres non ordonnés, binaires, planaires ainsi que les arbresexternes de n nœuds, pour n donné, n ≥ 0.

Exercice 3.6.2 Fournir l’expression ensembliste représentant l’arbre externe (10) de la page 96.

Exercice 3.6.3 Montrer que la fonction f définie lors de la construction des arbres externesest une fonction monotone.

Exercice 3.6.4 Nous voulons comparer le coût, en terme de quantité d’informations transférée,entre une solution par arbres totalement étiquetés et une solution par arbres externes. Nousconsidérons que les hypothèses suivantes sont satisfaites :

1. Chaque unité d’information est identifiée par une clé de longueur 1, elle s’accompagned’une information associée, de longueur i (i >> 1).

2. Les arbres sont supposés avoir le rayon le plus petit possible.3. Dans le cas des arbres totalement étiquetés, chaque nœud s’accompagne d’une infor-

mation de longueur i + 1 (i pour l’information associée et 1 pour la clé, la place desinformations de structure – pointeurs – est négligée).

4. Dans le cas des arbres externes, aux nœuds internes est associée une information delongueur 1 (pour la clé) et aux feuilles est associée une information de longueur i + 1.La place des informations de structure est négligée.

5. (Hypothèse simplificatrice) Consulter un nœud exige de transférer toute l’informationlocalisée sur ce nœud.

Sachant qu’il y a 2r − 1 nœuds utiles, quel est le coût minimum (resp. maximum) du transfertdans chacun des cas ?

3.7 Sacs finis

3.7.1 Présentation informelleIntuitivement, un sac sur un ensemble T est une collection d’éléments de T

dans laquelle un élément donné peut apparaître plusieurs fois. Pour cette raison,cette notion est parfois appelée multiensemble. Pour ce qui concerne les struc-tures de données, ce concept est utile par exemple lorsque l’on cherche à réaliserune modélisation élémentaire des files de priorité (cf. chapitre 9). Chaque clientde la file se présente alors avec une priorité de service ; si l’on fait abstraction del’identité du client, la file de priorité apparaît en première approximation commeun sac dont les éléments sont les priorités des clients en attente. Dans la suitenous nous intéressons aux sacs finis. Les symboles homologues de [ et ] pour leslistes sont � et �. De même que pour les listes, nous adoptons deux notationspour représenter un sac : la notation récursive et la notation linéaire. Ainsi, lesac b1, défini en notation récursive par :

b1 = �1 | �1 | �2 | �3 | �3 | �3 | �4 | � ��������s’écrit �1, 1, 2, 3, 3, 3, 4� en notation linéaire. De la même façon, le sac b2 définien notation récursive par :

b2 = �2 | �2 | �3 | �3 | � �����

Page 113: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 101

s’écrit �2, 2, 3, 3� en notation linéaire. La notion de liste véhicule une idée d’ordre :[2, 2, 3] = [2, 3, 2] (les trois valeurs sont présentes mais dans un ordre différent),ce n’est pas le cas des sacs où �2, 2, 3� = �2, 3, 2� (les trois valeurs sont présentes).

3.7.2 Ébauche de constructionDans cette section nous étudions comment la notion de sac peut se construire

inductivement à partir de la théorie des ensembles (cf. section 3.1.2 pour laprésentation de la démarche de construction). Un sac sur T est une fonctionpartielle entre T et N1 telle que si v est présent dans le sac en n exemplaires(n > 0), alors le couple v �→ n appartient à la fonction. Le sac b1 ci-dessus sereprésente par la fonction suivante : {1 �→ 2, 2 �→ 1, 3 �→ 3, 4 �→ 1}.1. Les notations �� (sac vide) et �v | s� (sac résultant de l’ajout d’une occur-

rence de l’élément v au sac s) se définissent par :

Not. Définition Condition

�� ∅

�v | s� s�− {v �→ s(v) + 1} s ∈ T �→ N1 ∧v ∈ dom(s)

�v | s� s�− {v �→ 1} s ∈ T �→ N1 ∧v /∈ dom(s)

2. La fonction �|�(T ) qui construit un sac à partir d’un élément v de T etd’un sac s se définit par :

�|�(T ) = λ(v, s) ·(v ∈ T ∧ s ∈ T �→ N1 | �v | s�)

3. La fonction « pivot » f se définit alors par :

f(T ) = λz ·(z ∈ P(T �→ N1) | {��} ∪ �|�(T )[T × z])

�|�(T )[T × z] est l’image par la fonction �|�(T ) du produit cartésien T × z.Il s’agit bien d’une fonction monotone de P(T �→ N1) dans P(T �→ N1).

4. Posons sac(T ) = fix(f(T )). Par définition nous avons alors :

sac(T ) = {��} ∪ �|�(T )[T × sac(T )]

5. De l’égalité précédente nous déduisons les deux propriétés suivantes :

1) �� ∈ sac(T )2) v ∈ T ∧ s ∈ sac(T )⇒ �v | s� ∈ sac(T ))

6. Il est alors possible de décliner le principe d’induction sous la forme sui-vante :

[b := ��]P ∧∀b ·(b ∈ sac(T ) ∧ P ⇒ ∀v ·(v ∈ T ⇒ [b := �v | b�]P ))

⇒∀b ·(b ∈ sac(T ) ⇒ P )

Page 114: Structures de données et méthodes formelles ||

102 Structures de données et méthodes formelles

3.7.3 Opérations sur les sacs

Afin de marquer l’analogie entre ensembles et sacs, mais également afin deprévenir toute confusion, nous avons décidé d’adopter comme opérateurs sur lessacs, des notations s’inspirant de celles des ensembles mais dans une version « àangles droits ». Ainsi le sac vide se note �� 9 (resp. ∅ pour les ensembles), lesymbole d’appartenance �− (resp. ∈), le symbole d’union et d’intersection � et (resp. ∪ et ∩), les symboles d’inclusion � et ! (resp. ⊂ et ⊆), etc. Notonscependant que l’opérateur �, souvent appelé addition multiensembliste, n’a pasd’analogue parmi les opérateurs ensemblistes. Cet opérateur étant fréquemmentutilisé dans le reste de ce livre, nous reviendrons sur sa signification ci-dessous.

L’opérateur s1 � s2 délivre un sac dans lequel toutes les valeurs de s1ou de s2 sont présentes, avec leur plus grande occurrence. Ainsi b1 � b2 =�1, 1, 2, 2, 3, 3, 3, 4�. L’opérateur s1 s2 délivre un sac dans lequel les valeurscommunes à s1 et à s2 sont présentes, avec leur plus petite occurrence. Ainsib1 b2 = �2, 3, 3�.

L’opérateur d’addition multiensembliste s1 � s2 délivre un sac tel que pourchaque valeur e présente dans s1 en n1 (n1 ≥ 0) exemplaires et pour chaquevaleur présente dans s2 en n2 (n2 ≥ 0) exemplaires, e est présente dans lerésultat en n1 + n2 exemplaires. L’expression b1 � b2 délivre le sac �1, 1, 2, 2, 2,3, 3, 3, 3, 3, 4�.

L’opérateur s1 − s2 délivre la différence entre les sacs s1 et s2. Pour toutélément e présent dans s1 en n1 (n1 ≥ 0) et dans s2 en n2 (n2 ≥ 0), le ré-sultat contient e en max({0, n1 − n2}) exemplaires. L’expression b1 − b2 délivre�1, 1, 3, 4�.

La fonction mult(e, s) délivre la multiplicité de la valeur e dans le sac s,c’est-à-dire le nombre d’exemplaires de e présents dans s. Ainsi mult(3, b2) = 2.

La fonction bCard(s) délivre le nombre de valeurs présentes dans s. L’ex-pression bCard(s1) délivre 7. Le prédicat s1 � s2 (resp. s1 ! s2) est identique à� si et seulement si pour tout élément e tel que e�− s1, mult(e, s1) < mult(e, s2)(resp. mult(e, s1) ≤ mult(e, s2)). Ainsi b2 � b1 est identique à ⊥ tandis que�1, 1, 4� � b1 est identique à �. bRan est l’opérateur qui délivre le « codomainemultiensembliste » de la relation en argument. Ainsi, si l’argument r est la rela-tion {1 �→ 10, 2 �→ 20, 2 �→ 30, 3 �→ 10, 3 �→ 30, 4 �→ 10}, bRan(r) délivre le sac�10, 10, 10, 20, 30, 30�.

Le tableau suivant définit les opérations décrites ci-dessus :

Notation Définition Condition

v �− s v ∈ dom(s)

v ��− s ¬ v �− s

�v, b� �v�� �b� �b� ∈ sac(T )

9. �� et �� sont synonymes, de même que ∅ et {} pour les ensembles.

Page 115: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 103

��� s s

�v | m�� s �v | m� s�

s −�� s

s − �v | m� (s�− {v �→ s(v)− 1}) −m v �− s

s − �v | m� s −m v ��− s

�� s �v | q� s q (s − �v�) v �− s

�v | q� s ⊥ v ��− s

s � t s t ∧ s �= t

mult(v,��) 0

mult(v, �w | s�) 1 + mult(v, s) v = w

mult(v, �w | s�) mult(v, s) v �= w

bRan(f)

⎧⎪⎪⎨⎪⎪⎩v �→ n

∣∣∣∣∣∣∣∣v ∈ ran(f)∧n ∈ N1 ∧n = card(f � {v})

⎫⎪⎪⎬⎪⎪⎭ f ∈ S→ T

bCard(s)∑

i ·(i ∈ dom(s) | s(i))

s � t

⎧⎪⎪⎨⎪⎪⎩v �→ n

∣∣∣∣∣∣∣∣(v �− s ∨ v �− t)∧n ∈ N∧n = max({mult(v, s),mult(v, t)})

⎫⎪⎪⎬⎪⎪⎭

s � t

⎧⎪⎪⎨⎪⎪⎩v �→ n

∣∣∣∣∣∣∣∣(v �− s ∧ v �− t)∧n ∈ N∧n = min({mult(v, s),mult(v, t)})

⎫⎪⎪⎬⎪⎪⎭

Dans le tableau ci-dessus, S est un ensemble, v ∈ T , w ∈ T , s ∈ sac(T ),t ∈ sac(T ) et m ∈ sac(T ).

Dans le cas de sacs définis sur des relatifs (ou sur un sous-ensemble de rela-tifs), nous pouvons enrichir le jeu d’opérations par les opérations bMin et bMaxqui délivrent respectivement le plus petit et le plus grand élément du sac 10.

Notation Définition Condition

bMax(��) −∞bMax(�v | s�) max({v, bMax(s)}) �v | s� ∈ sac(Z)

bMin(��) ∞bMin(�v | s�) min({v, bMin(s)}) �v | s� ∈ sac(Z)

3.7.4 Propriétés des sacs

Le tableau 3.3, page suivante, propose un échantillon intéressant des proprié-tés des sacs. De nombreuses autres propriétés existent telle que (a � b) � c =

10. Pour des raisons de cohérence avec le choix réalisé pour les ensembles de relatifs, nousadmettons que bMax(��) = −∞ et que bMin(��) = +∞.

Page 116: Structures de données et méthodes formelles ||

104 Structures de données et méthodes formelles

a � (b � c). Nous laissons au lecteur le soin de les découvrir et de les démontrersi nécessaire.

Tableau 3.3 – Propriétés des sacs.Ce tableau présente quelques-unes des propriétés des opérations �, −,bRan, mult et bMin. Dans ce tableau les conditions suivantes s’ap-pliquent : a ∈ sac(T ), b ∈ sac(T ), c ∈ sac(T ), v ∈ T , r ∈ S ↔ T ,t ∈ S ↔ T , e ∈ Z↔ T , i ∈ Z, p ∈ sac(Z), q ∈ sac(Z).

Propriété Condition Ident.a� b = b� a (3.7.1)a��� = a (3.7.2)(a� b)� c = a� (b� c) (3.7.3)a − a = �� (3.7.4)(a� b) − c = a� (b − c) c ! b (3.7.5)�� − a = �� (3.7.6)a −�� = a (3.7.7)bRan(∅) = �� (3.7.8)bRan({x �→ y}) = �y� x ∈ S ∧ y ∈ T (3.7.9)bRan(r ∪ t) = bRan(r)� bRan(t) r ∩ t = ∅ (3.7.10)bRan(r − t) = bRan(r) − bRan(t) (3.7.11)bRan(e� i) = bRan(e) (3.7.12)mult(v, a� b) = mult(v, a) + mult(v, b) (3.7.13)mult(v, a − b) = mult(v, a)−mult(v, b) b ! a (3.7.14)bMin(p� q) = min({bMin(p), bMin(q)}) (3.7.15)

Exercice

Exercice 3.7.1 Démontrer les propriétés du tableau 3.3.

3.8 Conclusion et remarques bibliographiques

Ce chapitre nous a permis de définir des structures outils utiles à la secondepartie. Nous avons pour cela appliqué une démarche en cohérence avec les cha-pitres précédents, qui consiste à étendre la théorie des ensembles. Nous avons pualors définir des opérations sur ces structures et en déduire certaines propriétés.

Cette démarche est largement inspirée du chapitre 3 du B-Book [3] où lesjustifications théoriques sont développées.

Il existe d’autres solutions pour construire des structures de données. Citonspour mémoire l’approche purement axiomatique (cf. [44]), les types abstraits

Page 117: Structures de données et méthodes formelles ||

3. Étude de quelques structures outils 105

algébriques (cf. par exemple [46, 27, 40, 83]), les relations bien fondées sur unensemble [44, 83, 3, 9, 5], les termes [77, 9]. J.-F. Monin [83] offre une vue critiquede ces différentes méthodes.

Notons à ce propos que la méthode du point fixe, que nous avons pratiquéepour les structures inductives, et celle des termes, convergent vers le même ré-sultat qui, dans le premier cas, constitue une propriété caractéristique et dansle second une définition 11. Dans la seconde partie de l’ouvrage, nous sommes enpermanence amené à spécialiser les structures étudiées ci-dessus. Des soucis deconcision nous conduisent en général à court-circuiter la construction formelle.Tout se passe alors comme si nous utilisions directement la technique des termes.Cette façon de procéder n’a pas d’incidence négative sur les développements réa-lisés.

11. Rappelons toutefois que les définitions inductives comportent une clause de minimalitéqui stipule que l’ensemble visé est le plus petit ensemble satisfaisant les clauses de base etinductive. Dans la démarche ensembliste, cette clause complémentaire est prise en compte parla définition du plus petit point fixe.

Page 118: Structures de données et méthodes formelles ||

Chapitre 4

Analyse d’algorithmes

La classe des algorithmes qui satisfont une spécification donnée, si ellen’est pas vide, contient en général une infinité d’éléments. Mais alors sur quellebase peut-on comparer ces algorithmes deux à deux ? Quel(s) critère(s) est-ilpertinent d’utiliser dans la pratique ? Typiquement, on distingue des critèresstatiques (c’est-à-dire indépendants de l’exécution de l’algorithme) et des critèresdynamiques. Pour les premiers nous pouvons citer :

– le temps de développement d’une solution à partir de la spécification ;– la lisibilité du programme ;– sa maintenabilité ;– la qualité de son ergonomie ;– sa sécurité d’utilisation ;– sa longueur ;– etc.

Les quatre premiers points ne doivent pas être négligés, mais ils sont trop subjec-tifs (ils dépendent autant du programmeur et/ou du lecteur que de l’algorithmelui-même) pour permettre une comparaison impartiale. L’objectif de sécuritéest, du point de vue des outils qui permettent de l’évaluer, très lié à la notionde correction du programme par rapport à sa spécification, puisqu’il s’agit alorsde démontrer qu’une propriété (comme par exemple « le programme ne modifieque des fichiers locaux ») est satisfaite par le programme. Le dernier point, lalongueur, est à la base de la notion de complexité de Kolmogorov. Son étude sortdu cadre de cet ouvrage. Compte tenu de nos objectifs, nous penchons pour uncritère de nature dynamique portant soit sur la place mémoire utilisée pour uneexécution soit sur le temps d’exécution. Pour les algorithmes qui nous intéressent,la place mémoire est souvent une fonction linéaire de la taille des données. Il estplus intéressant de se focaliser sur le critère du temps d’exécution (la complexitétemporelle) 1. Plusieurs arguments supplémentaires militent en faveur du critèretemporel plutôt que du critère spatial : pour occuper de la place il faut consom-mer du temps (l’inverse n’est pas vrai) ; de plus, en supposant que l’exécutionse termine, la place occupée est libérée à l’issue de l’exécution et est à nouveau

1. Pour cette raison, dans la suite lorsque nous utilisons le terme complexité, il s’agit pardéfaut de complexité temporelle.

Page 119: Structures de données et méthodes formelles ||

108 Structures de données et méthodes formelles

disponible, le temps consommé est lui perdu à jamais. Le temps n’est pas uneressource recyclable. Par ailleurs, la complexité asymptotique établit une lignede partage consensuelle entre les solutions praticables et les autres. De ce fait lanotion de complexité temporelle constitue une base théorique permettant de ju-ger de la possibilité de mettre en œuvre (ou non) une solution dotée des qualitésrequises.

De même que pour les algorithmes, et pour les mêmes raisons, toutes les misesen œuvre d’un même type de données ne sont pas équivalentes. En outre, le casdes structures de données est plus délicat. S’il est souvent possible de comparer(asymptotiquement) la complexité de deux algorithmes, la comparaison est engénéral impossible 2 pour deux structures de données, puisqu’elle devrait portersur plusieurs opérations. L’idéal serait de concevoir une mise en œuvre qui soitla meilleure pour toutes les opérations. . .

Il existe cependant une particularité des structures de données qui a conduitles chercheurs (cf. en particulier [113]) à définir une forme originale d’analyse decomplexité : l’analyse amortie. Cette particularité est liée au fait que lors de lavie d’une structure de données, on est souvent amené à réaliser des séquencesd’appels à une opération et à constater que le coût important d’un appel parti-culier peut être amorti sur les appels voisins.

Ce chapitre se compose de trois sections. La première présente les outilstraditionnels de la comparaison d’algorithmes : les notations O, Ω et Θ. Laseconde s’intéresse à la complexité « classique ». Le contenu de ces deux sectionsest supposé familier au lecteur, il n’est présenté que pour mémoire. Les références[40, 103, 9, 43] peuvent être consultées avec profit pour un approfondissement.La troisième section est une introduction à l’analyse amortie par la méthode laplus pratiquée, celle du potentiel. Bien que datant de la fin des années 1970, elleest par nature principalement réservée au domaine des structures de données etdonc moins largement diffusée que la complexité classique. Elle est appliquée àde nombreuses reprises dans le reste de l’ouvrage.

4.1 Notations asymptotiques

Dans la suite de ce chapitre nous nous intéressons aux fonctions de profilN→R+. Ce choix est justifié par le fait que la complexité d’un algorithme est unefonction à valeurs réelles non négatives définie sur une grandeur scalaire discrète,typiquement la taille de la « donnée ». Le caractère total de ces fonctions tientau fait qu’en général toutes les tailles sont significatives.

Remarque. Il existe des situations pour lesquelles réduire le domaine auxseuls entiers naturels est contraignant et trompeur. C’est par exemple le cas sila donnée est une relation : le cardinal de l’ensemble source, celui de l’ensembledestination et celui de l’ensemble des couples de la relation sont fortement in-dépendants. Ce type de situation exige en général une analyse séparée de lacomplexité pour chacun de ces paramètres. Il peut cependant être parfois traitépar des fonctions dont le domaine de définition est composite. Les notations et

2. Sauf à définir une structure d’ordre sur les opérations. . .

Page 120: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 109

propriétés présentées ci-dessous s’étendent facilement au cas de plusieurs para-mètres.

Considérons le problème du tri d’un tableau sans doublon. Ce problème estspécifié informellement de la manière suivante : « la fonction tri(t) délivre untableau représentant la permutation triée par ordre croissant des valeurs de t. »Supposons que nous cherchions à comparer la complexité de deux fonctions déter-ministes tri1(t) et tri2(t) qui satisfont cette spécification. Supposons par ailleursque la 3 complexité de la fonction tri1 (resp. tri2) soit donnée par la fonctionf1(n) (resp. f2(n)), n étant la taille de t. Du point de vue de la complexité,il serait intéressant de pouvoir comparer tri1 et tri2 à travers la situation re-lative de f1 et f2, et affirmer par exemple « tri1 est toujours au moins aussiperformante que tri2 » (qui traduit l’affirmation « la courbe de f1 n’est jamaisau-dessus de celle de f2 »). C’est ce que permettraient les fonctions f1 et f2 dela partie (11) de la figure 4.1 ci-dessous. Cependant il est rare que les fonctionsainsi comparées autorisent des affirmations aussi précises. Les courbes peuventse croiser indéfiniment. Une situation plus intéressante est celle où à partir d’unecertaine abscisse l’une des courbes passe au niveau ou au-dessus de l’autre. C’estl’hypothèse qui est retenue pour la partie (12) de la figure 4.1, où la courbe def2 passe définitivement au-dessus de la courbe f1 après l’abscisse n0.

n

f(n)

(11) f1

f2

n

f(n) f2f1

n0

(12)

Figure 4.1 – Comparaison de fonctions.La partie (11) montre deux fonctions qui sont comparables sur la totalitéde leur domaine de définition. Ce n’est pas le cas pour les fonctions dela partie (12) mais, à partir d’un certain rang n0, la courbe f1 vient« définitivement » sous la courbe f2.

Révisons nos ambitions en nous limitant à des affirmations du type « f1 esttoujours au moins aussi performante que f2, sauf pour un nombre fini de cas. »Cette fois nous sommes à même de comparer les deux fonctions de la partie (12)de la figure 4.1 : à partir de n0, f1 est toujours au moins aussi performante quef2. Les seuls cas qui ne satisfont pas cette affirmation sont ceux qui précèdentn0 ; compte tenu du domaine de définition (N), ils sont en nombre fini.

Cette notion se formalise facilement. Si l’on nomme # (f) l’ensemble desfonctions inférieures ou égales à f à partir d’une certaine abscisse, alors

#(f) = {t | t ∈ N→ R+ ∧ ∃n0 ·(n0 ∈ N ∧ ∀n ·(n ∈ N ∧ n ≥ n0 ⇒ t(n) ≤ f(n)))}

3. L’usage de l’article la est abusif dans la mesure où il existe en général plusieurs types decomplexité (complexité au pire, moyenne, etc.). Ces notions sont précisées à la section suivante.Nous acceptons momentanément cet abus de langage.

Page 121: Structures de données et méthodes formelles ||

110 Structures de données et méthodes formelles

Notons que la valeur n0 dépend en général de t. Munis de cette définition noussommes capable de démontrer des propositions telles que :1. n2 ∈#(2n + 2 · n)2. 20 · n2 ∈#(3 · n3 + 2 · n+ 1)3. 20 · n2 ∈#(20 · n2 + 50 · n+ 5)4. 20 · n2 /∈#(19 · n2)5. n2 /∈#(200 · n)La relation induite par la notation # est un préordre partiel (elle est réflexive

et transitive). Cette notion est le plus souvent considérée comme trop contrai-gnante : si la proposition 5 ci-dessus est légitime, la proposition 4 est discutable.On aimerait pouvoir affirmer que, pour tout réel c positif, f(n) ∈#(c · f(n)). Cequi revient à négliger les constantes de proportionnalité. Cette notion est captéepar la notation O :

Définition 1 (Notation O). Soit f ∈ N→ R+.

O(f) ={t

∣∣∣∣t ∈ N→ R+ ∧ ∃(c, n0) ·(

c, n0 ∈ R∗+ × N ∧∀n ·(n ∈ N ∧ n ≥ n0 ⇒ t(n) ≤ c ·f(n))

)}Cette notation induit également un préordre partiel sur l’ensemble des fonc-tions considérées. Elle est illustrée à la figure 4.2 qui montre le rôle que joue laconstante multiplicative c.

n

f(n)

f

c · ft

n0

Figure 4.2 – Comparaison de fonctions – Notation O.La fonction t est en O(f) puisqu’il existe une constante positive c etun entier naturel n0 tels qu’à partir de l’abscisse n0 la courbe de t n’estjamais au-dessus de celle de c · f.

Si f ∈ O(g) on écrit que « f est en O(g) », que « f est dominé asymptoti-quement par g », que « g est supérieur asymptotiquement à f » ou encore, parabus de langage, que f = O(g). Cette fois il est possible de montrer que :1. n2 ∈ O(2n + 2 · n)2. 20 · n2 ∈ O(3 · n3 + 2 · n+ 1)3. 20 · n2 ∈ O(20 · n2 + 50 · n+ 5)4. 20 · n2 ∈ O(19 · n2)5. n2 /∈ O(200 · n)Le tableau 4.1, page ci-contre, répertorie quelques-unes des propriétés de la

notation O en rappelant en particulier les propriétés de réflexivité et de transiti-vité. Toutes ces propriétés peuvent être utilisées pour faciliter les démonstrations.

Page 122: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 111

Tableau 4.1 – Quelques propriétés de la notation O.

Propriété Condition Ident.

na ∈ O(nb) n ∈ N ∧ a ∈ R+ ∧ b ∈ R+ ∧ a ≤ b (4.1.1)f ∈ O(f) f ∈ N→ R+ (4.1.2)

f ∈ O(h) f ∈ N→ R+ ∧ g ∈ N→ R+ ∧ h ∈ N→ R+ ∧f ∈ O(g) ∧ g ∈ O(h)

(4.1.3)

f1 + f2 ∈O(max({g1, g2}))

f1 ∈ N→ R+ ∧ f2 ∈ N→ R+ ∧g1 ∈ N→ R+ ∧ g2 ∈ N→ R+ ∧f1 ∈ O(g1) ∧ f2 ∈ O(g2)

(4.1.4)

f1 · f2 ∈O(g1 · g2)

f1 ∈ N→ R+ ∧ f2 ∈ N→ R+ ∧g1 ∈ N→ R+ ∧ g2 ∈ N→ R+ ∧f1 ∈ O(g1) ∧ f2 ∈ O(g2)

(4.1.5)

f ∈ O(g) f ∈ N→ R+ ∧ g ∈ N→ R+ ∧∧ limn→∞

f(n)g(n) = 0

(4.1.6)

f ∈ O(g)∧g ∈ O(f)

f ∈ N→ R+ ∧ g ∈ N→ R+ ∧∃c ·(c ∈ R∗+ ∧ limn→∞

f(n)g(n) = c)

(4.1.7)

Il existe une notation duale de O, la notation Ω, qui est à O ce que l’opérateur≥ est à ≤ . Si g ∈ Ω(f), il existe une constante réelle positive c et une constanteentière n0 telles qu’à droite de n0 la courbe f(n) est toujours sur ou au-dessusde f(n). Formellement, la définition de Ω est donnée par :

Définition 2 (Notation Ω). Soit f ∈ N→ R+.

Ω(f) =

{t

∣∣∣∣t ∈ N→ R+ ∧ ∃(c, n0) ·(

c, n0 ∈ R∗+ × N ∧∀n ·(n ∈ N ∧ n ≥ n0 ⇒ t(n) ≥ c ·f(n))

)}Ici aussi les formulations g = Ω(f) ou « g est en Ω(f) » sont admises. L’intérêtmajeur de cette notation est qu’elle permet de définir la notation Θ. Θ joueschématiquement le rôle de l’égalité asymptotique, elle se définit par :

Définition 3 (Notation Θ). Soit f ∈ N→ R+ et g ∈ N→ R+.

f ∈ Θ(g) = f ∈ O(g) ∧ f ∈ Ω(g)

Les formulations g = Θ(f), « g est en Θ(f) » ou encore « g est équivalent (oucomparable) asymptotiquement à f » sont permises. La relation induite par Θest un ordre partiel. Il est possible de démontrer que :1. n2 /∈ Θ(2n + 2 · n)2. 20 · n2 /∈ Θ(3 · n3 + 2 · n+ 1)3. 20 · n2 ∈ Θ(20 · n2 + 50 · n+ 5)4. 20 · n2 ∈ Θ(19 · n2)

Page 123: Structures de données et méthodes formelles ||

112 Structures de données et méthodes formelles

5. n2 /∈ Θ(200 · n)Le tableau 4.2 ci-dessous fournit quelques-unes des propriétés de la notation Θ.

Tableau 4.2 – Quelques propriétés de la notation Θ.

Propriété Condition Ident.

f ∈ Θ(f) f ∈ N→ R+ (4.1.8)

f ∈ Θ(g)f ∈ N→ R+ ∧ g ∈ N→ R+ ∧f ∈ O(g) ∧ g ∈ O(f)

(4.1.9)

f ∈ Θ(h)f ∈ N→ R+ ∧ g ∈ N→ R+ ∧h ∈ N→ R+ ∧ f ∈ Θ(g) ∧ g ∈ Θ(h)

(4.1.10)

f1 + f2 ∈Θ(max({g1, g2}))

f1 ∈ N→ R+ ∧ f2 ∈ N→ R+ ∧g1 ∈ N→ R+ ∧ g2 ∈ N→ R+ ∧f1 ∈ Θ(g1) ∧ f2 ∈ Θ(g2)

(4.1.11)

f1 · f2 ∈Θ(g1 · g2)

f1 ∈ N→ R+ ∧ f2 ∈ N→ R+ ∧g1 ∈ N→ R+ ∧ g2 ∈ N→ R+ ∧f1 ∈ Θ(g1) ∧ f2 ∈ Θ(g2)

(4.1.12)

f ∈ Θ(g)f ∈ N→ R+ ∧ g ∈ N→ R+ ∧∃c ·(c ∈ R∗+ ∧ limn→∞

f(n)g(n) = c)

(4.1.13)

f /∈ Θ(g) f ∈ N→ R+ ∧ g ∈ N→ R+ ∧∧ limn→∞

f(n)g(n) = 0

(4.1.14)

f /∈ Θ(g) f ∈ N→ R+ ∧ g ∈ N→ R+ ∧∧ limn→∞

f(n)g(n) =∞

(4.1.15)

Remarques.1. Les notations O et Θ sont utilisées dans le contexte de l’évaluation des

algorithmes notamment pour comparer asymptotiquement deux fonctionsentre elles. Les mathématiques offrent un autre usage (qui justifie les abusde langage f = O ou f = Ω(g)) lié à la majoration des erreurs faitesen assimilant une fonction à une autre. Ainsi écrire 20 · n2 + 50 · n + 5 =20 · n2+O(n) se lit de la manière suivante : la fonction 20 · n2+50 · n+5est égale à la fonction 20 · n2+ f(n) où f(n) est une fonction indéterminéedont on sait simplement que f(n) = O(n). L’utilisation de la notation =présente des risques d’erreurs dans certains calculs.

2. La comparaison de fonctions de complexité se fait en général en écrivantf(n) ∈ O(g(n)) où f(n) est la fonction de complexité en question et oùg(n) est une fonction la plus simple possible, prise autant que faire sepeut dans l’échelle de complexité croissante suivante : 1, log n, n, n · log n,n2, n3, . . . , 2n, 3n . . . , n!, nn. Les fonctions ni sont dites polynomiales

Page 124: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 113

et constituent la limite au-delà de laquelle les solutions algorithmiques nesont pas praticables.

Exercices

Exercice 4.1.1 Soit f ∈ N→ R+ et g ∈ N→ R+ deux fonctions quelconques. Est-il toujourspossible de démontrer soit que f ∈ O(g) soit que g ∈ O(f) ? Qu’en est-il si l’on remplace Opar Θ ?

Exercice 4.1.2 Sachant que pour x ∈ R∗+, x + 1 = x ·(1 + 1

x), montrer que log(x + 1) ∈

O(log(x)).

Exercice 4.1.3 Soit f ∈ N→ R+.1. Est-il toujours possible de trouver une fonction g telle que f ∈ O(g) ? Et f ∈ Θ(g) ?2. Est-il toujours possible de trouver une fonction g de la « liste étalon » 1, logn, n,

n · logn, n2, n3, . . . , 2n, 3n . . . , n!, nn telle que f ∈ O(g) ? Et f ∈ Θ(g) ?

Exercice 4.1.4 Soit f ∈ N→ R+ une fonction définie par :

f(n) =

{nn si n est premiern si n n’est pas premier

Proposer des fonctions g et h différentes de f telles que f ∈ O(g) et f ∈ Θ(h). Démontrervotre affirmation.

Exercice 4.1.5 Certains auteurs (cf. par exemple [7]) utilisent la définition suivante de lanotation Ω : Ω(f) est l’ensemble des fonctions t telles qu’il existe une constante positive c pourlaquelle t(n) ≥ c · f(n), ceci pour une infinité de valeurs de n.

– Formaliser la définition de cette notation.– Discuter de ses avantages et inconvénients.

4.2 Analyse classique de la complexitéde fonctions

À la section précédente, nous nous sommes préoccupé de donner un sensprécis aux notions de comportement et de comparaison asymptotiques de (cer-taines classes de) fonctions. Nous avons pour l’instant fait abstraction de lanature réelle de la grandeur mesurée en supposant simplement qu’elle est liée autemps d’exécution du programme. Il nous faut à présent préciser cet aspect avantd’aborder la question de fond de cette section : l’évaluation du comportementasymptotique d’un programme.

Deux types d’approche sont étudiés. Le premier consiste tout d’abord à pas-ser de l’algorithme (exprimé par une fonction) à l’équation récurrente dont lasolution fournit une mesure de la complexité, à résoudre ensuite l’équation ré-currente et enfin à en déduire son comportement asymptotique. Le second typed’approche exploite le fait que nous ne sommes pas à la recherche d’une solu-tion exacte pour l’équation récurrente afin de contourner, ou de simplifier, cetteétape.

Page 125: Structures de données et méthodes formelles ||

114 Structures de données et méthodes formelles

4.2.1 Passage du texte d’une fonction à une équationrécurrente

Lorsque nous affirmons que la complexité d’un algorithme traitant une don-née de taille n est fournie par la fonction T (n) telle que T (n) ∈ N→R+, quellegrandeur est ainsi mesurée ? Le temps processeur ? Ce choix est peu judicieuxcar trop lié à l’état de la technologie. Le nombre d’instructions exécutées ? Cechoix est plus pertinent mais, sauf à se baser sur un « ordinateur étalon », il estaussi sujet à caution (instructions machines ? instructions d’un langage de hautniveau ?, etc.). L’ordinateur étalon évoqué ci-dessus pourrait être une machinede Turing (cf. par exemple [117]) mais sa nature séquentielle conduit à un ré-sultat pessimiste par rapport aux machines dotées de mémoires à accès direct(machines ram) que nous utilisons au quotidien 4. Par ailleurs, cette solution exi-gerait de traduire le programme obtenu en un programme pour une machine deTuring à cette seule fin. . . Le contexte fonctionnel dans lequel nous nous plaçonsdans cet ouvrage nous offre une solution simple : nous dénombrons le nombre degardes évaluées par l’appel initial. Une autre méthode, qui fournit en général unrésultat asymptotique équivalent, consiste à dénombrer les appels à la fonction.Prenons l’exemple de la fonction estTrie(n, t) qui délivre true si et seulementsi le tableau t, de longueur n, est trié par ordre croissant 5 :

function estTrie(n, t) ∈ N1 × (1 .. n→ N)→ bool =if n = 1 →

true

| n > 1 →bool(t(n) ≥ t(n− 1)) ∧ estTrie(n− 1, t)

fi

À la section 1.11, nous avons étudié l’évaluation d’une fonction comportantune conditionnelle et la sémantique des conditionnelles. Pour ce qui concernel’analyse de complexité, de façon à ne pas introduire de biais dans les résultats,nous faisons l’hypothèse d’une implantation déterministe : nous supposons quel’évaluation des gardes est séquentielle.

Revenons à présent sur la recherche de la fonction de complexité pour lafonction estTrie. Si le tableau est réduit à un seul élément, seule la premièregarde (n = 1) est évaluée. Dans le cas contraire, il faut ajouter à la garde évaluéedirectement toutes les gardes évaluées lors de l’appel récursif. Si T (n) représentele nombre de gardes évaluées, pour n ≥ 1, T (n) satisfait l’équation récurrentesuivante :{

T (1) = 1T (n) = T (n− 1) + 1 Pour n > 1

(4.2.1)

Dans l’éventualité où une garde comptabilisée comporte un appel à une ou plu-sieurs fonctions, il faut tenir compte des gardes qui sont ainsi évaluées indirec-tement.

4. Un théorème montre que pour tout programme ram en O(f(n)) il existe une machinede Turing équivalente, à 7 rubans, pour laquelle la complexité est en O(f3(n)).

5. Par abus de langage, et exceptionnellement, nous considérons ici et dans la fonctionestTrie′ que ∧ est un opérateur booléen et non un opérateur de la logique propositionnelle.

Page 126: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 115

Des situations plus complexes peuvent survenir comme par exemple le cas defonctions mutuellement récursives : f se définit à partir de g qui elle-même sedéfinit à partir de f . Le principe de détermination de l’équation récurrente restele même. La seule différence étant que l’on travaille sur un vecteur d’équationset non plus sur une équation unique.

De par sa fréquence dans les algorithmes liés aux arbres binaires, un casparticulier mérite que l’on s’y arrête. Il s’agit de la récurrence appelée récurrencede partition, dans laquelle le membre droit de la partie inductive de l’équations’exprime sur une taille des données qui est une fraction de la taille initiale.Considérons le même problème que ci-dessus (déterminer si un tableau est trié)mais en supposant (i) que le tableau est défini sur l’intervalle i .. s, (ii) qu’ilpossède un nombre d’éléments qui est une puissance de 2 (s− i+ 1 = 2k).

function estTrie′(i, s, t) ∈ N× N× (i .. s→ N) �→ bool =pre

∃k ·(k ∈ N ∧ s− i+ 1 = 2k)then

if s− i = 0 →true

| s− i > 0 →let m := (s+ i)÷ 2 inbool(t(m) ≤ t(m+ 1)) ∧ estTrie′(i,m, t) ∧ estTrie′(m+ 1, s, t)

endfi

end

Si n est la longueur du tableau traité par la fonction estTrie′ et T (n) lenombre de gardes évaluées, dans le cas où n = 1, la valeur recherchée est 1.Par contre si n est plus grand que 1 (compte tenu de la précondition n estune puissance de 2) le résultat est 1 plus deux fois T (n ÷ 2). D’où l’équationrécurrente suivante :{

T (1) = 1T (n) = 2 · T (n÷ 2) + 1 pour n > 1 et n puissance de 2 (4.2.2)

Reste à résoudre cette équation. . .Le contexte fonctionnel dans lequel nous nous situons introduit, du point de

vue de l’analyse de la complexité, un écueil dont il faut être conscient. Nousallons l’illustrer à travers la fonction m(v, p, t) qui délivre un tableau identiqueau tableau t à l’exception de la position p qui contient v :

function m(v, p, t) ∈ N× 1 .. 10000× (1 .. 10000→ N)→ (1 .. 10000→ N) =t�− {p �→ v}

Le schéma de calcul de complexité préconisé ci-dessus nous conduit à affirmerabusivement que la fonction de complexité pour cette fonction est T (m) = 1puisqu’on ne dénombre qu’un seul appel à la fonction. Pourtant, si l’on y re-garde plus près, le résultat délivré est un tableau qu’il faut construire en copiant

Page 127: Structures de données et méthodes formelles ||

116 Structures de données et méthodes formelles

9 999 des éléments de t ! Difficile de ne pas tenir compte du coût de cette cons-truction ! C’est pour cette raison que parfois les tableaux ne sont pas considéréscomme des structures « fonctionnelles ». Nous n’adhérons pas à cette limitationpour deux raisons. La première est qu’exclure les tableaux de notre éventail destructures de base nous conduirait à écarter de notre étude des structures dedonnées importantes comme les techniques de hachage ou les B-arbres. La se-conde raison est que la suite (cf. chapitre 10) nous montre qu’il est possible dedéfinir et de mettre en œuvre efficacement des structures fonctionnelles qui secomportent comme des tableaux. Dans le reste de l’ouvrage, la complexité in-duite par l’utilisation de tableaux n’est pas prise en compte. Nous invitons lelecteur à réfléchir à ce problème à chaque fois qu’il est rencontré.

4.2.2 Complexité la meilleure, la pire, moyenne

Le lecteur attentif n’a pas manqué de remarquer que l’efficacité de la fonctionestTrie peut être améliorée. En effet, compte tenu de la définition de l’opérateur∧, il est parfois inutile d’évaluer l’appel récursif pour décider du résultat. Cetteremarque se traduit dans le code par l’introduction d’une conditionnelle qui, sinous sommes dans la situation t(n) < t(n−1), conclut directement que le tableaun’est pas trié et, dans le cas contraire, assimile le résultat à celui obtenu sur lapartie du tableau limitée au domaine 1 .. n− 1. Soit estTrie′′ cette fonction :

function estTrie′′(n, t) ∈ N1 × (1 .. n→ N)→ bool =if n = 1 →

true

| n > 1 →if t(n) < t(n− 1) →

false

| t(n) ≥ t(n− 1) →estTrie′′(n− 1, t)

fifi

Dans ce type de situation, il est courant de distinguer trois sortes de com-plexité selon la configuration de l’argument t pour une taille donnée n : la com-plexité la meilleure, la complexité la pire et la complexité moyenne. Les deuxpremières se définissent facilement. La complexité la meilleure est obtenue parune configuration des données qui minimise le coût. Dans notre exemple il estclair que, pour une taille n donnée (n = 1), la complexité la meilleure est obtenueavec un tableau tel que t(n) < t(n − 1). Formellement, pour une fonction f deprofil f(a) ∈ d �→ c, la complexité la meilleure pour un argument de taille n sedéfinit par :

T min(n) = min({T f(a)(n) | a ∈ dom(f) ∧ card(a) = n})

La complexité la meilleure d’une fonction f(a) pour une donnée de taille n estdonc le plus petit coût trouvé lorsque l’argument parcourt le domaine de lafonction. Ainsi, pour la fonction estTrie′′, nous avons trivialement T min(n) = 1

Page 128: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 117

et ceci pour tous les tableaux dont les deux dernières valeurs sont dans un ordredécroissant.

De même la complexité la pire est définie par :

T max(n) = max({T f(a)(n) | a ∈ dom(f) ∧ card(a) = n})

Dans le cas de la fonction estTrie′′, ce coût le pire est obtenu pour un tableaut trié. L’équation récurrente obtenue est :{

T max(1) = 1T max(n) = T max(n− 1) + 1 pour n > 1

La complexité moyenne se définit en sommant les coûts obtenus pour toutesles configurations possibles et en divisant par le nombre de configurations consi-dérées (à condition que celui-ci soit positif), soit :

T moy(n) =

∑a ·(a ∈ dom(f(a)) ∧ card(a) = n | T f(a)(n))

card({d | d ∈ dom(f(a)) ∧ card(d) = n})

Le calcul de la complexité moyenne sort en général du cadre de cet ouvrage.La définition de T moy(n) revient à considérer que toutes les configurations sontéquiprobables. Il est possible de l’affiner en adoptant un modèle probabiliste. Àla difficulté technique du calcul vient alors s’ajouter celle du choix d’un modèleprobabiliste approprié. Pour ces raisons, dans la suite, nous nous limitons en gé-néral à l’étude de la complexité la pire et nous n’abordons la complexité moyenneéquiprobabiliste que dans les cas simples (cf. section 6.3.4 pour un exemple).

4.2.3 Résolution d’équations récurrentes

Dans ce chapitre nous avons, dans une première section, étudié la notionde comportement asymptotique de (certaines classes de) fonctions, puis, danscette seconde section, nous avons vu comment il est possible d’interpréter letexte d’une fonction afin d’obtenir une équation récurrente destinée à rendrecompte de la complexité temporelle de l’algorithme codé par la fonction. Nousavons ensuite précisé différents types de complexité selon la configuration desdonnées. Il nous reste une étape à franchir qui va nous permettre de déterminerla complexité asymptotique d’un algorithme fonctionnel ; c’est celle qui, à partird’une équation récurrente, fournit la forme close équivalente. Il s’agit d’un sujetdifficile dont l’intérêt pratique dépasse largement l’analyse de complexité 6 etpour l’étude duquel de nombreux ouvrages existent (cf. [40, 103, 9, 43, 25] parexemple pour les ouvrages les plus orientés vers l’informatique). En conséquence,notre objectif se limite ici à rappeler quelques méthodes simples et à fournir despistes pour un approfondissement.

Considérons tout d’abord l’équation récurrente 4.2.1, page 114. Abandonnonscette notation pour la notation plus rigoureuse suivante :

6. Les équations récurrentes sont utilisées dans la plupart des sciences. Elles servent enparticulier de modèles approchés lorsque les modèles continus basés sur des équations différen-tielles, intégrales ou aux dérivées partielles n’ont pas de solutions connues.

Page 129: Structures de données et méthodes formelles ||

118 Structures de données et méthodes formelles

(T (1) = 1) ∧ ∀m ·(m ∈ N1 ∧m > 1⇒T (m) = T (m− 1) + 1) (4.2.3)

Une première façon, naïve, de résoudre cette équation consiste à appliquerla méthode dite de la somme. Réécrivons la formule à tous les ordres comprisentre 1 et n. Les termes T (i), pour i ∈ 1 .. n− 1, s’annulent alternativement etle résultat est immédiat :

T (n) = T (n− 1) + 1+

T (n− 1) = T (n− 2) + 1+

...+

T (2) = T (1) + 1+

T (1) = 1T (n) = n

En toute rigueur, puisque ce résultat a plus été deviné que démontré, nous de-vons réaliser une démonstration (par récurrence). Bien qu’à l’avenir nous feronsconfiance aux résultats obtenus par sommation (ou plus généralement par la mé-thode des facteurs sommants utilisée ci-dessous), nous allons cette fois mettre enpratique le théorème 1 pour effectuer cette démonstration. Cette démonstrationpeut être sautée en première lecture.

Soit Q la formule 4.2.3. Posons P (n) = (T (n) = n). Nous devons montrerque Q⇒P (n). Nous pouvons déplacer Q en hypothèse pour nous focaliser sur ladémonstration de P (n). D’après le théorème 1, page 44, nous devons démontrer :(i) la base [n := 1]P (n), (ii) la partie inductive [n := n + 1]P (n) sous leshypothèses Q, P (n) et n ∈ N1. Débutons par la preuve de la base.

[n := 1]P (n)⇔ Définition de P (n) et substitution

T (1) = 1⇔ Hypothèses1 = 1

⇔ Arithmétique�

Montrons à présent [n := n + 1]P (n) sous les hypothèses Q, P (n) et n ∈ N1.Au préalable, nous constatons que de l’hypothèse Q nous pouvons déduire [m :=n+1](m ∈ N1∧m > 1⇒T (m) = T (m−1)+1), soit encore (n+1 ∈ N1∧n+1 >1⇒T (n+1) = T (n) + 1), formule qui peut être ajoutée aux autres hypothèses.

[n := n+ 1]P (n)⇔ Définition de P

T (n+ 1) = T (n) + 1⇔ Hypothèse T (n+ 1) = T (n) + 1

Page 130: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 119

Ce qui achève la démonstration. Une autre solution pour résoudre l’équationrécurrente consiste à effectuer une somme partielle sur l’intervalle n− i .. n, pouri ∈ 0 .. n− 1 :

T (n) = T (n− 1) + 1+

T (n− 1) = T (n− 2) + 1+

...+

T (n− i+ 1) = T (n− i) + 1T (n) = T (n− i) + i

D’où, pour i = n − 1, T (n) = n. La preuve formelle de ce résultat peut sefaire par récurrence, comme ci-dessus. Il est également possible de prouver (parrécurrence) le résultat intermédiaire :

∀i ·(i ∈ 0 .. n− 1⇒T (n− i+ 1) = T (n− i) + 1)

(cf. exercice 4.2.2) avant d’effectuer la substitution i := n− 1 :

[i := n− 1](i ∈ 0 .. n− 1⇒T (n− i+ 1) = T (n− i) + 1)⇔ Calculs non développés

T (n) = n

L’équation récurrente que nous venons de résoudre de plusieurs façons estun exemple (très) simple d’une classe d’équations récurrentes – les équationslinéaires à coefficients constants – pour lesquelles il existe des méthodes plusgénérales, en particulier la méthode de l’équation caractéristique et la méthodedes séries génératrices. Les références [80, 40, 9, 25] peuvent être consultées pourde plus amples développements.

Considérons à présent l’équation récurrente 4.2.2, page 115, obtenue pour lafonction estTrie′. Elle se caractérise par le fait que le membre droit s’exprime àpartir d’une expression multiplicative de l’argument, le facteur multiplicatif estici 1

2 (et non plus comme dans les équations linéaires à partir d’une expressionadditive de l’argument). Nous allons la résoudre en procédant au changement devariable n = 2m et en posant T ′(m) = T (2m). L’équation 4.2.2 devient :{

T ′(0) = 1T ′(m) = 2 · T ′(m− 1) + 1 Pour m > 0

La méthode de sommation précédemment utilisée ne peut s’appliquer puisqu’enraison du facteur 2, les termes en T ′ ne s’annulent pas en alternance. Nous allonsemployer la méthode des facteurs sommants qui consiste à multiplier chaqueéquation par une puissance de 2 appropriée afin d’être à même d’appliquer cettefois la méthode de sommation :

Page 131: Structures de données et méthodes formelles ||

120 Structures de données et méthodes formelles

20 · T ′(m) = 20 ·(2 · T ′(m− 1) + 1)+

21 · T ′(m− 1) = 21 ·(2 · T ′(m− 2) + 1)+

...+

2m · T ′(0) = 2m · 1

En sommant, nous obtenons T ′(m) = Σj∈0..m2j . Soit encore T ′(m) = 2 · 2m−1.En effectuant le changement de variable réciproque, nous obtenons au final :

T (n) = 2 · n− 1

Gardons cependant à l’esprit le fait que nous avons résolu l’équation 4.2.2 uni-quement pour des puissances de 2.

4.2.4 Contourner ou simplifier certaines étapesintermédiaires

La section précédente nous a fourni quelques éléments pour résoudre uneéquation récurrente de manière exacte. Il ne faut cependant pas perdre de vueque notre objectif est moins ambitieux : il s’agit de déterminer un ordre degrandeur des fonctions qui définissent la complexité temporelle d’un algorithme.La solution exacte de l’équation récurrente nous importe peu. En particulier, sinous ne sommes intéressés que par un résultat en O, il est possible soit de majorerla fonction recherchée soit d’utiliser des théorèmes qui pour certaines formesgénériques d’équations récurrentes fournissent directement le résultat sans avoirà passer par le calcul exact de la solution de l’équation. C’est ce que nous nousefforçons de montrer dans cette section en nous penchant tout d’abord sur lacomplexité de la fonction estTrie′ dans le cas où n est quelconque et non plusune puissance de 2. Ensuite, nous étudierons, sans la démontrer, une formesimplifiée du théorème dit « théorème maître » avant de l’appliquer au cas de lafonction estTrie′. Une troisième solution est évoquée ci-dessous. Elle consiste àse fonder sur la structure de données plutôt que sur l’algorithme.

Rechercher une fonction majorante

L’équation récurrente 4.2.2, page 115, qui décrit la complexité de la fonctionestTrie′ lorsque n est une puissance de 2 n’est pas correcte pour un n quel-conque. En effet, lorsque n est impair, couper le tableau t en deux parties parune division euclidienne produit des sous-tableaux de longueurs différentes ; plusprécisément, le premier sous-tableau a une longueur de �n2 �, tandis que le seconda une longueur de �n2 �. Rappelons incidemment la propriété D.34 : �n2 �+�n2 � = n.Dans sa forme développée, l’équation récurrente 4.2.2 s’écrit maintenant :

(T (1) = 1) ∧ ∀p ·(p ∈ N1 − {1}⇒ T (p) = T (�p2�) + T (�p2�) + 1)

Page 132: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 121

Soit Q cette formule. Le résultat acquis pour les puissances de 2 nous suggèrede majorer T (n) par une fonction affine. Nous allons tenter de démontrer qu’ilexiste des réels a et b tels que si a · n + b ∈ N → R+ alors, pour tout n deN1, T (n) ≤ a · n + b. Soit P (n) cette dernière formule. Nous devons démontrerQ ⇒ P (n). Nous pouvons déplacer Q en hypothèse pour nous focaliser sur ladémonstration de la formule P (n).

Nous allons appliquer le principe de récurrence complète (théorème 2,page 44) pour n ∈ N1 − {1} (n ≥ 2). Il nous suffit donc de démontrer P (n)sous les hypothèses Q, n ≥ 2 et ∀m ·(m ∈ N1 − {1} ∧m < n⇒ [n := m]P (n)).Cette dernière formule peut être instanciée de deux façons afin d’obtenir deuxnouvelles hypothèses intéressantes pour la démonstration :

[m := �n2 �](m ∈ N1 − {1} ∧m < n⇒ [n := m]P (n))⇔ Substitution[m := �n2 �](m ∈ N1 − {1} ∧m < n⇒ P (m))

⇔ Substitution�n2 � ∈ N1 − {1} ∧ �n2 � < n⇒ P (�n2 �)

⇔ Définition de P�n2 � ∈ N1 − {1} ∧ �n2 � < n⇒T (�n2 �) ≤ a ·�n2 �+ b (4.2.4)

De même, pour [m := �n2 �], nous obtenons l’hypothèse suivante :

�n2 � ∈ N1 − {1} ∧ �n2 � < n⇒T (�n2 �) ≤ a ·�n2 �+ b (4.2.5)

Nous sommes maintenant prêt à démontrer T (n) ≤ a · n+ b :

T (n)= Hypothèse [p := n]Q

T (�n2 �) + T (�n2 �) + 1≤ Hypothèses 4.2.4 et 4.2.5

a ·�n2 �+ b+ a ·�n2 �+ b+ 1= Propriété D.34

a · n+ b + (b+ 1)≤ Sous réserve que b+ 1 ≤ 0

a · n+ b

Une possibilité consiste à choisir b = −1 et a = 2. Nous obtenons bien unefonction de N dans R+. Le cas n = 1 est trivial (notons qu’il ne s’agit pas d’uncas de base, puisque l’induction complète n’en comporte pas). Nous avons doncmontré que la solution à l’équation récurrente qui décrit la complexité de lafonction estTrie′ pour tout n est majorée par la fonction 2 · n− 1. Elle est doncen O(n).

Utiliser le théorème maître

Une autre technique, qui relève de l’application d’un théorème particulier,permet de s’affranchir de la recherche de la solution à l’équation récurrente oud’un majorant à cette solution : il s’agit du théorème maître (master theorem)dont nous allons fournir (sans la démontrer) une version simplifiée.

Page 133: Structures de données et méthodes formelles ||

122 Structures de données et méthodes formelles

Théorème 3 (Théorème maître). La solution à l’équation récurrente suivante :{S(1) = dS(n) = a · S(n÷ b) + c · nk

(où d ∈ N1, a ∈ N1, b ∈ N1 ∧ b ≥ 2, c ∈ N1 et k ∈ N) satisfait la propriété

S(n) ∈

⎧⎨⎩O(nlogb a) Si a > bk

O(nk · log n) Si a = bk

O(nk) Si a < bk

Ce théorème s’applique pour tout n et pas uniquement pour les puissancesde 2.

L’application à l’équation récurrente 4.2.2 est immédiate : a = 2, b = 2, c = 1,et k = 0. Nous sommes donc dans le cas où a > bk (2 > 20). En conséquence,T (n) ∈ O(nlog2 2) soit encore T (n) ∈ O(n). Nous retrouvons (facilement) lerésultat calculé en passant par une fonction majorante.

Utiliser les propriétés de la structure de données

Plutôt que d’interpréter la fonction à évaluer pour rechercher une équationrécurrente, il est parfois plus simple de dénombrer le nombre de comparaisonsqu’exige le traitement de la structure de données. Reprenons l’exemple de lafonction estTrie. La structure de données considérée est un tableau de n élé-ments, l’algorithme exige n−1 comparaisons. Nous pouvons facilement conclureque la fonction estTrie est en O(n) (et même en Θ(n)).

Cette technique, plus informelle en apparence que celles que nous avons étu-diées ci-dessus, présente l’avantage de prendre en considération des propriétésde la structure de données qui peuvent souvent être utilisées par plusieurs opé-rations. Cependant, la recherche de ces propriétés est un travail de nature com-binatoire qui conduit en général à résoudre des équations récurrentes (cf. [103]).Elle est fréquemment utilisée dans le cas des arbres pour lesquels les principalesopérations dépendent de propriétés telles que la longueur de la branche la pluslongue, la longueur moyenne des branches, etc. Cette méthode est adoptée àplusieurs reprises dans le reste de l’ouvrage.

4.2.5 Conclusion et remarques bibliographiquesNous avons procédé à un tour d’horizon de l’analyse classique de la com-

plexité. Les exemples développés sont basés sur des fonctions très simples, quipermettent cependant d’apprécier la difficulté du domaine. La démarche clas-sique pour résoudre des équations récurrentes consiste à identifier la forme del’équation (équation linéaire à coefficients constants, équation de partition, etc.)et à appliquer les méthodes spécifiques connues. Les équations récurrentes li-néaires à coefficients constants se traitent en général assez facilement dans lecadre théorique de l’algèbre linéaire. Pour le cas des équations de partitions, lethéorème maître présenté ci-dessus permet de résoudre de très nombreux caspratiques. Ce théorème maître est un cas particulier d’un théorème plus général,démontré dans [25]. Il est lui-même un cas particulier du théorème d’Akra-Bazzi

Page 134: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 123

publié en 1998. Dans [25] les auteurs présentent trois méthodes pour résoudre leséquations récurrentes. La première est appelée méthode de substitution. La sec-tion intitulée « Rechercher une fonction majorante » ci-dessus en est une illustra-tion. La seconde, dénommée « méthode arbre-récursion », de nature graphique,permet d’obtenir une suggestion pour appliquer la méthode de substitution. En-fin, le théorème maître est proposé comme troisième possibilité.

Pour le cas des équations de partition, les auteurs de l’ouvrage [17] utilisentles notions de comportement asymptotique conditionnel et de fonctions asymp-totiquement non décroissantes pour généraliser les résultats obtenus avec despuissances de 2, à N tout entier.

Le lecteur souhaitant compléter son information sur le calcul de la com-plexité moyenne peut par exemple consulter l’ouvrage [103] de R. Sedgewick etPh. Flajolet.

Exercices

Exercice 4.2.1 On considère les deux fonctions récursives suivantes :

function f(n) ∈ N→ N =if n ≤ 1 →1

| n > 1 →1 + f(n− 1) + g(n− 1)

fi

et

function g(n) ∈ N→ N =if n ≤ 1 →1

| n > 1 →2 + f(n− 1) · g(n− 1)

fi

Déterminer l’équation de récurrence qui exprime les complexités de f et de g. En déduire uneéquation récurrente pour f .

Exercice 4.2.2 Démontrer par récurrence que la formule 4.2.1, page 114, implique ∀i ·(i ∈0 .. n− 1⇒T (n− i+ 1) = T (n− i) + 1).

4.3 Analyse amortie de la complexité –la méthode du potentiel

4.3.1 IntroductionLes complexités classiques conviennent bien au cas des algorithmes « auto-

nomes » (non liés à une structure de données). Par contre, dès que l’on chercheà évaluer la complexité d’opérations sur une structure de données, on est fré-quemment confronté au problème suivant : une opération (comme par exempleune adjonction) est souvent itérée plusieurs fois consécutives sur la structurede données ; calculer un majorant du coût d’une séquence se fait en sommantsur un majorant de chaque opération. Il apparaît alors qu’en procédant ainsi lerésultat est très pessimiste, puisque dans la réalité les appels qui succèdent àune importante réorganisation de la structure peuvent en tirer immédiatementprofit.

Une solution consisterait à élaborer un modèle probabiliste des données età procéder à un calcul classique de complexité. La modélisation est en général

Page 135: Structures de données et méthodes formelles ||

124 Structures de données et méthodes formelles

difficile. Une autre solution consiste à réaliser une analyse amortie. Il existe plu-sieurs formes d’analyse amortie [112, 113, 109, 101, 69, 93]. La plus pratiquéeest l’analyse amortie par la méthode du potentiel. Son principe est le suivant.Plaçons-nous dans la situation où, pour un type d’opération donné, il existe desréalisations qui sont intrinsèquement coûteuses (évaluées dans une « monnaie »quelconque) alors qu’au contraire d’autres le sont très peu. Effectuer une opé-ration peu coûteuse s’accompagne d’un geste qui consiste à « mettre de côté »un certain montant (qui a pour effet d’augmenter le potentiel). Le coût amortiest pour cette opération le coût intrinsèque de l’opération plus le montant thé-saurisé. Inversement, il est possible, pour une opération coûteuse, de payer enallant puiser dans la réserve (en diminuant d’autant le potentiel). Le coût amortiest alors le coût intrinsèque moins le montant prélevé. Bien entendu, ces opé-rations d’amortissement sont purement virtuelles, elles n’interviennent que pourle calcul de la complexité amortie et n’ont aucune contrepartie dans le code del’opération.

Illustrons ce principe par l’exemple des systèmes de retraite par capitalisa-tion. Supposons que le montant des dépenses nécessaire pour vivre une annéepour une personne active soit de 10 000e et de 9 000e pour un retraité. Sup-posons par ailleurs que le revenu brut d’une personne active soit de 15 000e etqu’un retraité n’ait aucun revenu. Supposons enfin que la vie active dure 40 anset la retraite 20 ans. La personne pourra « mettre de côté » 5 000e chaque annéeen prévision de son départ en retraite. Le tableau 4.3 montre dans la colonne dile coût réel de chacune des 60 années. La colonne gi fournit les gains annuels.Les colonnes

∑di et

∑gi cumulent respectivement les valeurs de di et de gi sur

les 60 années.

Tableau 4.3 – Exemple de tableau d’amortissement.Ce tableau montre comment les gains bruts (colonne gi) d’un salariésur 40 ans lui permettent de vivre sa retraite pendant 20 ans, comptetenu des dépenses annuelles représentées dans la colonne di.

Année di gi∑

di∑

gi

1 10 000 15 000 10 000 15 0002 10 000 15 000 20 000 30 000

· · · · · · · · · · · ·40 10 000 15 000 400 000 600 00041 9 000 0 409 000 600 000· · · · · · · · · · · ·60 9 000 0 580 000 600 000

Le système fonctionne à condition que, pour tout n ∈ 1 .. 60, la somme desgains soit supérieure ou égale à la somme des dépenses, soit :

n∑i=1

gi ≥n∑

i=1

di (4.3.1)

Page 136: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 125

Par contre, il n’est pas nécessaire que pour toutes les années gi ≥ di : la personnepeut supporter une courte période de chômage pendant sa vie active à conditionque la formule 4.3.1 soit respectée.

En général, même dans le cas des retraites par capitalisation, le système estgéré par des « caisses de retraite ». Celles-ci y superposent d’ailleurs une formecomplémentaire d’amortissement afin que les centenaires puissent vivre grâceaux cotisations des personnes qui décèdent précocement.

4.3.2 Fondements théoriques de la méthode du potentielNous définissons tout d’abord les deux notions de fonction de potentiel et de

coût amorti avant de fournir une propriété du coût amorti.

Définition 4 (Fonction de potentiel). Soit un type T de support t. Soit Φ ∈t → R+, soit s0 la configuration initiale de la structure de données et sj uneconfiguration atteignable quelconque, alors Φ est une fonction de potentiel si etseulement si Φ(s0) = 0 et Φ(sj) ≥ 0.

Définition 5 (Coût amorti selon Φ). Soit Φ une fonction de potentiel pour letype T , soit oi un appel à une opération interne o de T , soit T (oi) le coût réel del’opération oi et soit si−1 (resp. si) la configuration de la structure de donnéesavant (resp. après) l’appel, alors

M(oi) = T (oi) + Φ(si)− Φ(si−1) pour i > 0 (4.3.2)

est le coût amorti selon Φ de l’opération oi.

Il est facile d’en conclure par sommation que :∑ki=1M(oi) =

∑ki=1 T (oi) + Φ(sk).

D’où, puisque Φ(sk) ≥ 0, la propriété fondamentale suivante du coût amorti :

Propriété 2 (du coût amorti).∑ki=1M(oi) ≥

∑ki=1 T (oi) (4.3.3)

Cette formule montre donc que le coût réel des k premières opérations est majorépar le coût amorti de ces k opérations. Il est important de noter que cette formulene peut en général s’appliquer à une séquence quelconque d’appels. En effet, lespréconditions des opérations doivent être respectées afin par exemple d’interdirede retirer une valeur d’un ensemble vide. En général on évalue le coût amortid’une séquence valide de n opérations à partir du coût amorti de chaque typed’opération. Le résultat constitue, d’après la formule 4.3.3, une borne supérieureau coût réel de la séquence.

Le choix de la fonction de potentiel Φ est arbitraire, à condition de respecterles propriétés requises. On peut alors calculer pour chaque opération (éventuel-lement conditionnée par le contexte de l’appel) son coût amorti. Bien que lerésultat obtenu soit, selon la formule 4.3.3, un majorant du coût réel, il dépenden général de la fonction de potentiel retenu : toutes les fonctions de potentielne sont pas égales devant le résultat obtenu. Un coût amorti ajusté au mieux

Page 137: Structures de données et méthodes formelles ||

126 Structures de données et méthodes formelles

s’obtient par un choix pertinent pour la fonction Φ. Alors que dans les exempleshistoriques (cf. [109, 110]) ce choix résulte d’une certaine expérience doubléed’une bonne intuition, on voit aujourd’hui émerger une approche, plus raison-nable sur un plan scientifique, dans laquelle la fonction de potentiel est dérivéeconjointement avec le calcul du programme (cf. [69, 101]).

Une difficulté technique surgit parfois dans la définition de la fonction Φ.Elle est liée au fait que l’opération sur laquelle porte l’analyse amortie n’estpas une opération purement interne au type considéré. Ainsi par exemple sinous travaillons sur des arbres, l’opération peut fusionner deux arbres pour n’enformer qu’un seul. Une telle opération (appelons-la fus), définie comme unefonction, aurait le profil suivant :

fus(a, a′) ∈ arbre× arbre→ arbre

Dans ce cas, il faut en principe plusieurs fonctions de potentiel, une pour chaquetype de structure de données considérée. Pour l’exemple ci-dessus nous aurionsΦ pour les arbres :

Φ(a) ∈ arbre→ R+

et Φ′ pour les couples d’arbres :

Φ′(a, a′) ∈ arbre× arbre→ R+

La fonction M se définit alors par

M(fus(a, a′)) = T (fus(a, a′)) + Φ(fus(a, a′))− Φ′(a, a′)

Dans la pratique, lorsqu’il n’y a pas ambiguïté, et par abus de langage, nousassimilons les Φ et Φ′ en une seule fonction.

4.3.3 ExempleCet exemple est pris dans le cadre de la vie quotidienne afin de montrer

la simplicité des concepts sous-jacents et avant de les appliquer à des cas pluscomplexes (cf. pages 135, 251, 322, 351 et 368). Un détaillant en vins souhaiteévaluer le coût amorti de son activité. Celle-ci se décrit comme suit.

– Un employé travaillant à la cave remplit des bouteilles une à une (à partird’une citerne) avant de les stocker dans des porte-bouteilles d’une capacitéde six bouteilles. Cette opération d’embouteillement, dénommée emb, a uncoût réel de 1 (pour une bouteille).

– Au rez-de-chaussée, un porte-bouteilles est disponible pour la vente audétail. Dès que le porte-bouteilles est vide, le vendeur va en chercher unnouveau à la cave. Cette opération, dénommée vente, s’évalue, dans saversion standard, à un coût réel de 1. Par contre, lorsqu’il faut descendrechercher un nouveau porte-bouteilles plein, le coût se décompose en 1 (coûtréel de la vente) + 6 (coût du déplacement à la cave). Cette opération estmunie d’une précondition qui stipule qu’il reste des porte-bouteilles pleinsà la cave et que le porte-bouteilles du rez-de-chaussée est vide.

Page 138: Structures de données et méthodes formelles ||

4. Analyse d’algorithmes 127

Le commerçant décide de choisir comme fonction de potentiel Φ(si) le nombreBi de bouteilles pleines disponibles (en porte-bouteilles) à la cave. Cette fonctionsatisfait les conditions requises : initialement, il y a 0 bouteille disponible et lenombre de bouteilles disponibles n’est jamais négatif.

Le coût amorti M(embi) d’une opération d’embouteillement est :

M(embi)=1 + Coût réel du remplissageΦ(si)− Φ(si−1) Amortissement

= Définition de Φ et arithmétique1 +Bi −Bi−1

= Bi = Bi−1 + 11 +Bi−1 + 1−Bi−1

= Arithmétique2

Le coût amortiM(ventei) d’une vente doit considérer les deux cas possibles.Pour le cas standard nous avons :

M(ventei)=1 + Coût réel de la venteΦ(si)− Φ(si−1) Amortissement

= Définition de Φ et arithmétique1 +Bi −Bi−1

= Bi = Bi−1

1 +Bi−1 −Bi−1

= Arithmétique1

Par contre, le coût amorti d’une vente exigeant de descendre à la cave est :

M(ventei)=1 + Coût réel de la vente6 + Coût réel du déplacementΦ(si)− Φ(si−1) Amortissement

= Définition de Φ et arithmétique7 +Bi −Bi−1

= Bi = Bi−1 − 67 +Bi−1 − 6−Bi−1

= Arithmétique1

Au total, toute séquence valide de n opérations embi ou ventei a un coûtamorti inférieur ou égal à 2 · n (compte tenu du choix de la fonction de potentielΦ). Ces deux opérations ont un coût amorti constant. Si le commerçant avaitvoulu évaluer le coût traditionnel d’une opération vente, il aurait dû majorer le

Page 139: Structures de données et méthodes formelles ||

128 Structures de données et méthodes formelles

coût d’une vente par son coût au pire, soit 7. Il aurait alors obtenu un résultatplus pessimiste que nécessaire. La fonction de potentiel Φ a été judicieusementchoisie pour obtenir le même coût dans les deux situations à envisager pourl’opération vente. Il est bien sûr possible de faire des choix différents (cf. exer-cice 4.3.2).

4.3.4 Conclusion et remarques bibliographiquesHistoriquement, la notion d’analyse amortie est associée à celle de structures

autoadaptatives. Elles ont été introduites principalement par R.E. Tarjan autournant des années 1980. À l’issue d’un troisième cycle à Standford University,sous la direction de J. Hopcroft, R.E. Tarjan a soutenu son phd en 1971. Lesujet portait sur la planarité des graphes. Il a ensuite été enseignant-chercheurà Cornell University, à Berkeley, à Standford puis chercheur aux laboratoiresat&t (tout en poursuivant en parallèle des activités d’enseignement à New-YorkUniversity). Il a obtenu, conjointement avec J. Hopcroft, la distinction TuringAward en 1986 pour leurs contributions à la conception et l’analyse d’algorithmeset de structures de données.

Ses travaux sur les algorithmes union-find (qui sont des algorithmes de main-tenance d’une structure de partition sur des ensembles évolutifs) puis sur l’opti-misation des flots dans les graphes l’ont conduit à l’idée d’analyse amortie de lacomplexité.

Ainsi que nous l’avons écrit plus haut, il existe plusieurs façons de faire del’analyse amortie (cf. [113, 25]). La plus pratiquée est sans conteste la méthodedu potentiel, que nous avons utilisée ci-dessus. Elle est attribuée par R.E. Tarjanà D.D. Sleator (cf. [113], page 308).

L’encadré de la page 324 explique pourquoi il faut être prudent lorsque l’onutilise des structures de données persistantes dans un contexte d’analyse amortie.

Exercices

Exercice 4.3.1 Après l’installation de votre nouvelle chaudière, votre installateur vous proposele contrat de maintenance annuel suivant (J pour janvier, F pour février, etc.) :

J F M A M J J A S O N D0e 0e 100e 0e 0e 60e 0e 0e 200e 0e 0e 100e

En supposant que vous recherchiez une fonction de potentiel Φ constante, qu’allez-vous choisirselon que votre contrat commence en

1. janvier,2. septembre,3. avril,

si vous recherchez la plus petite fonction possible ? Vérifier votre réponse à l’aide d’un tableur.

Exercice 4.3.2 Dans l’exemple de calcul amorti de la page 126 que se passe-t-il si le commer-çant travaille avec des porte-bouteilles d’une capacité de 2 ? de 20 bouteilles ? Proposer unefonction de potentiel Φ différente et refaire un calcul du coût amorti de chaque opération.

Page 140: Structures de données et méthodes formelles ||

Chapitre 5

Exemples

Dans ce chapitre nous proposons de développer deux exemples simplesqui vont nous permettre de mieux appréhender la démarche utilisée dans le restede cet ouvrage.

Ces deux exemples portent sur les entiers naturels. Le premier concerne lareprésentation d’un compteur qu’il est possible d’incrémenter à partir de sa va-leur initiale 0. Nous adoptons une représentation concrète sous la forme d’uneliste d’éléments binaires. Le second exemple vise à représenter un sous-ensembled’entiers. La représentation retenue est fondée sur une liste triée (sans doublon)et l’unique opération que nous développons est l’ajout d’un élément dans lesous-ensemble. Dans chacun des cas, les calculs de représentation sont suivis deconsidérations sur la complexité des opérations.

5.1 Premier exemple

L’objectif de cet exemple est double. Il s’agit tout d’abord de travailler surune structure de données concrète de type liste (cf. section 3.1, page 78) etde calculer des opérations concrètes non triviales. Par ailleurs, et c’est le secondobjectif, cette structure de données nous donne l’occasion d’effectuer une analysede complexité amortie tout en montrant l’intérêt de cette technique.

La structure abstraite qui nous intéresse est celle de compteur. Les deuxopérations abstraites retenues sont raz(), (« remise à zéro ») qui délivre 0 etsuc(v), qui délivre le successeur de v, soit v + 1. Le type abstrait est dénommécompteur. La structure concrète est une liste, reflet de la représentation enbinaire de la valeur. Le type concret est appelé lb (pour liste binaire).

5.1.1 Spécification du type abstrait

Le type abstrait compteur est défini sur le support compteur (cf. figure 5.1).

Page 141: Structures de données et méthodes formelles ||

130 Structures de données et méthodes formelles

abstractType compteur = (compteur, (raz, suc), ())uses Nsupport

e ∈ N ⇔ e ∈ compteuroperations

function raz() ∈ compteur = 0;

function suc(v) ∈ compteur � compteur = v + 1end

Figure 5.1 – Spécification du type abstrait compteur.Ce type abstrait définit la structure des entiers naturels dotée de deuxopérations, raz() qui délivre 0 et suc(v) qui délivre v + 1.

5.1.2 Définition du support concret

Nous abordons à présent la spécification du support concret du type lb quiraffine le type compteur. Le support concret se dénomme lb, il se définit par :

1) [ ] ∈ lb2) v ∈ {0, 1} ∧ l ∈ lb ⇒ [v | l] ∈ lb

La première formule introduit la notation pour les listes vides (cf. section 3.1,page 78), la seconde précise que, si v est un élément binaire (0 ou 1) et l uneliste lb alors [v | l] est aussi une liste lb. Ainsi par exemple la liste k =[0 | [1 | [1 | [ ]]]] est une liste lb. Rappelons que les listes possèdent égalementune représentation linéaire externe qui permet de représenter k par [0, 1, 1].

5.1.3 Définition de la fonction d’abstraction

Toute liste lb représente en binaire un entier compteur, cependant, pour desraisons de facilité de lecture, la représentation se lit de droite à gauche. La listel ci-dessus est donc la représentation de la valeur 0 · 20 + 1 · 21 + 1 · 22, soit 6.Formellement, cette conversion est définie par la fonction d’abstraction suivante :

function A(l) ∈ lb� compteur =if l = [ ] →0

| l = [t | q] →t+ 2 · A(q)

fi

Cette fonction n’est pas bijective (cf. exercice 5.1.2).

Page 142: Structures de données et méthodes formelles ||

5. Exemples 131

5.1.4 Spécification formelle des opérationsRappelons qu’il s’agit ici, pour chacune des opérations concrètes, de spécifier

ce qu’elle représente du point de vue du type abstrait. Les opérations de lbse dénomment raz_l() et suc_l(v), homologues respectivement de raz() et desuc(v). La première, raz_l(), se spécifie par :

function raz_l() ∈ lb = l : (l ∈ lb ∧ A(l) = raz())

Cette spécification se paraphrase de la manière suivante. Toute invocation del’opération concrète raz_l() délivre une liste lb, c’est le sens du symbole ∈. Laformule à droite du symbole de définition = nous apprend que la valeur l délivréepar raz_l() est une liste lb telle que sa conversion par la fonction d’abstractionA fournit le même résultat que l’appel de l’opération abstraite raz().

Il faut se garder de spécifier la fonction raz_l() de la manière suivante :

function raz_l() ∈ lb = [ ]

et ceci pour différentes raisons qui justifient l’intérêt de la démarche utilisée ici :– en procédant de cette façon, nous n’exprimerions pas ce qu’est raz_l() enterme d’entiers naturels ;

– dans des cas plus complexes que celui de l’opération raz_l(), nous serionsconduit à une description inductive prématurée ;

– nous devrions prouver (puisque nous ne l’avons pas spécifié) que l’opérationraz_l() permet bien d’obtenir un résultat cohérent avec celui de l’opérationabstraite raz().

La seconde opération, suc_l(l), se spécifie par :

function suc_l(l) ∈ lb→ lb = k : (k ∈ lb ∧ A(k) = suc(A(l)))

Cette spécification nous dit en particulier qu’un appel à la fonction suc_l(l)délivre une entité k qui est une liste lb telle que sa conversion par la fonctiond’abstraction est égale à l’application de la fonction suc à la conversion de laliste l.

À ce stade du développement, il est possible de fournir une description com-plète du type spécifié lb. C’est ce qui est présenté à la figure 5.2, page 133.

5.1.5 Calcul de la représentation des opérationsCalcul d’une représentation de l’opération raz_l

Il s’agit ici, en partant de la spécification de l’opération concrète raz_l d’encalculer une représentation fonctionnelle.

A(raz_l())= Propriété caractéristique de l’opération raz_l0

= Définition de AA([ ])

Page 143: Structures de données et méthodes formelles ||

132 Structures de données et méthodes formelles

Structures de données et systèmes de numération

À plusieurs occasions il est fait allusion ici à l’analogie qui peut existerentre certains systèmes de numération et certaines structures de don-nées (les files binomiales, section 9.4 ou encore les files gloutonnes, exer-cice 10.4.7). Représenter une structure de données de n éléments se faiten décomposant n dans la base considérée. Ainsi, pour représenter unefile de priorité de 13 éléments par une file binomiale, on décompose 13en base 2 (soit (1101)2) et on construit une file contenant successivementun arbre de 8 éléments, de 4 éléments et de 1 élément. Les opérationsde mise à jour s’assimilent alors à des additions ou à des soustractionsdans la base en question. Ce principe, appliqué à d’autres systèmes denumération, peut permettre de systématiser la recherche de structures dedonnées équilibrées efficaces.

Un système de numération de position se définit par la donnéed’un ensemble B fini de chiffres et d’un ensemble W de poids (W ={w0, w1, w2, . . .}) tels que tout entier n s’écrit de manière unique sous laforme n =

∑mi=0 bi · wi, où bi ∈ B. La suite bmbm−1 . . . b0 est la repré-

sentation de n dans le système considéré. Pour la numération de positionbinaire nous avons B = {0, 1} et W = {20, 21, 22, . . .}. Un autre exemple,le système de numération de Fibonacci, diffère du précédent par les va-leurs de l’ensemble W , qui sont prises sur les nombres fi de la suite deFibonacci. 12 s’écrit alors (1010100), mais peut aussi s’écrire (10001110).L’unicité de représentation est obtenue en normalisant. Pour le systèmede Fibonacci, on impose cm = 1 (on ne fait pas intervenir de 0 non si-gnificatifs) et ci · ci+1 = 0 (on interdit donc la présence de deux termesconsécutifs de la suite dans la représentation). Il existe de nombreux autressystèmes de numération : Avizienis, factorielle, fractions continues, Mer-senne, etc. (cf. [37]).

Le problème qui se pose alors au concepteur de structures de donnéesest de choisir ou de découvrir des arbres appropriés, c’est-à-dire des ar-bres tels que la fusion de deux arbres de poids wi donne un arbre de poidswi+1.

Pour le système de numération binaire, trois types d’arbre sont candi-dats : les arbres externes pleins, les arbres binomiaux et les arbres guidons.Ces derniers sont des arbres pleins (qui possèdent donc 2m−1 nœuds) en-racinés sur une valeur (soit au total 2m−1+1 = 2m nœuds). Ces arbres ont

l’aspect suivant :••

•• •

••• •

. L’arbre de poids 4 a la forme d’un guidon.

Dans [93], C. Okasaki passe en revue plusieurs structures de donnéesfondées sur les principes exposés ci-dessus.

Page 144: Structures de données et méthodes formelles ||

5. Exemples 133

concreteType lb = (lb, (raz_l, suc_l), ())refines compteur

support1) [ ] ∈ lb2) v ∈ {0, 1} ∧ l ∈ lb ⇒ [v | l] ∈ lb

abstractionFunctionfunction A(l) ∈ lb� compteur = . . .

operationSpecificationsfunction raz_l() ∈ lb = l : (l ∈ lb ∧ A(l) = raz())

;function suc_l(l) ∈ lb→ lb = k : (k ∈ lb ∧ A(k) = suc(A(l)))

end

Figure 5.2 – Spécification du type concret lb.Cette spécification raffine le type compteur présenté à la figure 5.1.Elle est fondée sur un support qui est une liste d’éléments binaires. Lafonction d’abstraction A montre comment une liste se convertit dans unentier naturel. La rubrique operationSpecifications spécifie les deuxopérations en mettant en évidence la relation qu’elles entretiennent avecleurs homologues abstraits.

Nous pouvons alors appliquer la propriété de l’équation à membres identiques(page 67) pour affirmer qu’une solution à l’équation A(raz_l()) = A([ ])(équation en raz_l()) est [ ].

Au total nous avons donc calculé la représentation suivante pour l’opérationraz_l() :

function raz_l() ∈ lb = [ ]

L’opération raz_l() délivre simplement une liste vide. Sa complexité est trivia-lement en O(1).

Calcul d’une représentation de l’opération suc_l

Nous recherchons une représentation pour l’opération concrète suc_l(l).Après la phase traditionnelle de passage par la « propriété caractéristique »(cf. section 2.3), nous devons effectuer un raisonnement par induction dont lapartie inductive fait elle-même appel à une analyse par cas.

A(suc_l(l))= Propriété caractéristique de l’opération suc_l1 +A(l) (5.1.1)

Nous procédons à une induction structurelle sur l en commençant par le cas debase l = [ ] :

Page 145: Structures de données et méthodes formelles ||

134 Structures de données et méthodes formelles

1 +A(l)= Hypothèse1 +A([ ])

= Définition de A1 + 0

= Arithmétique1 + 2 · 0

= Définition de A1 + 2 · A([ ])

= Définition de AA([1 | [ ]])

Nous appliquons la propriété de l’équation à membres identiques (page 67) pourproposer la première équation gardée pour l’opération suc_l :

l = [ ]→suc_l(l) = [1 | [ ]]

Concernant le cas inductif, nous pouvons faire l’hypothèse que l = [v | q]. Enrepartant de la formule 5.1.1 nous avons :

1 +A(l)= Hypothèse1 +A([v | q])

= Définition de A1 + v + 2 · A(q) (5.1.2)

La suite du développement dépend de la valeur de v. Nous effectuons une analysepar cas, selon que v = 0 ou que v = 1. Débutons par v = 0 :

1 + v + 2 · A(q)= Hypothèse1 + 0 + 2 · A(q)

= Arithmétique1 + 2 · A(q)

= Définition de AA([1 | q])

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée suivante :

l = [v | q] →v = 0→

suc_l(l) = [1 | q]

Pour le cas v = 1, le développement repart de la formule 5.1.2 et se poursuitpar :

Page 146: Structures de données et méthodes formelles ||

5. Exemples 135

1 + v + 2 · A(q)= Hypothèse1 + 1 + 2 · A(q)

= Arithmétique0 + 2 ·(A(q) + 1)

= Propriété caractéristique de l’opération suc_l0 + 2 · A(suc_l(q))

= Définition de AA([0 | suc_l(q)])

D’où, d’après la propriété de l’équation à membres identiques (page 67), la troi-sième équation gardée :

l = [v | q] →v = 1→

suc_l(l) = [0 | suc_l(q)]

Au total, nous avons calculé la version suivante pour l’opération suc_l :

function suc_l(l) ∈ lb→ lb =if l = [ ] →[1 | [ ]]

| l = [v | q] →if v = 0 →[1 | q]

| v = 1 →[0 | suc_l(q)]

fifi

5.1.6 Complexités de l’opération suc_l

Dans cette section nous cherchons à évaluer la complexité de l’opérationsuc_l. Nous allons tout d’abord nous préoccuper de la complexité au pire puistenter d’effectuer une analyse amortie. Le critère choisi pour évaluer le coût estle nombre d’appels à la fonction suc_l, pour un argument l donné.

La structure de la représentation de la fonction suc_l calculée ci-dessus nouspermet de fournir l’équation récurrente suivante pour le coût « réel » T (suc_l(l))d’un appel :⎧⎨⎩ T (suc_l([ ])) = 1

T (suc_l([0 | q])) = 1T (suc_l([1 | q])) = 1 + T (suc_l(q))

Il est alors facile de majorer T par la fonction T ′ définie en ne retenant que lapremière et la troisième équation ci-dessus :{

T ′(suc_l([ ])) = 1T ′(suc_l([v | q])) = 1 + T ′(suc_l(q))

Page 147: Structures de données et méthodes formelles ||

136 Structures de données et méthodes formelles

Nous obtenons la forme close suivante pour l = [ ] : T ′(suc_l(l)) = #(l) + 1(rappel :#(l) est la fonction qui délivre la longueur de la liste). D’où nous tirons :

T (suc_l(l)) ∈ O(#(l))

qui nous permet d’affirmer que la complexité au pire de l’opération suc_l decalcul de la représentation du successeur se comporte asymptotiquement commele nombre d’éléments de la liste.

Intuitivement nous ressentons que la majoration de T par T ′ est très péna-lisante. Observons le tableau 5.1 ci-dessous qui, pour chacune des 18 premièresconfigurations de la liste, fournit (i) la valeur représentée (colonne A(l)), (ii) lenombre d’appels à la fonction suc_l pour passer de la configuration précédentede l à la configuration courante (colonne r(l)), (iii) le nombre d’appels cumulésà la fonction suc_l depuis l’initialisation (colonne c(l)), (iv) le nombre moyend’appels (valeur tronquée), c’est-à-dire c(l)/A(l) (colonne m(l)). Nous consta-tons (colonne c(l)) que le coût cumulé des opérations suc_l effectuées depuisla situation initiale [ ] ne dépasse jamais la valeur 2 · A(l) : il faut par exemple31 appels à la fonction pour faire passer la liste de la configuration initiale à laconfiguration [0, 0, 0, 0, 1] qui représente la valeur 16.

Tableau 5.1 – Compteurs par listes binaires : estimation des coûts.La colonne dénommée l montre comment évolue une liste initialementvide par appels successifs à la fonction suc_l(l). La colonne suivantefournit la valeur représentée par la configuration de l qui lui correspond.La colonne r(l) quantifie le nombre d’appels à la fonction suc_l pourpasser de la configuration précédente de l à la configuration courante.La colonne c(l) cumule les coûts individuels de la colonne r(l). Enfin lacolonne m(l) délivre la valeur approximative de c(l)/A(l).

l A(l) r(l) c(l) m(l) l A(l) r(l) c(l) m(l)

[ ] 0 0 [1, 0, 0, 1] 9 1 16 1,78[1] 1 1 1 1,00 [0, 1, 0, 1] 10 2 18 1,80[0, 1] 2 2 3 1,50 [1, 1, 0, 1] 11 1 19 1,73[1, 1] 3 1 4 1,33 [0, 0, 1, 1] 12 3 22 1,83[0, 0, 1] 4 3 7 1,75 [1, 0, 1, 1] 13 1 23 1,77[1, 0, 1] 5 1 8 1,60 [0, 1, 1, 1] 14 2 25 1,79[0, 1, 1] 6 2 10 1,67 [1, 1, 1, 1] 15 1 26 1,73[1, 1, 1] 7 1 11 1,57 [0, 0, 0, 0, 1] 16 5 31 1,94[0, 0, 0, 1] 8 4 15 1,88 [1, 0, 0, 0, 1] 17 1 32 1,88

Si, comme le laisse penser la courbe de la figure 5.3, page ci-contre, cetterègle se généralise, cela signifie qu’il doit être possible de mettre en évidence unecomplexité amortie inférieure ou égale à 2, qui serait donc en O(1). C’est ce quenous allons tenter de démontrer à présent.

Page 148: Structures de données et méthodes formelles ||

5. Exemples 137

A(l)

m(l)

2

32 64 96 128

Figure 5.3 – Nombre moyen d’appels à la fonction suc_l.Cette courbe fournit le nombre moyen d’appels à l’opération suc_l enfonction de la valeur A(l) représentée par la liste. Elle semble présenterune asymptote pour m(l) = 2.

Ainsi que nous l’avons vu à la section 4.3, effectuer une analyse amortienécessite de choisir une fonction de potentiel définie sur le type considéré et àvaleurs dans R+. Nous nous décidons pour la fonction qui délivre le nombre de1 présents dans la liste en argument. Cette fonction se définit par la récurrencesuivante :{

Φ([ ]) = 0Φ([t | q]) = t+Φ(q)

La formule de la complexité amortie (formule 4.3.2, page 125) s’instancie de lamanière suivante pour l’opération suc_l :

M(suc_l(l)) = T (suc_l(l)) + Φ(suc_l(l))− Φ(l)

Elle se résout par induction sur la structure de l et, pour la partie inductive, parune analyse par cas. Débutons par le cas de base l = [ ] :

M(suc_l([ ]))= Définition de M(suc_l(l))

T (suc_l([ ])) + Φ(suc_l([ ]))− Φ([ ])= Définition de T et représentation de suc_l1 + Φ([1 | [ ]])− Φ([ ])

= Définition de Φ1 + 1 + Φ([ ])− Φ([ ])

= Définition de Φ et arithmétique2

Pour la partie inductive (l = [t | q]), nous distinguons les cas t = 0 et t = 1 ;nous débutons par t = 0 :

M(suc_l([0 | q]))= Définition de M(suc_l(l))

T (suc_l([0 | q])) + Φ(suc_l([0 | q]))− Φ([0 | q])= Définition de T et représentation de suc_l

Page 149: Structures de données et méthodes formelles ||

138 Structures de données et méthodes formelles

1 + Φ([1 | q])− Φ([0 | q])= Définition de Φ1 + 1 + Φ(q)− Φ(q)

= Arithmétique2

Enfin, le cas t = 1 se traite comme suit :

M(suc_l([1 | q]))= Définition de M(suc_l(l))

T (suc_l([1 | q])) + Φ(suc_l([1 | q]))− Φ([1 | q])= Définition de T et de suc_l1 + T (suc_l(q)) + Φ([0 | suc_l(q)])− Φ([1 | q])

= Définition de Φ1 + T (suc_l(q)) + Φ(suc_l(q))− Φ(q)− 1

= Calcul sur R+

T (suc_l(q)) + Φ(suc_l(q))− Φ(q)= Définition de M

M(suc_l(q))

Au total, nous avons calculé la version récurrente suivante de M(suc_l(l)) :⎧⎨⎩ M(suc_l([ ])) = 2M(suc_l([0 | q])) = 2M(suc_l([1 | q])) =M(suc_l(q))

dont la solution immédiate est M(suc_l(l)) = 2. Nous avons donc le résultatsuivant pour l’analyse amortie de la complexité de l’opération suc_l selon lafonction de potentiel Φ :

M(suc_l(l)) est en O(1)

En terme d’analyse amortie, l’opération suc_l est donc en temps constant.

5.1.7 Conclusion et remarques bibliographiquesCet exemple nous a permis de nous familiariser avec une structure de don-

nées importante : les listes. Par ailleurs, il constitue un cas d’étude typiquede l’analyse amortie. Il est également utilisé dans ce but par T. Cormen et al.dans [25]. Notre approche est cependant différente (le support concret est uneliste et nous calculons les opérations) et s’inspire plus de celle d’A. Kaldewaijet B. Schoenmakers dans [69]. Ces derniers auteurs l’utilisent également commeexemple introductif dans un article portant sur la dérivation de fonctions depotentiel.

Page 150: Structures de données et méthodes formelles ||

5. Exemples 139

Exercices

Exercice 5.1.1 Nous considérons le type de base N doté de l’opérateur +. Raffiner ce typeabstrait par une structure de données représentant la liste des chiffres décimaux significatifs.

Exercice 5.1.2 Dans l’exemple ci-dessus, l’ensemble lo des listes qu’il est possible d’obtenir àpartir des deux opérations raz_l et suc_l est strictement inclus dans l’ensemble lb des listesdécrites par le support. En effet, ces opérations n’engendrent pas de 0 non significatifs.

1. Donner un exemple d’une liste appartenant à lb mais pas à lo.2. La fonction A n’est pas injective. Pourquoi ? Modifier le support lb afin qu’elle le soit.

Exercice 5.1.3 On considère le type abstrait natbool destiné à représenter des booléens. Lesupport est constitué des deux entiers 0 et 1, et les opérations possibles sont non et et. On veutimplanter ce type abstrait en utilisant le support {V, F}. Proposer une spécification abstraite,une spécification concrète et calculer les opérations concrètes.

Exercice 5.1.4 Définir un type abstrait permettant l’addition d’entiers. Mettre en œuvre cetype abstrait par des listes binaires. Effectuer les calculs de complexité (classique et amortie)de votre solution.

5.2 Second exempleDans cet exemple, nous souhaitons raffiner le type abstrait ensnat (qui per-

met de représenter des sous-ensembles finis d’entiers naturels définis en exten-sion) par des listes triées. Nous limitons le jeu d’opérations à eV ide() qui délivreun sous-ensemble vide et à eAjout(v, e) qui introduit l’entier v dans le sous-ensemble e. Nous focalisons notre attention sur l’opération eAjout.

5.2.1 Spécification du type abstrait ensnat

Le type abstrait ensnat est défini sur le support ensNat. Celui-ci s’identifieà l’ensemble des parties finies de N. En principe, cet exemple aurait sa place audébut du chapitre 6 consacré aux ensembles finis de scalaires, cependant leditchapitre est réservé à des mises en œuvre plus élaborées.

5.2.2 Définition du support concretNous abordons à présent la spécification du type concret dénommé lt (liste

triée) qui raffine le type ensnat. Le support lt se définit par :

1) [ ] ∈ lt2) v ∈ N⇒ [v | [ ]] ∈ lt3) v ∈ N ∧ [w | q] ∈ lt ∧ v < w ⇒ [v | [w | q]] ∈ lt

La première formule introduit la notation pour les listes « vides ». La secondeformule précise qu’une liste ne comportant qu’un seul élément est une liste lt.La troisième formule affirme que la liste obtenue en plaçant en tête d’une listelt non vide [w | q] une valeur v plus petite que w est une liste lt.

Page 151: Structures de données et méthodes formelles ||

140 Structures de données et méthodes formelles

abstractType ensnat = (ensNat, (eV ide, eAjout), ())uses Nsupport

e ∈ F(N) ⇔ e ∈ ensNatoperations

function eV ide() ∈ ensNat = ∅;

function eAjout(v, e) ∈ N× ensNat→ ensNat = {v} ∪ eend

Figure 5.4 – Spécification du type abstrait ensnat.Spécification de sous-ensembles d’entiers naturels définis en extension.Seules les deux opérations fondamentales eV ide et eAjout sont définies.

5.2.3 Définition de la fonction d’abstraction

Cette fonction se définit de manière inductive. Puisque nous réalisons unraffinement de ensNat par lt, A a comme domaine le support lt défini ci-dessuset comme codomaine ensNat. C’est une fonction surjective (tout élément deensNat doit pouvoir être représenté), totale (tout élément de lt représente unensemble) et injective (à un élément donné de ensNat ne correspond qu’uneseule liste possible). Il s’agit donc d’une bijection.

function A(l) ∈ lt�� entNat =if l = [ ]→∅

| l = [v | q]→{v} ∪ A(q)

fi

5.2.4 Spécification des opérations concrètes

Les identificateurs des opérations concrètes sont suffixés par _l. La spécifica-tion des opérations se fait comme d’habitude en exploitant le fait que la fonctiond’abstraction est un homomorphisme entre le type concret et le type abstrait. Àce stade du développement, il est possible de fournir une spécification complètedu type lt. C’est ce qui est présenté à la figure 5.5, page ci-contre.

5.2.5 Calcul d’une représentation de l’opération eAjout_l

Il s’agit ici, en partant de la spécification de l’opération concrète eAjout_l,d’en calculer une représentation fonctionnelle.

A(eAjout_l(v, l))= Propriété caractéristique de l’opération eAjout_l

{v} ∪ A(l) (5.2.1)

Page 152: Structures de données et méthodes formelles ||

5. Exemples 141

concreteType lt = (lt, (eV ide_l, eAjout_l), ())uses Nrefines ensnat

support1) [ ] ∈ lt2) v ∈ N⇒ [v | [ ]] ∈ lt3) v ∈ N ∧ [w | q] ∈ lt ∧ v < w ⇒ [v | [w | q]] ∈ lt

abstractionFunctionfunction A(l) ∈ lt�� entNat = . . .

operationsfunction eV ide_l() ∈ lt = e : (e ∈ lt ∧ A(e) = eV ide())

;function eAjout_l(v, l) ∈ N× lt→ lt =f : (f ∈ lt ∧ A(f) = eAjout(v,A(l)))

end

Figure 5.5 – Spécification du type concret lt.Il s’agit d’une spécification concrète du type ensnat de la figure 5.4,page ci-contre. Le support est une liste triée de naturels. La fonctiond’abstraction est détaillée page ci-contre.

À ce stade, nous ne pouvons éviter un raisonnement par induction sur la structurede l. Nous considérons successivement l = [ ] (pour l’étape de base) et l = [w | q](étape inductive). Débutons par l’étape de base :

{v} ∪ A(l)= Hypothèse

{v} ∪ A([ ])= Définition de A

A([v | [ ]])

D’où la première équation gardée, par application de la propriété de l’équationà membres identiques (page 67) :

l = [ ] →eAjout_l(v, l) = [v | [ ]]

L’étape inductive suppose que l = [w | q]. Nous poursuivons à partir de laformule 5.2.1 :

{v} ∪ A(l)= Hypothèse

{v} ∪ A([w | q]) (5.2.2)= Définition de A

{v} ∪ {w} ∪ A(q) (5.2.3)

À ce stade du développement, progresser exige d’effectuer une analyse par cas,selon que v = w, que v < w ou que v > w. Débutons par le cas v = w enreprenant la formule 5.2.3 :

Page 153: Structures de données et méthodes formelles ||

142 Structures de données et méthodes formelles

{v} ∪ {w} ∪ A(q)= Hypothèse et propriété A.9

{w} ∪ A(q)= Définition de A

A([w | q])= Hypothèse

A(l)

Nous obtenons l’équation gardée :

l = [w | q] →v = w →

eAjout_l(v, l) = l

Pour le cas v < w, nous repartons de la formule 5.2.2 :

{v} ∪ A([w | q])= Définition de A

A([v | [w | q]])

Notons que l’application de la définition de A n’est possible que parce que v < w.Nous obtenons l’équation gardée :

l = [w | q] →v < w →

eAjout_l(v, l) = [v | [w | q]]

Le cas v > w se traite également en repartant de la formule 5.2.3 :

{v} ∪ {w} ∪ A(q)= Commutativité de ∪

{w} ∪ {v} ∪ A(q)

Arrivé à ce stade du développement, il convient de noter que, certes, nous sa-vons que v > w, mais nous ne savons rien de la position de v par rapport aux(éventuels) éléments de q. Il est donc hors de question d’appliquer la définitionde A pour remplacer {v} ∪ A(q) par A([v | q]). Par contre, nous remarquonsque nous pouvons utiliser la propriété caractéristique pour introduire l’opérationeAjout_l :

{w} ∪ {v} ∪ A(q)= Propriété caractéristique de l’opération eAjout_l

{w} ∪ A(eAjout_l(v, q))

Cette fois nous avons la certitude que w est inférieur à tous les éléments deA(eAjout_l(v, q)). Nous pouvons exploiter la définition de A :

{w} ∪ A(eAjout_l(v, q))= Définition de A

A([w | eAjout_l(v, q)])

Page 154: Structures de données et méthodes formelles ||

5. Exemples 143

D’où l’équation gardée :

l = [w | q] →v > w →

eAjout_l(v, l) = [w | eAjout_l(v, q)]

En rassemblant les quatre équations gardées calculées ci-dessus, nous obte-nons la représentation suivante de l’opération eAjout_l :

function eAjout_l(v, l) ∈ N× lt→ lt =if l = [ ] →

[v | [ ]]| l = [w | q] →

if v = w →l

| v < w →[v | [w | q]]

| v > w →[w | eAjout_l(v, q)]

fifi

Concernant la complexité au pire, il est clair que l’ajout d’une valeur dansune liste de n éléments peut conduire à traverser la totalité de la liste. Nousavons donc une opération qui est au pire en O(n).

5.2.6 ConclusionCet exemple nous a permis de renforcer notre savoir-faire sur les listes. Il

nous a également fait toucher du doigt les limites des structures à base de listes,en particulier en termes d’efficacité, mais il nous a fait acquérir des réflexes dedéveloppement qui s’appliqueront sur des structures plus complexes comme lesarbres.

Exercices

Exercice 5.2.1 Enrichir le type abstrait ensnat en introduisant les opérations :– eSupp(v, e) qui délivre l’ensemble e− {v}.– eUnion(e, f) qui délivre l’ensemble e ∪ f .– eInter(e, f) qui délivre l’ensemble e ∩ f .

Exercice 5.2.2Mettre en œuvre le type abstrait de l’exercice 5.2.1 en utilisant successivement :1. des listes triées,2. des listes (non triées) sans doublon,3. des listes quelconques.

Exercice 5.2.3 On considère les polynômes sur N dotés des opérations pV ide() (qui délivreun polynôme vide), pAjout(m, p) (qui ajoute le monôme m au polynôme p), pAdd(p, q) (quiadditionne les deux polynômes p et q) et pAppli(v, p) (qui applique la valeur v à la fonctionpolynôme p).

Page 155: Structures de données et méthodes formelles ||

144 Structures de données et méthodes formelles

1. Spécifier le type abstrait comme un ensemble de couples c �→ e (coefficient/exposant),avec c = 0.

2. Fournir une spécification concrète sous la forme d’une liste triée sur l’exposant, puiscalculer les différentes opérations.

Page 156: Structures de données et méthodes formelles ||

Deuxième partie

Structures de donnéesfondamentales :

spécification et mises enœuvre

Page 157: Structures de données et méthodes formelles ||

Chapitre 6

Ensembles de clés scalaires

6.1 Présentation informelleAu chapitre 1 nous avons étudié la théorie des ensembles sous son aspect

mathématique. Cet aspect ne satisfait pas complètement l’informaticien, qui abesoin d’un « type abstrait » ensemble. C’est cette facette qui est explorée ici. Lecontexte général de ce chapitre est le suivant. Soit T un ensemble dénombrable.Nous cherchons à représenter des sous-ensembles finis de T , dynamiques, définisen extension. Explicitons les trois qualificatifs.

– Sous-ensembles finis de T : nous nous intéressons à des ensembles e telsque e ∈ F(T ) où F(T ) dénote l’ensemble des parties finies de T .

– Sous-ensembles définis en extension : il s’agit du cas où les sous-ensemblessont définis par l’énumération de leurs éléments et non par l’établissementd’une propriété des éléments.

– Sous-ensembles dynamiques : le contenu des sous-ensembles est susceptibled’évoluer dans le temps, par l’adjonction ou la suppression d’éléments.

Nous nous intéressons en particulier à des ensembles de scalaires (ou d’élé-ments considérés comme tels). Certains choix de représentation nous obligerontà nous limiter à des ensembles T dotés d’une relation d’ordre totale (notée ≤ ou≥ dans la suite).

Le type abstrait ensabst défini ci-dessous permet de gérer l’adjonction etla suppression d’éléments, en nommant les éléments qui sont manipulés. Demanière plus précise, nous disposons des cinq opérations suivantes :

– eV ide(), cette opération délivre un ensemble vide ;– eAjout(v, e), cette opération délivre l’ensemble e ∪ {v} qui contient tousles éléments déjà présents dans e plus (si v /∈ e) l’élément v ;

– eSupp(v, e), cette opération délivre l’ensemble contenant tous les élémentsde e moins l’élément v. Si e ne contient pas l’élément v, le résultat délivréest e ;

– eApp(v, e), cette opération délivre true si et seulement si l’élément v estprésent dans l’ensemble e ;

– eEstV ide(e), cette opération délivre true si et seulement si l’ensemble eest vide.

Page 158: Structures de données et méthodes formelles ||

148 Structures de données et méthodes formelles

Pour ce qui concerne les opérations d’union, d’intersection et de différence,leur mise en œuvre est en général proposée en exercice.

Quid des sous-ensembles définis en compréhension ? Un approfondissementde ce thème – important en informatique – nous conduirait rapidement auxnotions de systèmes formels et de grammaires, dont l’étude sort du cadre de cetouvrage.

Pour ce qui concerne les ensembles définis en extension, en général, dans lapratique, à chaque élément est associé un jeu de valeurs (le nom et l’âge pour unensemble d’individus, le prix d’achat et le prix de vente pour le code d’un pro-duit, etc.) appelés parfois attributs. Cette association, de nature fonctionnelle,est facile à représenter. Pour cette raison, dans la suite nous faisons systémati-quement abstraction de ces informations secondaires tout en acceptant le termede clé ou d’identifiant pour désigner chaque élément de l’ensemble.

Ainsi que nous l’avons mentionné dans l’avant-propos, la référence chrono-logique aux quatre époques des structures de données sert de fil rouge au déve-loppement de chaque chapitre de la seconde partie. Concernant les ensembles declés scalaires, les trois premières mises en œuvre (arbres binaires de recherche,hachage et arbres externes) concernent la première période, celle des pionniers.Les deux suivantes, les Avl et les B-arbres, sont caractéristiques de la secondepériode, celle des « structures équilibrées ». La sixième mise en œuvre, par arbresdéployés, est l’archétype des structures autoadaptatives des années 1980. Enfin,la dernière, les arbres randomisés, sert de prototype pour la quatrième période,celle des structures aléatoires. Une autre méthode, datant de la première époque,celle du vecteur caractéristique, aurait mérité d’être développée ici en raison desa simplicité. Par ailleurs, elle permet aisément de réaliser un calcul de com-plexité moyenne. Cependant il ne s’agit pas d’une structure fonctionnelle pure.Son principe est le suivant : pour représenter un sous-ensemble d’un intervalled’entiers i ..s, il suffit de prendre un tableau t de booléens tel que t(k) vaut truesi et seulement si k est présent dans l’ensemble représenté par t.

6.2 Spécification du type abstrait ensabst

Le type abstrait ensabst est particulièrement simple à spécifier dans la me-sure où nous utilisons directement les notations de la théorie des ensembles pourdéfinir les cinq opérations retenues. La spécification de ensabst est présentée àla figure 6.1, page ci-contre.

eV ide() est une fonction sans argument délivrant un élément (toujours lemême : l’ensemble vide) de type ensabst(T ). eV ide() est donc une constante.

eAjout(v, e) est une fonction à deux arguments délivrant un élément du typeensabst(T ). Il s’agit d’une fonction totale : tout élément v, qu’il soit déjà présentou non, peut être « ajouté » à l’ensemble e. Dans le premier cas (resp. le second),nous parlons de fausse (resp. de vraie) insertion. Une remarque analogue peutêtre réalisée pour le cas de la fonction eSupp(v, e).

Page 159: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 149

eApp(v, e) est une fonction à deux arguments délivrant un booléen. Si l’onconsidère tous les couples du produit cartésien T × ensAbst(T ), pour certainsleur valeur à travers la fonction délivre true pour d’autres false. L’ensemblebool est donc atteint dans son intégralité : c’est une fonction surjective. Desurcroît elle est totale. D’où la notation � utilisée pour préciser la nature decette fonction. Le constat est identique pour la fonction eEstV ide(e).

abstractType ensabst(T ) = (ensAbst, (eV ide, eAjout, eSupp),(eApp, eEstV ide))

usesbool, T

supporte ∈ F(T ) ⇔ e ∈ ensAbst(T )

operationsfunction eV ide() ∈ ensAbst(T ) = ∅

;function eAjout(v, e) ∈ T × ensAbst(T )→ ensAbst(T ) = e ∪ {v}

;function eSupp(v, e) ∈ T × ensAbst(T )→ ensAbst(T ) = e− {v}

;function eApp(v, e) ∈ T × ensAbst(T )� bool = bool(v ∈ e)

;function eEstV ide(e) ∈ ensAbst(T )� bool = bool(e = ∅)

end

Figure 6.1 – Spécification du type abstrait ensabst.Les cinq opérations spécifiées ci-dessus sont reprises plus tard dansles mises en œuvre qui sont envisagées. Le support ensAbst est définicomme étant un sous-ensemble fini d’éléments de T. eV ide et eAjoutsont les deux opérations à partir desquelles il est possible de construiretout ensemble fini sur T : ce sont les constructeurs.

Exercices

Exercice 6.2.1 Fournir une définition alternative à la définition de l’opération eAjout de lafigure 6.1 ci-dessus, de façon à délivrer un second résultat par lequel l’utilisateur est informéde l’absence ou non de la clé à insérer dans l’ensemble en argument.

Exercice 6.2.2 Enrichir le type abstrait ensabst en lui adjoignant les opérations suivantes :– eInter qui calcule l’intersection de deux ensembles ;– eUnion qui calcule l’union de deux ensembles ;– eDiff qui calcule la différence entre deux ensembles ;– eMax qui délivre la plus grande valeur d’un ensemble non vide doté d’une structure

d’ordre total.

Page 160: Structures de données et méthodes formelles ||

150 Structures de données et méthodes formelles

6.3 Méthodes arborescentes élémentaires :les arbres binaires de recherche

La recherche dichotomique est connue pour son efficacité mais ne peut êtrepratiquée sur une représentation séquentielle chaînée (une liste). Les ajouts etsuppressions, si l’on fait abstraction de la fonctionnalité de recherche que com-portent ces opérations, ne sont souvent efficaces que pour des représentationschaînées. L’objectif d’une bonne efficacité pour les trois opérations de recherche,d’ajout et de suppression nous conduit à dépasser les représentations linéairespour adopter des méthodes arborescentes.

L’idée est la suivante : il faut rendre explicite l’arbre de recherche qui gou-verne la recherche dichotomique. L’utilisation d’une représentation chaînée pourcet arbre facilite les mises à jour, qui étaient problématiques dans le cas desreprésentations linéaires. Le type concret étudié ci-dessous représente des sous-ensembles finis d’entiers naturels, il se dénomme eabr. Il se base sur les abr(cf. section 3.5.2, page 89).

6.3.1 Définition du support concret

Nous adoptons une représentation telle que, à tous les niveaux, le sous-arbregauche contient toutes les valeurs de l’ensemble inférieures à la racine et le sous-arbre droit toutes les valeurs supérieures à la racine. Le caractère « sans dou-blon » de la structure est trivialement lié au caractère strict des inégalités pré-sentes dans la définition du support eAbr. A est la fonction d’abstraction, A(a)est l’ensemble abstrait représenté par l’arbre a.

1) 〈〉 ∈ eAbr2) n ∈ N ∧ g ∈ eAbr ∧ d ∈ eAbr ∧ max(A(g)) < n ∧ min(A(d)) > n

⇒〈g, n, d〉 ∈ eAbr

Ainsi l’arbre binaire suivant :

〈〈〈〈〉, 4, 〈〉〉, 7, 〈〈〈〉, 10, 〈〉〉, 15, 〈〉〉〉, 20, 〈〈〈〈〉, 24, 〈〉〉, 27, 〈〈〉, 30, 〈〉〉〉, 33, 〈〉〉〉

se représente graphiquement par :

20

7

4 15

10

33

27

24 30

Page 161: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 151

6.3.2 Définition de la fonction d’abstractionLa fonction d’abstraction A a comme domaine l’ensemble eAbr et comme

codomaine ensAbst(N). La première expression gardée de la définition stipulequ’un arbre vide représente l’ensemble vide tandis que la seconde décrit com-ment, dans un arbre non vide, la racine et les ensembles issus des sous-arbresgauche et droit se composent pour représenter un ensemble.

function A(a) ∈ eAbr � ensAbst(N) =if a = 〈〉 →∅

| a = 〈g, n, d〉 →A(g) ∪ {n} ∪ A(d)

fi

Théorème 4 (des arbres binaires de recherche). Soit a = 〈g, n, d〉 un eAbr etv ∈ N.

1. v ≥ n⇒ v /∈ A(g),2. v ≤ n⇒ v /∈ A(d).

Ce théorème établit que si une valeur v est supérieure ou égale (resp. inférieureou égale) à la racine, elle n’appartient pas au sous-arbre gauche (resp. droit). Sadémonstration est laissée en exercice ; elle résulte directement des propriétés D.4et D.12.

6.3.3 Spécification des opérations concrètesLe nom des opérations concrètes dérive du nom des opérations abstraites en

le suffixant par _a. La spécification de chaque opération concrète s’obtient àpartir des opérations abstraites en considérant la fonction d’abstraction commeun homomorphisme entre la structure concrète et la structure abstraite. La spé-cification du type concret eabr est présentée à la figure 6.2, page suivante.

6.3.4 Calcul de la représentation des opérations concrètesNous allons développer le calcul de la représentation de deux des cinq opé-

rations du type eabr : eAjout_a et eSupp_a. Pour ce qui concerne l’opérationd’adjonction eAjout_a, deux démarches extrêmes sont à considérer : l’adjonc-tion aux feuilles et l’adjonction à la racine (cette dernière se décline sous deuxformes : par partitionnement et par rotation). L’adjonction aux feuilles est la so-lution classique qui, à l’inverse des deux formes d’adjonction à la racine, s’étendà différentes variantes d’abr (aux Avl par exemple, cf. section 6.6) et s’adapteaux cas d’arbres autres que les abr (aux B-arbres par exemple, cf. section 6.7).L’existence de ces deux solutions extrêmes nous conduit à penser qu’il doit êtrepossible d’insérer une valeur dans un abr à tout endroit sur le chemin de la re-cherche. Cette possibilité est exploitée dans les abr randomisés (cf. section 6.9.7).Trois sections sont réservées aux insertions : la première est consacrée à l’inser-tion aux feuilles, la seconde à l’insertion à la racine par partitionnement et latroisième présente, sans la développer, l’insertion à la racine par rotation.

Page 162: Structures de données et méthodes formelles ||

152 Structures de données et méthodes formelles

concreteType eabr = (eAbr, (eV ide_a, eAjout_a, eSupp_a),(eApp_a, eEstV ide_a))

uses bool,Nrefines ensabst(N)support

1) 〈〉 ∈ eAbr2) n ∈ N ∧ g ∈ eAbr ∧ d ∈ eAbr ∧ max(A(g)) < n ∧ min(A(d)) > n

⇒〈g, n, d〉 ∈ eAbr

abstractionFunctionfunction A(a) ∈ eAbr � ensAbst(N) = . . .

operationSpecificationsfunction eV ide_a() ∈ eAbr = b : (b ∈ eAbr ∧ A(b) = eV ide())

;function eAjout_a(v, a) ∈ N× eAbr→ eAbr =b : (b ∈ eAbr ∧ A(b) = eAjout(v,A(a)))

;function eSupp_a(v, a) ∈ N× eAbr→ eAbr =b : (b ∈ eAbr ∧ A(b) = eSupp(v,A(a)))

;function eApp_a(v, a) ∈ N× eAbr � bool = eApp(v,A(a))

;function eEstV ide_a(a) ∈ eAbr � bool = eEstV ide(A(a))

end

Figure 6.2 – Spécification du type concret eabr.

Calcul d’une représentation de l’opération eAjout_a : insertion auxfeuilles

Nous partons de l’expression A(eAjout_a(v, a)) :

A(eAjout_a(v, a))= Propriété caractéristique de l’opération eAjout_a

A(a) ∪ {v} (6.3.1)

Il est alors nécessaire de procéder à un raisonnement par induction en considérantdeux cas selon la structure de a, le cas de base pour lequel a = 〈〉 et le cas inductifpour lequel a = 〈〉. Nous débutons par le cas de base.

A(a) ∪ {v}= Hypothèse

A(〈〉) ∪ {v}= Proposition A.9

A(〈〉) ∪ {v} ∪ ∅= Définition de A

A(〈〉) ∪ {v} ∪ A(〈〉)

Page 163: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 153

= Application de AA(〈〈〉, v, 〈〉〉)

En appliquant la propriété de l’équation à membres identiques (page 67), nousobtenons la première équation gardée de la fonction eAjout_a :

a = 〈〉 →eAjout_a(v, a) = 〈〈〉, v, 〈〉〉

Pour le second cas, a = 〈〉, nous considérons que a = 〈g, n, d〉. Nous repartonsde la formule 6.3.1 ci-dessus.

A(a) ∪ {v}= Hypothèse

A(〈g, n, d〉) ∪ {v}= Définition de A

A(g) ∪ {n} ∪ A(d) ∪ {v}= Propriété A.7 itérée

A(g) ∪ {v} ∪ {n} ∪ A(d) (6.3.2)

À ce stade du développement, il est nécessaire de distinguer trois cas : v = n,v < n et v > n. Nous débutons par le cas v = n.

A(g) ∪ {v} ∪ {n} ∪ A(d)= Propriété A.9

A(g) ∪ {n} ∪ A(d)= Définition de A

A(〈g, n, d〉)

L’application de la propriété de l’équation à membres identiques (page 67) nouspermet d’obtenir l’équation gardée suivante :

a = 〈g, n, d〉 →v = n →

eAjout_a(v, a) = 〈g, n, d〉

Le cas v < n se traite en repartant de la formule 6.3.2 :

A(g) ∪ {v} ∪ {n} ∪ A(d)= Propriété caractéristique de l’opération eAjout_a

A(eAjout_a(v, g)) ∪ {n} ∪ A(d)= Définition de A

A(〈eAjout_a(v, g), n, d〉)

Ce résultat nous conduit à l’équation gardée suivante pour le cas v < n :

a = 〈g, n, d〉 →v < n →

eAjout_a(v, a) = 〈eAjout_a(v, g), n, d〉

Page 164: Structures de données et méthodes formelles ||

154 Structures de données et méthodes formelles

Le résultat pour le cas v > n s’en déduit aisément par symétrie. Au total, enrassemblant les différents résultats obtenus, pour cette version de l’opérationeAjout_a, nous avons calculé la représentation suivante :

function eAjout_a(v, a) ∈ N× eAbr→ eAbr =if a = 〈〉 →

〈〈〉, v, 〈〉〉| a = 〈g, n, d〉 →

if v = n →〈g, n, d〉

| v < n →〈eAjout_a(v, g), n, d〉

| v > n →〈g, n, eAjout_a(v, d)〉

fifi

Qu’en est-il de la complexité temporelle ? Dans le reste de la section, l’opé-ration qui tient lieu d’unité pour les mesures de complexité est la comparaisonimpliquant un nœud de l’arbre. Cela signifie que nous faisons abstraction desautres gardes qui pourraient être évaluées dans l’algorithme (comme les gardesdes conditionnelles dédiées à la sélection entre un arbre vide et un arbre nonvide) ainsi que des autres opérations, apparentes ou non (comme les recopiesde structures). Du point de vue asymptotique, cette approximation est justi-fiée. La complexité de l’ajout dépend à l’évidence du rayon de l’arbre considéré.Elle est de n pour l’insertion dans l’arbre de la n + 1e valeur d’une liste triée.C’est le pire des cas possibles. Asymptotiquement l’opération est donc au pireen O(n). À l’inverse, la complexité la meilleure est obtenue lors de l’insertiondans un sous-arbre vide d’un abr de poids n. D’où la complexité asymptotiquela meilleure : O(1).

Qu’en est-il en moyenne ? Est-on plus près de O(n) ou de O(1) ? Excep-tionnellement 1, nous allons tenter de répondre à ces questions, les calculs étantassez faciles à réaliser. Cependant, avant de nous lancer dans le développement,il est nécessaire de préciser le modèle probabiliste sur lequel nous nous basonspour analyser l’insertion aux feuilles dans un abr de n éléments. Nous consi-dérons tout d’abord que toutes les valeurs destinées à apparaître dans l’arbresont différentes. Deux modèles équiprobabilistes sont en concurrence. Le premierconsidère que tous les abr de n éléments sont équiprobables. C’est le modèle des« arbres de Catalan » [103]. Le second considère que ce sont les n! permuta-tions des n valeurs insérées qui sont équiprobables. C’est le modèle des « arbresaléatoires ». Dans ce dernier cas, il est facile de comprendre que nous pouvons,sans perte de généralité, considérer que les n valeurs prises en compte sont lesn premiers entiers positifs. La figure 6.3 montre les différents cas, pour n = 3.Nous constatons que les 6 permutations produisent 5 arbres de Catalan. Nousobservons également que le modèle aléatoire semble donner plus de poids aux

1. Rappelons que nous avons décidé de limiter en général le calcul de la complexité au casle pire.

Page 165: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 155

arbres équilibrés puisque deux permutations partagent le troisième arbre (celuiqui est le mieux équilibré). Si cette intuition est confirmée, cela se traduirait parle fait qu’il y a en moyenne plus d’arbres équilibrés que d’arbres non équilibrés.

•3, 2, 1

•3, 1, 2

• •

2, 1, 3

2, 3, 1

•1, 3, 2

•1, 2, 3

Figure 6.3 – Arbres de Catalan vs arbres aléatoires.La figure montre d’une part tous les arbres de trois nœuds qu’il estpossible d’obtenir et d’autre part comment se répartissent les 3! permu-tations possibles des 3 valeurs 1, 2, 3 sur les 5 arbres dans l’hypothèsed’une insertion aux feuilles.

Le modèle aléatoire est en général considéré comme le plus utile dans lapratique. C’est celui que nous retenons dans la suite pour évaluer la complexité.Deux types de méthodes sont possibles : les méthodes directes (cf. [40]) et lesméthodes indirectes comme [102, 103, 104] ou [75]. Notre calcul se situe dans lacatégorie des méthodes indirectes, il est inspiré de [102, 103, 104]. Le principeconsiste à calculer le nombre moyen de comparaisons C(n) pour construire unarbre de n nœuds. Il sera alors facile, en calculant la différence C(n+ 1)− C(n),de connaître le nombre moyen de comparaisons I(n) pour ajouter une n + 1e

valeur dans un arbre de n nœuds construit par insertion aux feuilles.La première valeur i est insérée à la racine. La probabilité que i soit la ie plus

petite valeur de l’intervalle 1 .. n est la même pour tout i. Les deux sous-arbresgauche et droit sont donc construits de la même façon avec un poids respectifde i − 1 et de n − i. Dans la suite nous supposons que la fonction eAjout_aest simplifiée afin de tenir compte de l’absence de doublons. Cette hypothèse n’apas d’incidence sur la complexité asymptotique. Construire un arbre de 0 nœudcoûte 0 comparaison. Au total, construire un arbre fini de n nœuds s’exprimepar l’équation récurrente suivante :⎧⎪⎨⎪⎩

C(0) = 0

C(n) = n− 1 + 1n·

n∑i=1

(C(i− 1) + C(n− i)) pour n > 0

Le terme n− 1 provient du fait qu’atteindre tout élément présent dans les sous-arbres exige au préalable de « passer par la racine », ce qui conduit à ajouter unecomparaison pour chacun des n − 1 nœuds présents dans les deux sous-arbres.La recherche d’une forme close pour C(n) débute par le développement suivant,qui exploite le fait que

∑ni=1 C(i− 1) =

∑ni=1 C(n− i) :

C(n) = n− 1 + 1n·

n∑i=1

(C(i− 1) + C(n− i))

Page 166: Structures de données et méthodes formelles ||

156 Structures de données et méthodes formelles

⇔ Remarque ci-dessus

C(n) = n− 1 + 2n·

n∑i=1

C(i− 1)

⇔ Multiplication des 2 membres par n

n · C(n) = n ·(n− 1) + 2 ·n∑

i=1

C(i− 1) (6.3.3)

À l’ordre n− 1, la formule 6.3.3 se réécrit :

(n− 1) · C(n− 1) = (n− 1) ·(n− 2) + 2 ·n−1∑i=1

C(i− 1) (6.3.4)

Remarquons par ailleurs que, pour n > 0,∑n

i=1 C(i−1) = C(n−1)+∑n−1i=1 C(i−1)

avant de retrancher membre à membre la formule 6.3.4 de 6.3.3 :⎧⎪⎪⎪⎪⎨⎪⎪⎪⎪⎩n · C(n) = n ·(n− 1) + 2 ·

n∑i=1

C(i− 1) −

(n− 1) · C(n− 1) = (n− 1) ·(n− 2) + 2 ·n−1∑i=1

C(i− 1)

⇔ Remarque ci-dessus, arithmétique et division par n.(n+ 1) pour n > 0C(n)n+ 1

= 2 · (n− 1)n ·(n+ 1) +

C(n− 1)n

(6.3.5)

qui est une récurrence d’ordre 1 sur laquelle nous pouvons appliquer la mé-thode des facteurs sommants. Celle-ci consiste à ajouter toutes les formules dutype 6.3.5 pour i situé dans l’intervalle 1 ..n et à simplifier. Nous obtenons alors :

C(n)n+ 1

= 2 ·n∑

i=1

(i− 1)i ·(i+ 1)

Avant de simplifier cette formule, nous pouvons rappeler d’une part que 1n ·(n+1) =

1n − 1

n+1 et d’autre part que la notation H(k) représente le nombre harmo-nique. H(k) est tel que H(k) =

∑ki=1

1i . On sait (cf. par exemple [43]) que

H(k) = ln(k) +O(1).

2 ·n∑

i=1

(i− 1)i ·(i+ 1)

= Arithmétique

2 ·(

n∑i=1

i

i ·(i+ 1) −n∑

i=1

1

i ·(i+ 1)

)= Identité remarquable ci-dessus

2 ·(

n∑i=1

1

i+ 1−

n∑i=1

1

i+

n∑i=1

1

i+ 1

)= Arithmétique

Page 167: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 157

4 ·n∑

i=1

1

i+ 1− 2 ·

n∑i=1

1

i

= Propriété de∑

, n > 0

4 ·(

n∑i=1

1

i− 1 +

1

n+ 1

)− 2 ·

n∑i=1

1

i

= Introduction de la notation H

2 ·H(n)− 4 + 4

n+ 1

Nous avons alors

C(n)n+ 1

= 2 ·H(n)− 4 + 4

n+ 1⇔ Arithmétique

C(n) = 2 ·(n+ 1) ·H(n)− 4 · n (6.3.6)

Le nombre moyen de comparaisons pour construire, par insertion aux feuilles,un arbre aléatoire de n nœuds est donc :

C(n) = 2 ·(n+ 1) ·H(n)− 4 · n

Ainsi que nous l’avons mentionné ci-dessus, il est facile d’en déduire le nombremoyen de comparaisons I(n) exigé par l’insertion aux feuilles d’une valeur dansun arbre de n nœuds. Ce nombre est donné par la formule C(n + 1) − C(n)qui s’interprète comme le nombre moyen de comparaisons pour construire parinsertion aux feuilles un arbre de n+1 valeurs à partir d’un arbre de n valeurs :

I(n)= Définition

C(n+ 1)− C(n)= Formule 6.3.62 ·(n+ 2) ·H(n+ 1)− 4 ·(n+ 1)− (2 ·(n+ 1) ·H(n)− 4 · n)

= H(n) = H(n+ 1)− 1

n+ 1

2 ·(n+ 2)·H(n+ 1)− 4·(n+ 1)− 2 ·(n+ 1)·(H(n+ 1)− 1

n+ 1

)+ 4 · n

= Arithmétique2 ·H(n+ 1)− 2

Le nombre moyen de comparaisons pour ajouter un élément à un arbre aléa-toire de n nœuds est donc :

I(n) = 2 ·H(n+ 1)− 2

Nous en déduisons que I(n) est en O(log n). Ce qui confirme que les arbresplutôt équilibrés sont plus nombreux que les arbres déséquilibrés.

Page 168: Structures de données et méthodes formelles ||

158 Structures de données et méthodes formelles

Calcul d’une représentation de l’opération eAjout_a : insertion à laracine par partitionnement

Certaines applications se caractérisent par le fait que beaucoup de valeursrecherchées sont parmi celles qui ont été introduites le plus récemment dansl’ensemble 2. Dans ce type de situation, puisque l’opération conserve près dusommet les valeurs qui s’y trouvaient déjà, il peut être intéressant de procéderà des insertions à la racine. Ci-dessous nous étudions une première façon deprocéder : en réalisant un partitionnement (aussi appelé coupure).

Le début du développement de l’opération eAjout_a se fait comme précé-demment. Nous repartons de la formule 6.3.1, page 152, soit A(a) ∪ {v}. À cestade du développement, nous constatons que si nous disposions de deux arbresl et r tels que :

– A(a) = A(l) ∪ A(r),– max(A(l)) < v et v < min(A(r)),

nous serions en mesure de réécrire l’expression 6.3.1 sous la forme :

A(l) ∪ {v} ∪ A(r)

pour aboutir, en exploitant la fonction d’abstraction, à A(〈g, v, d〉). À l’évidencecette solution ne s’applique que si v /∈ A(a). C’est sous cette hypothèse quenous débutons le développement. Il devient alors clair qu’il suffit de partitionnerl’arbre a en deux sous-arbres satisfaisant les conditions ci-dessus. Pour cela, nousproposons de développer la fonction auxiliaire part répondant à ces objectifs.Dans la mesure où la fonction de partitionnement délivre un couple d’arbres,nous devons définir une fonction d’abstraction auxiliaire A′ qui renvoie l’en-semble correspondant à un couple d’abr. Le type concret eabr s’enrichit de lamanière suivante :

concreteType eabr = · · ·...

auxiliaryAbstractionFunctionfunction A′((a, b)) ∈ eAbr × eAbr � ensAbst(N) = A(a) ∪ A(b)...

auxiliaryOperationSpecificationsfunction part(v, a) ∈ N× eAbr � eAbr × eAbr =pre

v /∈ A(a)then

(l, r) :

⎛⎝l, r ∈ eAbr × eAbr ∧

⎛⎝ A′((l, r)) = A(a)∧max(A(l)) < v ∧v < min(A(r))

⎞⎠⎞⎠end

end

2. Cette propriété est exploitée dans les antémémoires, avec une différence qui est que cequi se trouve dans une antémémoire est une duplication partielle du contenu d’une mémoireplus lente.

Page 169: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 159

Dans la spécification de l’opération part, la composante l du couple (l, r) est unabr quelconque contenant toutes les valeurs présentes dans a inférieures à v, tan-dis que la composante r est un abr quelconque contenant toutes les valeurs de asupérieures à v. Si nous parvenons à calculer une représentation (si possible effi-cace) de cette opération, nous serons en mesure de poursuivre le développementde l’opération eAjout_a de la manière suivante, en posant (l, r) = part(v, a) eten repartant de la formule 6.3.1 :

A(a) ∪ {v}= Spécification de part

A′((l, r)) ∪ {v}= Définition de A′ et propriété A.7

A(l) ∪ {v} ∪ A(r)= Définition de A

A(〈l, v, r〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée suivante :

v /∈ A(a) →let (r, l) := part(v, a) in

eAjout_a(v, a) = 〈l, v, r〉end

Si nous admettons qu’une fausse insertion ne provoque pas de changementdans a, le cas v ∈ A(a) est trivial. Il n’est pas développé. Au total, nous obtenonsla version suivante de l’opération eAjout_a :

function eAjout_a(v, a) ∈ N× eAbr→ eAbr =if v ∈ A(a) →

a| v /∈ A(a) →

let (r, l) := part(v, a) in〈l, v, r〉

endfi

Un raffinement supplémentaire est nécessaire afin de traduire les gardes. Ilpeut se fonder sur l’opération eApp(v, a). Nous nous intéressons à présent à lareprésentation de l’opération part dont le calcul débute par :

A′(part(v, a))= Propriété caractéristique

A(a) (6.3.7)

Nous poursuivons en réalisant une induction sur la structure de l’arbre a. Le casde base est trivial et conduit à l’équation gardée suivante :

a = 〈〉 →part(v, a) = (〈〉, 〈〉)

Page 170: Structures de données et méthodes formelles ||

160 Structures de données et méthodes formelles

Pour le cas inductif, puisque a = 〈〉, nous pouvons poser a = 〈l, n, r〉 pourrepartir de la formule 6.3.7 :

A(a)= Hypothèse

A(〈l, n, r〉)= Définition de A

A(l) ∪ {n} ∪ A(r) (6.3.8)

À ce stade du développement, il nous faut distinguer deux cas selon la positionrelative de n et de v. Les situations étant symétriques, nous nous restreignonsau cas v < n. Formulons l’hypothèse d’induction qui affirme que l’on sait parti-tionner l’arbre l par rapport à v et posons (l′, l′′) = part(v, l). Nous avons alors,d’après la spécification de l’opération part, A(l) = A(l′) ∪ A(l′′).

A(l) ∪ {n} ∪ A(r)= Spécification de part

A′(part(v, l)) ∪ {n} ∪ A(r)= Hypothèse

A′((l′, l′′)) ∪ {n} ∪ A(r)= Définition de A′

A(l′) ∪ A(l′′) ∪ {n} ∪ A(r)= Définition de A

A(l′) ∪ A(〈l′′, n, r〉)= Définition de A′

A′((l′, 〈l′′, n, r〉))

L’étape qui permet d’obtenir l’arbre 〈l′′, n, r〉 est légitime puisque tous les élé-ments de l′′ sont inférieurs à n. Le couple final satisfait bien toutes les contraintesde la spécification de l’opération part. L’élément v est bien supérieur à tout élé-ment de l′ et inférieur à tout élément de 〈l′′, n, r〉. D’où, d’après la propriété del’équation à membres identiques (page 67), la seconde équation gardée :

a = 〈l, n, r〉 →v < n →

let (l′, l′′) := part(v, l) inpart(v, a) = (l′, 〈l′′, n, r〉)

end

Le cas v > n se traite par symétrie. Compte tenu de la précondition de l’opérationpart, le cas v = n est à écarter. Au total, nous obtenons la représentation suivantede l’opération part :

Page 171: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 161

function part(v, a) ∈ N× eAbr � eAbr × eAbr =pre

v /∈ A(a)then

if a = 〈〉 →(〈〉, 〈〉)

| a = 〈l, n, r〉 →if v < n →

let (l′, l′′) := part(v, l) in(l′, 〈l′′, n, r〉)

end| v > n →

let (r′, r′′) := part(v, r) in(〈l, n, r′〉, r′′)

endfi

fiend

On montre (cf. [116]) que le nombre de comparaisons réalisé pour effectuerun partitionnement dans un arbre de poids n (n ≥ 1) est au moins de 1, au pirede n et (pour des arbres aléatoires) de 2 ·H(n+1)−2 en moyenne. Il s’en déduitque le coût moyen de l’insertion par partitionnement est en O(log n).

Calcul d’une représentation de l’opération eAjout_a : insertion à laracine par rotations

Il existe une autre façon de réaliser une insertion à la racine. Elle consisteà effectuer l’insertion aux feuilles comme nous l’avons fait dans la section 6.3.4,page 152, puis, en remontant le long du chemin de l’insertion, à itérer une rotationsimple (cf. section 3.5.2, page 91, pour une introduction aux rotations) – gaucheou droite selon que l’insertion aux feuilles s’est elle-même faite à gauche ou àdroite – de façon à placer la valeur insérée à la racine du sous-arbre considéré. Àl’issue du traitement, la valeur insérée se trouve bien à la racine de l’arbre initial.Cette méthode est proposée à l’exercice 6.3.1. Une technique similaire peut êtreutilisée lors de la recherche (opération eApp_a) pour amener la valeur trouvéeà la racine.

Calcul d’une représentation de l’opération eSupp_a

Le cas des fausses suppressions nous oblige à considérer que, dans l’opérationeSupp_a(v, a), a est un abr quelconque. Le calcul démarre avec l’expressionA(eSupp_a(v, a)).

A(eSupp_a(v, a))= Propriété caractéristique de l’opération eSupp_a

A(a)− {v} (6.3.9)

Page 172: Structures de données et méthodes formelles ||

162 Structures de données et méthodes formelles

Procédons à une induction sur la structure de a. Le cas de base (a = 〈〉) esttrivial. Il conduit à la première équation gardée suivante :

a = 〈〉 →eSupp_a(v, a) = 〈〉

Abordons l’étape inductive en posant a = 〈g, n, d〉. Repartons de la for-mule 6.3.9 :

A(a)− {v}= Hypothèse

A(〈g, n, d〉)− {v}= Définition de A(A(g) ∪ {n} ∪ A(d))− {v}

= Propriété A.17(A(g)− {v}) ∪ ({n} − {v}) ∪ (A(d)− {v}) (6.3.10)

Deux cas sont tout d’abord à considérer : v = n et v = n. Nous débutons parle cas v = n. L’absence de doublon garantit alors que A(g) ∩ {v} = ∅ et queA(d) ∩ {v} = ∅.

(A(g)− {v}) ∪ ({n} − {v}) ∪ (A(d))− {v})= Propriété A.16

A(g) ∪ ({n} − {v}) ∪ A(d)= Hypothèse et propriété A.18

A(g) ∪ ∅ ∪ A(d)= Propriété A.9

A(g) ∪ A(d) (6.3.11)

Si A(g) = ∅ (et donc si g = 〈〉) ou encore si A(d) = ∅ (soit si d = 〈〉) cetteexpression se simplifie et la solution est triviale. Par contre, si les abr g et dne sont pas vides, l’expression doit être reconfigurée afin qu’elle se présentesous la forme A(. . .). Trois sous-cas sont donc à considérer : g = 〈〉, d = 〈〉 etg = 〈〉 ∧ d = 〈〉. Débutons par le cas g = 〈〉.

A(g) ∪ A(d)= Hypothèse

A(〈〉) ∪ A(d)= Définition de A∅ ∪ A(d)

= Propriétés A.7 et A.23A(d)

En appliquant la propriété de l’équation à membres identiques (page 67), nousobtenons l’équation gardée suivante :

v = n →g = 〈〉 →

eSupp_a(v, 〈g, n, d〉) = d

Page 173: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 163

Le cas d = 〈〉 est symétrique. Reste à considérer le troisième sous-cas : g =〈〉 ∧ d = 〈〉. Il faut rechercher deux abr g′ et d′, et un entier naturel m tels que :1. A(g′) ∪ {m} ∪ A(d′) = A(g) ∪ A(d),2. max(A(g′)) < m ∧min(A(d′)) > m.

Nous serons alors à même d’appliquer la définition de A pour obtenirA(〈g′,m, d′〉), formule qui, via la propriété de l’équation à membres identiques(page 67), permettra de conclure. Puisque g = 〈〉, il existe dans g un plus grandélément capable de tenir le rôle de m. Soit, en repartant de la formule 6.3.11 :

A(g) ∪ A(d)= Propriété A.10(A(g)− {max(A(g))}) ∪ {max(A(g))} ∪ A(d)

= Propriété caractéristique de l’opération eSupp_aA(eSupp_a(max(A(g)), g)) ∪ {max(A(g))} ∪ A(d)

= Définition de AA(〈eSupp_a(max(A(g)), g),max(A(g)), d〉)

D’où l’équation gardée :

v = n →g = 〈〉 ∧ d = 〈〉 →

eSupp_a(v, 〈g, n, d〉) = 〈eSupp_a(max(A(g)), g),max(A(g)), d〉

En repartant de la formule 6.3.10, page ci-contre, il nous reste à prendre encompte le cas où v = n, qui se décompose en deux cas symétriques : v < n etv > n. Détaillons le premier cas. Puisque v < n, c’est donc que {n} ∩ {v} = ∅et que ({n} ∪ A(d)) ∩ {v} = ∅ :

(A(g)− {v}) ∪ ({n} − {v}) ∪ (A(d)− {v})= Propriété A.16(A(g)− {v}) ∪ {n} ∪ A(d)

= Propriété caractéristique de l’opération eSupp_aA(eSupp_a(v, g)) ∪ {n} ∪ A(d)

= Définition de AA(〈eSupp_a(v, g), n, d〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée suivante pour eSupp_a :

v < n →eSupp_a(v, 〈g, n, d〉) = 〈eSupp_a(v, g), n, d〉

Le cas v > n se traite aisément par symétrie. Au total, nous avons calculé lareprésentation suivante de l’opération eSupp_a :

function eSupp_a(v, a) ∈ N× eAbr→ eAbr =if a = 〈〉 →

〈〉| a = 〈g, n, d〉 →

if v = n →

Page 174: Structures de données et méthodes formelles ||

164 Structures de données et méthodes formelles

if g = 〈〉 →d

| d = 〈〉 →g

| g = 〈〉 ∧ d = 〈〉 →〈eSupp_a(max(A(g)), g),max(A(g)), d〉

fi| v < n →

〈eSupp_a(v, g), n, d〉| v > n →

〈g, n, eSupp_a(v, d)〉fi

fi

Cette version de l’opération eSupp_a est une version intermédiaire qui doitêtre raffinée afin de faire disparaître l’argument max(A(g)) au profit d’une ex-pression implantable. Parmi les solutions envisageables, citons en deux.1. Rendre disponible une opération auxiliaire concrète qui raffine l’opération

« abstraite » max et qui délivre la plus grande valeur présente dans un abrnon vide.

2. Renforcer le support en décomposant l’opération max sur l’abr. Le principede cette solution est appliqué à la section 6.5, page 187, dans le cas desarbres externes (voir aussi l’exercice 6.3.3, page 169).

La première solution présente l’inconvénient de descendre deux fois dansl’arbre g, une première fois pour y rechercher le plus grand élément et une se-conde fois pour le supprimer. La seconde est coûteuse en place mémoire puis-qu’elle exige de réserver de la place dans chaque nœud pour y accueillir le plusgrand élément de l’arbre. Nous allons emprunter une troisième voie qui écarte cesinconvénients sans en introduire de nouveaux. C’est celle qui consiste en quelquesorte à fusionner l’opération de recherche du plus grand élément et l’opérationde suppression du plus grand élément. Plus précisément, nous allons spécifierformellement, puis calculer, l’opération auxiliaire maxRac(a) qui, par des rota-tions simples, amène le plus grand élément de A(a) à la racine comme le montrel’exemple suivant :

13

10

8 12

21

18

15 19

25

24

13

10

8 12

25

21

18

1519

24

25

13

10

8 12

21

18

1319

24

Cette opération est spécifiée dans la rubrique auxiliaryOperationSpecifica-tions de la manière suivante :

Page 175: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 165

concreteType eabr = · · ·...

auxiliaryOperationSpecificationsfunction maxRac(a) ∈ eAbr �→ eAbr =pre

A(a) = ∅then

a′ : (a′ ∈ eAbr ∧ a′ = 〈g′,m, 〈〉〉 ∧ A(a′) = A(a))end

end

La formule a′ = 〈g′,m, 〈〉〉 précise que le sous-arbre droit de l’arbre résultat a′

est vide et donc, puisque c’est un eAbr, que m est le plus grand élément del’ensemble A(a). L’égalité A(a′) = A(a) spécifie que l’opération maxRac laisseinchangé l’ensemble des valeurs présentes dans l’arbre.

Une fois cette fonction mise en œuvre, l’expression〈eSupp_a(max(A(g)), g),max(A(g)), d〉 peut être remplacée par 〈g′,m, d〉et l’équation gardée dans laquelle apparaît cette expression devient :

v = n →g = 〈〉 ∧ d = 〈〉 →

let 〈g′,m, 〈〉〉 := maxRac(g) ineSupp_a(v, 〈g, n, d〉) = 〈g′,m, d〉

end

La représentation de l’opération eSupp_a se raffine et se simplifie en :

function eSupp_a(v, a) ∈ N× eAbr→ eAbr =if a = 〈〉 →

〈〉| a = 〈g, n, d〉 →

if v = n →if g = 〈〉 →

d| d = 〈〉 →

g| g = 〈〉 ∧ d = 〈〉 →

let 〈g′,m, 〈〉〉 := maxRac(g) in〈g′,m, d〉

endfi

| v < n →〈eSupp_a(v, g), n, d〉

| v > n →〈g, n, eSupp_a(v, d)〉

fifi

Page 176: Structures de données et méthodes formelles ||

166 Structures de données et méthodes formelles

Retour sur l’opération maxRac

Puisque A(a) = ∅, nous pouvons poser a = 〈l, w, r〉. Nous avons alors :

A(maxRac(a))= Spécification de maxRac

A(a)= Hypothèse

A(〈l, w, r〉) (6.3.12)

Procédons à une induction sur la structure de r en débutant par le cas de baser = 〈〉 :

A(〈l, w, r〉)= Hypothèse

A(〈l, w, 〈〉〉)

Nous pouvons appliquer la propriété de l’équation à membres identiques(page 67) puisque l’arbre 〈l, w, 〈〉〉 satisfait la spécification. Nous obtenons l’équa-tion gardée suivante :

let 〈l, w, r〉 := a inr = 〈〉 →

maxRac(a) = aend

Le cas inductif r = 〈〉 se développe comme suit à partir de la formule 6.3.12 :

A(〈l, w, r〉)= Définition de A

A(l) ∪ {w} ∪ A(r)= Spécification de maxRac

A(l) ∪ {w} ∪ A(maxRac(r))

Posons, conformément à la spécification, maxRac(r) = 〈l′,m, 〈〉〉 et poursuivonsle calcul :

A(l) ∪ {w} ∪ A(maxRac(r))= Hypothèse

A(l) ∪ {w} ∪ A(〈l′,m, 〈〉〉)= Définition de A

A(l) ∪ {w} ∪ A(l′) ∪ {m} ∪ A(〈〉)= Définition de A

A(〈l, w, l′〉) ∪ {m} ∪ A(〈〉)= Définition de A

A(〈〈l, w, l′〉,m, 〈〉〉)

Les deux dernières étapes reviennent à réaliser une rotation à gauche à la racine.En appliquant la propriété de l’équation à membres identiques (page 67), nousobtenons la seconde équation gardée :

Page 177: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 167

let 〈l, w, r〉 := a inr = 〈〉 →

let 〈l′,m, 〈〉〉 := maxRac(r) inmaxRac(a) = 〈〈l, w, l′〉,m, 〈〉〉

endend

Au total, nous avons calculé la version suivante de l’opération maxRac :

function maxRac(a) ∈ eAbr �→ eAbr =pre

A(a) = ∅then

let 〈l, w, r〉 := a inif r = 〈〉 →

a| r = 〈〉 →

let 〈l′,m, 〈〉〉 := maxRac(r) in〈〈l, w, l′〉,m, 〈〉〉

endfi

endend

On montre (cf. [116]) que la complexité moyenne de la suppression d’unevaleur dans un arbre de recherche aléatoire de poids n est 2 ·(1+1/n) ·H(n)−3.Asymptotiquement, le coût de la suppression est donc en O(log n). Cependantla suppression ne préserve pas le caractère aléatoire de l’arbre.

Représentation de l’opération eApp_a

Le calcul d’une représentation de l’opération eApp_a ne présente pas dedifficulté, il est laissé en exercice. Une solution possible est :

function eApp_a(v, a) ∈ N× eAbr � bool =if a = 〈〉 →

false

| a = 〈g, r, d〉 →if v = r →

true

| v < r →eApp_a(v, g)

| v > r →eApp_a(v, d)

fifi

Page 178: Structures de données et méthodes formelles ||

168 Structures de données et méthodes formelles

On montre (cf. [116]) que la complexité moyenne de la recherche positived’une valeur dans un arbre de recherche aléatoire de poids n est de 2 ·(H(n +1)−1) et, pour une recherche se terminant par un échec, de 2 ·(1+1/n) ·H(n)−3.Asymptotiquement, le coût moyen d’une recherche, quelle qu’en soit l’issue, estdonc en O(log n).

6.3.5 Conclusion et remarques bibliographiquesLes abr constituent la structure de base pour la représentation d’ensembles

de scalaires. Exception faite de la technique de hachage, toutes les autres misesen œuvre étudiées dans ce chapitre sont des extensions ou des variantes des abr.

Le principal avantage des abr est sa simplicité algorithmique. Un autre pointfort à ne pas négliger est qu’un abr est une structure adéquate pour réaliserdes tris de manière raisonnablement efficace. Concernant la représentation d’en-sembles, les abr constituent même la structure de prédilection à deux conditions :il faut d’une part qu’il n’y ait pas de suppressions et d’autre part que les n va-leurs insérées résultent d’un tirage aléatoire parmi les n! permutations possibles.C’est le cas idéal des abr aléatoires.

L’inconvénient majeur est un risque de performances dégradées quand (aumoins) l’une de ces deux conditions n’est pas satisfaite. La seconde condition aété étudiée ci-dessus. Le risque qu’elle soit violée n’est pas négligeable. Quant auproblème induit par les suppressions, il survient quand des séquences d’ajoutset de suppressions s’entrelacent (cf. [75], pages 431-435, pour une analyse de cetaspect).

Selon D. Knuth [75], la première description de l’insertion (aux feuilles) dansun abr est à porter au crédit de P.F. Windley, de A.D. Booth et A.J.T. Colin, etenfin de T.N. Hibbard. Ce dernier est aussi l’inventeur (en 1962) de la méthodede suppression fondée sur la recherche de la clé la plus proche, cette méthodeest voisine de celle calculée ci-dessus. La méthode d’insertion à la racine parpartitionnement est due à C.J. Stephenson [111] en 1980, la description originaleest purement itérative. D’autres méthodes de suppression que celle étudiée icisont possibles, comme par exemple la méthode de fusion (cf. exercice 6.3.5).

Le problème du maintien du statut d’arbre aléatoire en présence de suppres-sions est résolu dans les structures de données aléatoires que sont les treaps etabr randomisés (cf. section 6.9).

Exercices

Exercice 6.3.1 L’opération de rotation droite (rd) d’un arbre binaire de recherche est définiepar :

function rd(〈〈gg , vg , dg〉, v, d〉) ∈ eAbr→ eAbr = 〈gg , vg , 〈dg , v, d〉〉

La rotation gauche rg est l’opération duale de rd. On cherche à calculer une version del’opération d’insertion eAjout_a qui effectue une insertion à la racine par rotations.

1. Démontrer le théorème suivant :Théorème 5. Si a = 〈〈gg , vg , dg〉, v, d〉 alors :(a) rd(a) ∈ eAbr (la rotation droite préserve la propriété d’arbre binaire de re-

cherche).

Page 179: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 169

(b) A(a) = A(rd(a)) (la rotation droite préserve la structure abstraite).2. Disséquer l’insertion de la valeur 15 dans l’arbre binaire de recherche suivant :

23

17

10

5 14

12

20

19

31

27 37

34 41

Faire de même pour l’insertion de la valeur 19.3. Après avoir décidé d’une stratégie pour le cas des fausses insertions, calculer l’opération

eAjout_a.Suggestion. On effectue tout d’abord une insertion aux feuilles puis, par des rotations appro-priées, on remonte la valeur insérée jusqu’à la racine.

Exercice 6.3.2 Spécifier puis calculer une représentation de l’opération auxiliaire maxAbrqui délivre le plus grand élément d’un abr non vide.

Exercice 6.3.3 Appliquer le principe du renforcement du support par décomposition de l’opé-rateur max (cf. section 6.5, page 187, pour un exemple) sur l’abr pour calculer un raffinementde la version de l’opération eSupp_a obtenue à la page 164.

Exercice 6.3.4 Spécifier par abr les opérations abstraites complémentaires décrites dansl’exercice 6.2.2, page 149. On suppose en outre que les deux arbres à fusionner résultent d’unpartitionnement. Calculer une représentation de ces opérations. Suggestion pour l’opérationeUnion_a(a1, a2) : amener le plus grand élément de a1 à la racine puis enraciner a2.

Exercice 6.3.5 Soit a et b deux abr sans doublon tels que max(A(a)) < min(A(b)). Calculerl’opération fus_a(a, b) qui délivre un abr représentant l’ensemble A(a) ∪ A(b). En déduireune nouvelle version de l’opération de suppression.

Exercice 6.3.6 Le support eAbr est défini ci-dessus comme un arbre sans doublon. Il est pos-sible d’implanter le type abstrait ensabst en utilisant des abr pouvant présenter des doublons.Développer une version du type ensabst sur cette nouvelle base.

6.4 Méthodes de hachage

6.4.1 Introduction

Dans les méthodes étudiées jusqu’à présent, la place d’une clé est déterminéepar rapport à celle des clés déjà présentes dans l’ensemble. L’inconvénient quien résulte est que le temps d’accès pour la consultation ou pour la mise à jourest une fonction croissante du cardinal de l’ensemble.

Les techniques de hachage visent à supprimer – ou du moins à limiter – cetinconvénient. Elles se fondent sur l’hypothèse qu’il est préférable du point devue de la complexité temporelle de gérer un petit ensemble plutôt qu’un grand.

La technique de hachage que nous allons plus particulièrement détailler, ap-pelée hachage externe, se fonde sur un partitionnement de l’ensemble à gérer, desorte que l’essentiel du travail se fait sur une classe de la partition a priori plus

Page 180: Structures de données et méthodes formelles ||

170 Structures de données et méthodes formelles

petite que l’ensemble pris dans sa totalité. On a « haché » l’ensemble initial enplusieurs petits sous-ensembles, d’où le nom de ce type de technique 3.

Considérons l’ensemble N, que nous décidons de partitionner en trois classes,identifiées respectivement par les indices 0, 1 et 2. Considérons par ailleurs lesous-ensemble de clés {17, 28, 54, 127, 221, 241}. Il est facile de comprendre que sinous sommes capable, de manière efficace, d’associer à chacun de ces six entiersune classe de la partition, comme dans le schéma ci-dessous :

17

28

54

127

221

241

2

01

la recherche, l’ajout ou la suppression d’une de ces clés se fera dans un sous-ensemble en moyenne trois fois plus petit que l’ensemble initial.

Il est important de prendre conscience que, certes nous avons progressé vers letraitement de sous-ensembles plus petits, mais nous n’avons pris aucune décisionquant à la façon de mettre en œuvre ces sous-ensembles. Cette décision n’appar-tient pas à la méthode de hachage externe proprement dite. Nous devons, dansune phase de raffinement ultérieure, nous déterminer pour une méthode (incluantcelles étudiées ou mentionnées dans ce chapitre à l’exception de la méthode duvecteur caractéristique (cf. section 6.1), pour laquelle la contiguïté exige unecertaine proximité des valeurs) : listes, abr, Avl, B-arbres, arbres externes, voireune méthode de hachage.

La situation idéale du point de vue de la complexité serait celle qui attri-buerait une classe par clé. Cette solution n’est en général pas viable du pointde vue de l’occupation : elle reviendrait, à l’instar de la méthode du vecteurcaractéristique, à attribuer un emplacement à chaque clé possible.

Pour la technique du hachage externe introduite ci-dessus, nous devons nousarrêter sur deux questions :1. Comment associer à toute clé susceptible d’être présente dans l’ensemble

un indice qui identifie la classe de la partition ? C’est la question de lafonction de hachage.

2. Comment associer à chaque indice sa classe ? C’est la question de la tablede hachage.

Concernant la question de la fonction de hachage fh, l’efficacité de la méthodeest en partie liée à trois caractéristiques que doit posséder cette fonction :

3. Les libellés « adressage dispersé » ou « adressage associatif » sont des synonymes de« hachage » parfois employés dans la littérature.

Page 181: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 171

1. La fonction de hachage doit être facile (et rapide) à calculer afin de garantirque le surcoût occasionné par le partitionnement reste acceptable.

2. La fonction de hachage doit répartir uniformément les clés existantes surl’intervalle des indices de la partition. Comme en général le sous-ensemblede clés à gérer n’est pas connu à l’avance le mieux est de choisir une fonctionde hachage qui répartisse uniformément l’ensemble des clés potentielles.

3. La fonction de hachage doit être déterministe. Le cas échéant la recherched’appartenance pourrait se faire dans une classe différente de la classe oùs’est effectuée l’insertion.

Nous reviendrons largement sur ces propriétés et sur les différentes techniquesqui garantissent leur existence.

Concernant maintenant la question de la table de hachage t, la réponse estsuggérée par la question : la fonction qui associe à chaque indice une classe dela partition est une fonction totale surjective définie sur l’intervalle des indicesdes classes. C’est précisément la définition d’une table.

Nous pouvons à présent reprendre le schéma ci-dessus en le précisant :

Ainsi, si nous souhaitons insérer la clé v dans l’ensemble e, la technique dehachage externe étudiée ici consiste à insérer v dans le sous-ensemble t(fh(v)).

6.4.2 Définition du support concretDans la suite, nous considérons que ehach(m) est le type concret que nous

définissons. m, paramètre du type, est un entier positif et les indices des classesappartiennent à l’intervalle 0 .. m − 1. Nous rappelons par ailleurs que fh et tsont respectivement la fonction de hachage et la table de hachage.

t ∈ 0 .. m− 1→ F(N) ∧∀j ·(j ∈ 0 .. m− 1 ⇒ ∀v ·(v ∈ t(j)⇒ fh(v) = j))⇔

t ∈ eHach(m)

Cette définition nous affirme que (i) si t est une fonction totale de l’intervalle0 .. m − 1 sur l’ensemble des parties finies de N et si (ii) toutes les clés d’uneclasse t(j) ont comme valeur de hachage j, alors t est un élément de eHach(m).

Il est facile de montrer que la fonction fh induit un partitionnement ducodomaine de t (voir exercice 6.4.1).

17

28

54

127

221

241

2

01

0

1

2

fonction de hachage fh

table de hachage t

Page 182: Structures de données et méthodes formelles ||

172 Structures de données et méthodes formelles

Pour un t, t ∈ eHach(m) et pour une fonction de hachage fh donnés, chaquet(i) est un ensemble abstrait. Une conséquence prévisible est que, contrairementà ce que nous avons pu rencontrer jusqu’à présent, certaines des opérationsconcrètes que nous calculerons feront appel aux opérations abstraites correspon-dantes. Cela signifie, ainsi que nous l’avons déjà dit ci-dessus, qu’une décisionultérieure doit être prise quant au choix de la représentation concrète pour lesclasses de la partition.

6.4.3 Définition de la fonction d’abstractionLa fonction d’abstraction se définit facilement. Elle capte le fait que l’en-

semble abstrait représenté est l’union de tous les « petits » sous-ensembles consti-tuant la partition.

function A(t) ∈ eHach(m)→ ensAbst =⋃

j ·(j ∈ 0 .. m− 1 | t(j))

6.4.4 Spécification des opérations concrètesLa figure 6.4, page ci-contre, représente le type concret ehach(m) avec, en

particulier, la spécification des opérations concrètes ainsi que l’ébauche de lafonction de hachage.

6.4.5 Calcul de la représentation des opérations concrètesCalcul d’une représentation de l’opération eV ide_h

Le tableau {0 �→ ∅, 1 �→ ∅, . . . ,m− 1 �→ ∅} n’est pas vide puisque m ∈ N1.Chacun de ses éléments vaut ∅ (c’est par exemple le cas du m − 1e : {0 �→∅, 1 �→ ∅, . . . ,m − 1 �→ ∅}(m − 1) = ∅). Leur union est l’ensemble vide. Plusformellement :⋃

j ·(j ∈ 0 .. m− 1 | ((0 .. m− 1)× {∅})(j)) = ∅La démonstration de cette propriété est proposée à l’exercice 6.4.2.

A(eV ide_h())= Propriété caractéristique de l’opération eV ide_h∅

= Remarque ci-dessus et exercice 6.4.2⋃j ·(j ∈ 0 .. m− 1 | ((0 .. m− 1)× {∅})(j))

= Définition de AA((0 .. m− 1)× {∅})

D’où, d’après la propriété de l’équation à membres identiques (page 67), la re-présentation suivante pour l’opération eV ide_h :

function eV ide_h() ∈ eHach(m) = (0 .. m− 1)× {∅}

Ce résultat s’interprète en disant qu’un ensemble vide s’obtient en créant untableau dont tous les éléments désignent l’ensemble vide. La complexité de cetteopération est en O(m).

Page 183: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 173

concreteType ehach(m) = (eHach, (eV ide_h, eAjout_h, eSupp_h),(eApp_h, eEstV ide_h))

uses bool,N,N1constraints m ∈ N1

refines ensabst(N)support

t ∈ 0 .. m− 1→ F(N) ∧∀j ·(j ∈ 0 .. m− 1 ⇒ ∀v ·(v ∈ t(j)⇒ fh(v) = j))⇔

t ∈ eHach(m)abstractionFunction

function A(t) ∈ eHach(m)→ ensAbst = . . .operationSpecifications

function eV ide_h() ∈ eHach(m) =h : (h ∈ eHach(m) ∧ A(h) = eV ide())

;function eAjout_h(v, t) ∈ N× eHach(m)→ eHach(m) =h : (h ∈ eHach(m) ∧ A(h) = eAjout(v,A(t)))

;function eSupp_h(v, t) ∈ N× eHach(m)→ eHach(m) =h : (h ∈ eHach(m) ∧ A(h) = eSupp(v,A(t)))

...auxiliaryOperationRepresentations

function fh(v) ∈ N� 0 .. m− 1 = · · ·end

Figure 6.4 – Spécification du type concret ehach.Ce type concret implante le type abstrait ensabst(N) par une techniquede hachage externe. L’ensemble des clés possibles est partitionné enm sous-ensembles. Lors d’une recherche, il faut tout d’abord identifierle sous-ensemble concerné puis effectuer une recherche « classique » àl’intérieur de ce sous-ensemble.

Calcul d’une représentation de l’opération eAjout_h

A(eAjout_h(v, t))= Propriété caractéristique de l’opération eAjout_h

A(t) ∪ {v}= Définition de A⋃

j ·(j ∈ 0 .. m− 1 | t(j)) ∪ {v}

Nous pouvons en principe ajouter v dans n’importe quelle classe t(j), cependant,si nous souhaitons conserver invariante la propriété caractéristique du support,il est judicieux d’introduire v dans t(fh(v)).⋃

j ·(j ∈ 0 .. m− 1 | t(j)) ∪ {v}

Page 184: Structures de données et méthodes formelles ||

174 Structures de données et méthodes formelles

= Propriété A.14⎧⎨⎩⋃

j ·(j ∈ (0 .. m− 1) − {fh(v)} | ((0 .. m− 1)− {fh(v)} � t)(j))∪⋃j ·(j ∈ {fh(v)} | ({fh(v)}� t)(j)) ∪ {v}

Arrêtons-nous sur la seconde partie de cette formule.⋃j ·(j ∈ {fh(v)} | ({fh(v)}� t)(j)) ∪ {v}

= Propriété A.15[j := fh(v)](({fh(v)}� t)(j)) ∪ {v}

= Substitution({fh(v)}� t)(fh(v)) ∪ {v}

= Propriétés B.127 et C.17t(fh(v)) ∪ {v}

= Définition de l’opération eAjouteAjout(v, t(fh(v)))

= Propriété C.17{fh(v) �→ eAjout(v, t(fh(v)))}(fh(v))

= Substitution[j := fh(v)]{fh(v) �→ eAjout(v, t(fh(v)))}(j)

= Propriété A.15⋃j ·(j = fh(v) | {fh(v) �→ eAjout(v, t(fh(v)))}(j))

Avant d’intégrer ce résultat à la formule ci-dessus, posons s = t �− {fh(v) �→eAjout(v, t(fh(v)))}. La formule ci-dessus devient :⎧⎨⎩

⋃j ·(j ∈ (0 .. m− 1) − {fh(v)} | ((0 .. m− 1)− {fh(v)} � s)(j))∪⋃j ·(j ∈ {fh(v)} | ({fh(v)} � s)(j))

= Propriété A.14⋃j ·(j ∈ 0 .. m− 1 | s(j)})

= Définition de s et de la fonction d’abstraction AA(t�− {fh(v) �→ eAjout(v, t(fh(v)))})

D’où, d’après la propriété de l’équation à membres identiques (page 67), la re-présentation suivante pour l’opération eAjout_h :

function eAjout_h(v, t) ∈ N× eHach(m)→ eHach(m) =t�− {fh(v) �→ eAjout(v, t(fh(v)))}

Cette représentation s’interprète comme suit : pour ajouter l’élément v dansl’ensemble abstrait représenté par t, il suffit d’ajouter v dans l’ensemble abstraitdésigné par t(fh(v)).

Admettons que le nombre de comparaisons exigé par le calcul de la fonction dehachage soit négligeable (il est en général est faible et constant), que la fonctionde hachage distribue uniformément les clés, et que la gestion des classes se fassepar une opération eAjout_xx. Sous ces hypothèses, la complexité de l’opération

Page 185: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 175

eAjout_h est du même ordre que celle de eAjout_xx, mais avec un facteurmultiplicatif de 1

m . Ce facteur reflète le fait que l’ensemble initial a été « haché »en m sous-ensembles. La complexité au pire, qui survient lorsque la fonction dehachage délivre une constante, est celle de eAjout_xx avec cette fois un facteurmultiplicatif de 1.

Le calcul des autres opérations, et notamment celui de l’opération de sup-pression, est proposé en exercice (cf. exercice 6.4.3).

6.4.6 Fonction de hachage

Nous avons vu à la section 6.4.1 que la fonction de hachage doit satisfaire lesexigences suivantes :1. être facile à calculer,2. répartir de manière homogène les valeurs de hachage de l’ensemble sur les

m entrées de la table,3. être déterministe.

La littérature abonde de conseils, d’études et de résultats concernant le choixd’une bonne fonction de hachage (par exemple [40, 75, 7, 102, 104, 25]). L’unedes suggestions qui est régulièrement faite, et qu’il convient d’appliquer, est que,étant donné l’argument c de la fonction fh, cette dernière doit, lors de sonévaluation, utiliser tous les éléments binaires présents dans c. Le cas échéant, ily aurait un risque de ne pas garantir une répartition équitable des clés sur lesm sous-ensembles.

Une façon d’y parvenir – probablement la plus pratiquée – est de disposerd’une table de hachage dont la longueur m est un nombre premier et de prendrecomme fonction de hachage le reste de la division entière de l’argument c par m :fh(c) = c mod m. C’est ce que nous avons réalisé dans l’exemple de la page 170en prenant m = 3 comme indiqué ci-dessous :

17 = 5 · 3 + 228 = 9 · 3 + 154 = 18 · 3 + 0127 = 42 · 3 + 1221 = 72 · 3 + 2241 = 80 · 3 + 1

Dans le cas où c n’est pas un entier (mais par exemple une chaîne de caractères),il est possible de prendre en compte l’entier représenté par la chaîne de bitscorrespondante. Si la chaîne c se révèle trop longue pour représenter un entieren machine, on peut la compresser en la découpant en portions de longueurconvenable puis en composant (par exemple au moyen d’opérations de type « ouexclusif ») les différents fragments avant de procéder au calcul modulaire.

6.4.7 Autres méthodes de hachage

L’approche générique développée ci-dessus est qualifiée de hachage externe.Le lecteur aura compris l’origine de ce qualificatif : les éléments sont enregistrés àl’extérieur de la table de hachage. À l’inverse, les méthodes de hachage internes

Page 186: Structures de données et méthodes formelles ||

176 Structures de données et méthodes formelles

se caractérisent par le fait que les clés sont enregistrées dans la table elle-même,qui se présente non plus comme une fonction à valeurs dans F(N) mais unefonction à valeurs dans N.

La première conséquence du choix d’un hachage interne est le problème descollisions : la fonction de hachage fh n’étant pas, par nature, injective, que fait-on d’une clé c2 si t(fh(c2)) = c1, c2 devant en principe venir se placer dans uneentrée de la table déjà occupée par une clé c1 ? En supposant que la table n’estpas pleine, il s’agit de trouver un emplacement libre pouvant être occupé parc2 (et pour lequel c2 deviendrait un « squatter »). Les méthodes se distinguentselon la façon de trouver un emplacement libre pour c2. Deux types d’approchesont en compétition :

– L’approche linéaire où l’on recherche en séquence (modulo m) un empla-cement libre. L’un des inconvénients de cette approche est le risque d’ac-cumulation (clustering) à partir de la position fh(c1) pour peu que l’em-placement suivant (fh(c1) + 1) soit occupé par une clé « légitime ». Parailleurs, ce risque d’accumulation est d’autant plus important que le tauxd’occupation de la table est élevé : on a tout intérêt à surestimer la taillede la table 4. Un autre inconvénient, partagé par toutes les méthodes in-ternes, est celui lié à la suppression : un emplacement qui devient libresuite à une suppression doit être considéré comme occupé mais sans valeursignificative pour la recherche par contre, pour une opération d’insertion,il est vraiment considéré comme libre.

– L’approche par double hachage vise à éviter le clustering. Pour cela, elleimpose que le pas de recherche d’un emplacement libre dépende à la fois dela clé c2 faisant l’objet de la recherche et du nombre d’étapes de recherchedéjà réalisé. Par ailleurs, il faut garantir, malgré le caractère variable dupas de recherche, que toutes les positions de la table de hachage sont acces-sibles. L’approche par double hachage fait l’hypothèse que l’on dispose :(i) d’une fonction de hachage classique, fh, (ii) d’une seconde fonctionde hachage fh′ surjective sur l’intervalle 1 .. m − 1. La suite de fonctionssi(c) = (fh(c) + fh′(c) ·(i− 1)) mod m est telle qu’à la première tentativeon essaie la position s1(c) = fh(c) mod m, à la seconde, la position s2(c) =(fh(c)+ fh′(c)) mod m, à la troisième s3(c) = (fh(c)+2 · fh′(c)) mod m,etc. La valeur 0 doit être exclue du codomaine de la fonction fh′. Le caséchéant, la suite de fonctions si se réduirait à si(c) = fh(c) mod m qui nedépend pas de i. En cas de collision, cette suite conduirait à une absence determinaison de l’algorithme. On montre que la suite si(c) définie ci-dessuslimite le clustering en nombre et en taille, et que, si m est premier, toutesles valeurs de l’intervalle 0 .. m− 1 sont atteintes en m étapes.

Une troisième méthode, appelée hachage dynamique, proposée en 1978 parP.-Å. Larson [78] et classée le plus souvent dans les techniques de hachage, relèveplutôt des « tries ». Elle est présentée dans la section consacrée à cette structurede données (cf. section 7.1, page 273).

4. Ce qui constitue une forme de compromis espace/temps.

Page 187: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 177

6.4.8 Conclusion et remarques bibliographiques

Comparées aux méthodes arborescentes (abr, Avl, B-arbres, etc.), les mé-thodes de hachage présentent l’avantage de l’efficacité. Elles n’exigent pas nonplus que l’ensemble soit doté d’une structure d’ordre. Par contre, elles interdisentd’enrichir le type abstrait par une opération de tri ou d’accès séquentiel. Les fonc-tions de hachage peuvent être utilisées à chaque fois que l’on souhaite associer àune clé une valeur ayant un comportement proche de l’aléatoire (cf. section 6.9.6pour une application aux treaps randomisés).

Si l’on considère les différentes méthodes de hachage, le hachage externeprésente beaucoup d’avantages : taille dynamique de l’ensemble (non limité parla taille de la table de hachage), facilité des suppressions (qui en fait est reportésur la gestion secondaire des classes). Son principal inconvénient est d’exiger desopérations secondaires indépendantes des opérations primaires, ce qui nécessiteun double travail de conception.

A priori hachage et programmation fonctionnelle ne font pas bon ménage :une recopie entière du tableau représentant la table est exigée à chaque opération.Nous verrons cependant, au chapitre 10, qu’il existe des mises en œuvre detableaux qui peuvent tempérer ce défaut.

L’idée du hachage doit être attribuée à deux équipes indépendantes de lacompagnie ibm, en 1953. L’une avait comme mission l’écriture d’un assembleurpour la machine ibm 701. Cette équipe comprenait celui qui allait devenir l’un desplus célèbres architectes de la compagnie, Gene M. Amdahl, qui après avoir quittéibm en 1970 allait créer sa propre compagnie, Amdahl Corporation. Cependant,la première diffusion publique d’une technique de hachage (due à A.I. Dumey)ne date que de 1956.

Exercices

Exercice 6.4.1 Montrer que si la fonction de hachage fh est une fonction totale, la définitiondu support du type ehach induit un partitionnement de l’ensemble abstrait considéré.

Exercice 6.4.2 Pour n ∈ N, démontrer la propriété suivante :

⋃j ·(j ∈ 0 .. n | ((0 .. n)× {∅})(j)) = ∅

Suggestion : utiliser la propriété A.15 pour effectuer une induction.

Exercice 6.4.3 Après avoir calculé la représentation des opérations non développées ci-dessus(eSupp_h, eApp_h et eEstV ide_h), compléter le raffinement en choisissant une mise enœuvre (liste non triée, liste triée, abr, Avl, B-arbre, etc.) pour la représentation des classes dela partition.

Exercice 6.4.4 Spécifier le hachage linéaire (cf. page ci-contre). Calculer la représentationfonctionnelle des opérations.

Exercice 6.4.5 Spécifier pour le hachage externe les opérations abstraites complémentairesdécrites dans l’exercice 6.2.2, page 149. Calculer une représentation de ces opérations.

Page 188: Structures de données et méthodes formelles ||

178 Structures de données et méthodes formelles

6.5 Méthodes arborescentes élémentaires :les arbres externes de recherche

À la page 96, nous avons défini les arbres externes binaires. Dans cette sectionnous allons étudier comment – moyennant l’ajout de la caractéristique « arbrede recherche » – il est possible d’utiliser ces arbres pour mettre en œuvre le typeabstrait ensabst sur un ensemble totalement ordonné. A priori ce type d’arbrene présente que des inconvénients par rapport aux arbres totalement étiquetés.Il faut en effet s’attendre à des complexités moyennes supérieures puisque l’in-formation utile se trouve sur les feuilles. Outre le fait que les algorithmes sont engénéral plus simples à calculer, le principal avantage qu’il est possible d’en retirerest que la recherche d’un élément ne s’encombre pas des informations auxiliaires(attributs) qui sont en général associées à une clé. L’argument vaut principale-ment pour les structures enregistrées sur supports auxiliaires, pour lesquels lecoût de transfert vers ou depuis la mémoire principale est critique.

6.5.1 Définition du support concret

Rappelons qu’informellement un arbre externe binaire fini est tel que toutnœud interne possède exactement deux descendants (ce sont des arbres complets)et que les valeurs sont situées aux feuilles. Superposer à ces propriétés la qualitéd’arbre de recherche signifie que pour tout nœud interne les valeurs contenuesdans le sous-arbre gauche sont inférieures à celles contenues dans le sous-arbredroit. Formellement, le support concret ainsi obtenu, eAe, se décrit de la manièresuivante :

1) 〈〉 ∈ eAe2) n ∈ N ⇒ 〈n〉 ∈ eAe3) g ∈ eAe− {〈〉} ∧ d ∈ eAe− {〈〉} ∧ (6.5.1)max(A(g)) < min(A(d)) (6.5.2)

⇒〈g, d〉 ∈ eAe

Le conjoint 6.5.1 précise que tout nœud interne possède exactement deuxdescendants tandis que le conjoint 6.5.2, en utilisant la fonction d’abstraction Aqui convertit un tel arbre en un ensemble, formalise le fait qu’il s’agit d’un arbrede recherche.

L’arbre externe de recherche suivant :

〈〈〈〈4〉, 〈7〉〉, 〈〈10〉, 〈〈〈15〉, 〈20〉〉, 〈24〉〉〉〉, 〈〈27〉, 〈〈30〉, 〈35〉〉〉〉

se représente graphiquement par :

Page 189: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 179

4 7

10 •

15 20

24

27 •

30 35

6.5.2 Définition de la fonction d’abstraction

La fonction d’abstraction A décrit comment un arbre externe représente unensemble. L’arbre vide représente l’ensemble vide, une feuille n représente l’en-semble {n}, enfin un arbre quelconque représente l’union des sous-ensemblesmatérialisés par les sous-arbres gauche et droit.

function A(a) ∈ eAe� ensAbst(N) =if a = 〈〉 →∅

| a = 〈n〉 →{n}

| a = 〈g, d〉 →A(g) ∪ A(d)

fi

Théorème 6 (des arbres externes binaires de recherche). Soit a = 〈g, d〉 ∈ eAeet v ∈ N.

1. v ≤ max(A(g))⇒ v /∈ A(d),2. v ≥ min(A(d))⇒ v /∈ A(g).

Ce théorème établit que si une valeur v est inférieure ou égale (resp. supérieureou égale) à la plus grande valeur du sous-arbre gauche (resp. à la plus petitevaleur du sous-arbre droit), elle n’appartient pas au sous-arbre droit (resp. ausous-arbre gauche). Sa démonstration est laissée en exercice.

6.5.3 Spécification des opérations

La spécification du type concret eae limitée aux deux opérations concrètesd’ajout et de suppression est présentée à la figure 6.5, page suivante. Elle cor-respond au raffinement du type abstrait ensabst(N).

6.5.4 Calcul de la représentation des opérations concrètes

Le calcul de eAjout_ae va nous permettre de nous focaliser sur la ques-tion suivante – qui se pose également dans le développement de l’opérationeSupp_ae : comment, à partir d’un nœud interne, savoir s’il faut se diriger

Page 190: Structures de données et méthodes formelles ||

180 Structures de données et méthodes formelles

concreteType eae = (eAe, (eV ide_ae, eAjout_ae, eSupp_ae),(eApp_ae, eEstV ide_ae))

usesbool,N

refines ensabst(N)support

1) 〈〉 ∈ eAe2) n ∈ N ⇒ 〈n〉 ∈ eAe3) g ∈ eAe− {〈〉} ∧ d ∈ eAe− {〈〉} ∧max(A(g)) < min(A(d))

⇒〈g, d〉 ∈ eAe

abstractionFunctionfunction A(a) ∈ eAe� ensAbst(N) = . . .

operationSpecifications...

function eAjout_ae(v, a) ∈ N× eAe→ eAe =b : (b ∈ eAe ∧ A(b) = eAjout(v,A(a)))

;function eSupp_ae(v, a) ∈ N× eAe→ eAe =b : (b ∈ eAe ∧ A(b) = eSupp(v,A(a)))

...end

Figure 6.5 – Spécification du type concret eae.Il s’agit d’un spécification concrète du type ensabst de la figure 6.1,page 149. Le support concret est un arbre externe de naturels. La fonc-tion d’abstraction est détaillée page précédente.

vers le sous-arbre gauche ou vers le sous-arbre droit ? La technique utilisée esttypique de notre démarche (cf. sections 1.10 et 2.4) : nous supposons disponibleune certaine fonction (en l’occurrence ici la fonction qui délivre le plus grandélément d’un arbre externe non vide). Nous vérifions que cette fonction est bienO(1)-décomposable (cf. page 188). Le développement se déroule en utilisant cettefonction. Au moment du raffinement final, un champ est ajouté à la structure dedonnées. Il est destiné à représenter la valeur de la fonction pour chaque nœudde l’arbre considéré.

Calcul d’une représentation de l’opération eAjout_ae

A(eAjout_ae(v, a))= Propriété caractéristique de l’opération eAjout_ae

A(a) ∪ {v} (6.5.3)

Pour poursuivre, nous procédons à une induction structurelle sur l’arbre a. Lecas a = 〈〉 est trivial et conduit à la première équation gardée :

Page 191: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 181

a = 〈〉 →eAjout_ae(v, a) = 〈v〉

Pour le second cas de base, a = 〈n〉, nous repartons de la formule 6.5.3ci-dessus :

A(a) ∪ {v}= Hypothèse

A(〈n〉) ∪ {v}= Définition de A

A(〈n〉) ∪ A(〈v〉)

Trois cas sont à considérer selon la position relative de n et de v : n = v, n < vet n > v. Si n = v, nous avons :

A(〈n〉) ∪ A(〈v〉)= Définition de A

{n} ∪ {v}= Hypothèse et propriété A.9

{n}= Définition de A

A(〈n〉)

Soit encore A(a) d’après l’hypothèse. D’où l’équation gardée :

a = 〈n〉 →n = v →

eAjout_ae(v, a) = a

Si n < v, nous avons :

A(〈n〉) ∪ A(〈v〉)= Définition de A

A(〈〈n〉, 〈v〉〉)

D’où l’équation gardée :

a = 〈n〉 →v > n →

eAjout_ae(v, a) = 〈〈n〉, 〈v〉〉

Le cas v < n est symétrique.Le cas inductif a = 〈g, d〉 se fonde sur l’hypothèse d’induction qui affirme

que nous savons insérer une valeur v dans le sous-arbre g aussi bien que dans lesous-arbre d. Nous repartons de la formule 6.5.3 ci-dessus.

A(a) ∪ {v}= Hypothèse

A(〈g, d〉) ∪ {v}= Définition de A

A(g) ∪ A(d) ∪ {v}

Page 192: Structures de données et méthodes formelles ||

182 Structures de données et méthodes formelles

A priori il est possible d’insérer v soit dans le sous-arbre g soit dans le sous-arbred. Cependant, il faut nous assurer que le conjoint 6.5.2 de la troisième clausede la définition du support (cf. page 178) est satisfait. Pour cela, nous pouvonsdistinguer les deux cas v ≤ max(A(g)) et v > max(A(g)). Considérons le casv ≤ max(A(g)).

A(g) ∪ A(d) ∪ {v}= Propriété A.7(A(g) ∪ {v}) ∪ A(d)

= Propriété caractéristique de l’opération eAjout_aeA(eAjout_ae(v, g)) ∪ A(d)

= Définition de AA(〈eAjout_ae(v, g), d〉)

D’où l’équation gardée :

a = 〈g, d〉 →v ≤ max(A(g)) →

eAjout_ae(v, a) = 〈eAjout_ae(v, g), d〉

Le cas v > max(A(g)) se traite facilement par symétrie. Nous obtenons :

function eAjout_ae(v, a) ∈ N× eAe→ eAe =if a = 〈〉 → /*vraie insertion*/

〈v〉| a = 〈n〉 →

if v = n → /*fausse insertion*/a

| v > n → /*vraie insertion à droite*/〈〈n〉, 〈v〉〉

| v < n → /*vraie insertion à gauche*/〈〈v〉, 〈n〉〉

fi| a = 〈g, d〉 →

if v ≤ max(A(g)) → /*insertion à gauche*/〈eAjout_ae(v, g), d〉

| v > max(A(g)) → /*insertion à droite*/〈g, eAjout_ae(v, d)〉

fifi

Pour le calcul de complexité, nous allons procéder comme nous l’avons faità la section 6.3.4, page 152, en passant par le calcul préalable de la complexitémoyenne C(n) de la construction d’un arbre externe de n valeurs (de n feuillesdonc), puis en calculant par différence la complexité moyenne I(n) de l’insertiond’une valeur dans un arbre externe de n valeurs. La construction se fait selon lemodèle des arbres aléatoires déjà utilisé à la section 6.3.4 (dans un arbre de nvaleurs différentes, les n! permutations sont équiprobables).

Page 193: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 183

La première valeur i est insérée à la racine. La probabilité que i soit la ie pluspetite valeur de l’intervalle 1 .. n est la même pour tout i. Les deux sous-arbresgauche et droit sont donc construits de la même façon avec un nombre de feuillesrespectif de i et de n−i. Dans la suite, nous supposons que la fonction eAjout_aeest simplifiée afin de tenir compte de l’absence de doublons. Cette hypothèse n’apas d’incidence sur la complexité asymptotique. Construire un arbre d’un seulnœud coûte une comparaison. Au total, le coût moyen de la construction d’unarbre fini de n valeurs s’exprime par l’équation récurrente suivante :⎧⎪⎨⎪⎩

C(1) = 1

C(n) = n− 1 + 1

n− 1 ·n−1∑i=1

(C(i) + C(n− i)) pour n > 1

Le terme n− 1 provient du fait que pour toutes les insertions, sauf la première,il faut ajouter une comparaison pour tenir compte du fait qu’il est nécessaired’évaluer une condition au niveau de la racine. Par ailleurs, puisque n > 1 etqu’il s’agit d’arbres complets, l’insertion ne se fait jamais dans un sous-arbrevide, ce qui justifie les bornes de la quantification ainsi que son facteur 1

n−1 .La recherche d’une forme close pour C(n) se fait, comme à la section 6.3.4,

en trois étapes. La première est la recherche d’une équation récurrente d’ordre 1pour C(n). Pour cela, nous exploitons d’une part le fait que ∑n−1

i=1 (C(i) + C(n−i)) = 2 ·∑n−1

i=1 C(i) et d’autre part que, pour n−1 ≥ 1 (soit n ≥ 2),∑n−1

i=1 C(i) =∑n−2i=1 C(i) + C(n− 1). Nous avons alors, pour n ≥ 2 :

C(n) = n− 1 + 1

n− 1 ·n−1∑i=1

(C(i) + C(n− i))

⇔ Première remarque ci-dessus

C(n) = n− 1 + 2

n− 1 ·n−1∑i=1

C(i)

⇔ Arithmétique

(n− 1) · C(n) = (n− 1)2 + 2 ·n−1∑i=1

C(i) (6.5.4)

⇔ Seconde remarque ci-dessus

(n− 1) · C(n) = (n− 1)2 + 2 ·n−2∑i=1

C(i) + 2 · C(n− 1) (6.5.5)

À l’ordre n− 1, la formule 6.5.4 s’écrit :

(n− 2) · C(n− 1) = (n− 2)2 + 2 ·n−2∑i=1

C(i) (6.5.6)

Retranchons membre à membre 6.5.6 de 6.5.5 :

(n− 1) · C(n)− (n− 2) · C(n− 1) = (n− 1)2 − (n− 2)2 + 2 · C(n− 1)⇔ Arithmétique

Page 194: Structures de données et méthodes formelles ||

184 Structures de données et méthodes formelles

(n− 1) · C(n) = 2 · n− 3 + n · C(n− 1)⇔ Division par n ·(n− 1) (n ≥ 2)

C(n)n

=2 · n− 3n ·(n− 1) +

C(n− 1)n− 1

D’où (seconde étape) nous déduisons, par la méthode des facteurs sommants :

C(n)n

=n∑

i=2

2 · i− 3i ·(i− 1) + 1 pour n ≥ 1

Pour la troisième étape, et de même qu’à la section 6.3.4, nous exploitonsl’identité remarquable 1

n ·(n−1) =1

n−1 − 1n :

C(n)n

= Arithmétique

2 ·n∑

i=2

1

i− 1 − 3 ·n∑

i=2

1

i ·(i− 1) + 1

= Identité remarquable

2 ·n∑

i=2

1

i− 1 − 3 ·n∑

i=2

1

i− 1 + 3 ·n∑

i=2

1

i+ 1

= Arithmétique

−n∑

i=2

1

i− 1 + 3 ·n∑

i=2

1

i+ 1

= Changement de variable

−n−1∑i=1

1

i+ 3 ·(

n∑i=1

1

i− 1) + 1

Nous introduisons le nombre harmonique H(k) (qui est tel que H(k) =∑k

i=11i ) :

−n−1∑i=1

1

i+ 3 ·(

n∑i=1

1

i− 1) + 1

= Notation−H(n− 1) + 3 ·H(n)− 2

= Propriété de H(n) pour n > 1−H(n− 1) + 3 ·(H(n− 1) + 1

n )− 2= Arithmétique

2 ·H(n− 1) + 3n− 2

En multipliant chaque membre par n nous obtenons :

C(n) = 2 · n ·H(n− 1) + 3− 2 · n

Nous pouvons alors calculer le coût moyen de l’insertion I(n) en évaluantl’expression C(n+ 1)− C(n). Nous obtenons :

Page 195: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 185

I(n) = 2 ·H(n− 1) + 2n

Puisque H(k) = ln(k) + O(1) (cf. section 6.3.4), nous en déduisons que le coûtmoyen de l’insertion est en O(log n). Le coût le meilleur est en O(1). Il est parexemple atteint quand on insère 1 dans un arbre dans lequel on a déjà insérésuccessivement les n − 1 valeurs de l’intervalle 2 .. n. Le coût le pire est enO(n). Il est atteint quand on insère n dans un arbre dans lequel on a déjà insérésuccessivement les n− 1 valeurs de l’intervalle 1 .. n− 1.

Calcul d’une représentation de l’opération eSupp_ae

A(eSupp_ae(v, a))= Propriété caractéristique de l’opération eSupp_ae

A(a)− {v} (6.5.7)

À nouveau nous procédons à une induction sur la structure de a. Débutonspar le cas a = 〈〉.

A(a)− {v}= Hypothèse et définition de A∅− {v}

Nous avons déjà rencontré une situation semblable lors du calcul de l’opérationeSupp_a (cf. section 6.3.4, page 161). Nous obtenons l’équation gardée :

a = 〈〉 →eSupp_ae(v, a) = 〈〉

Abordons à présent le cas a = 〈n〉.

A(a)− {v}= Hypothèse et définition de A

{n} − {v} (6.5.8)

Il nous faut procéder à une analyse par cas, en distinguant les deux cas n = vet n = v. Si v = n, nous avons :

{n} − {v}= Hypothèse et propriété A.18∅

= Définition de AA(〈〉)

qui conduit à l’équation gardée suivante :

a = 〈n〉 →n = v →

eSupp_ae(v, a) = 〈〉

Page 196: Structures de données et méthodes formelles ||

186 Structures de données et méthodes formelles

Le cas n = v se traite de manière analogue en repartant de la formule 6.5.8 :

{n} − {v}= Hypothèse et propriété A.16

{n}= Définition de A

A(〈n〉)

Soit encore A(a) d’après l’hypothèse. D’où l’équation gardée :

a = 〈n〉 →n = v →

eSupp_ae(v, a) = a

Le cas inductif a = 〈g, d〉 se traite comme suit, en repartant de la formule 6.5.7ci-dessus :

A(a)− {v}= Hypothèse a = 〈g, d〉

A(〈g, d〉)− {v}= Définition de A et propriété A.17(A(g)− {v}) ∪ (A(d)− {v})

Deux cas sont à considérer, v ≤ max(A(g)) et v > max(A(g)). Débutons parle cas v ≤ max(A(g)) (nous savons alors, d’après le théorème 6, page 179, quev /∈ A(d)) :

(A(g)− {v}) ∪ (A(d)− {v})= Propriété A.16 et théorème 6(A(g)− {v}) ∪ A(d)

= Propriété caractéristique de l’opération eSupp_aeA(eSupp_ae(v, g)) ∪ A(d) (6.5.9)

À ce stade nous ne pouvons cependant pas utiliser aveuglément la fonction d’abs-traction car le support exige qu’aucun des deux arbres ne soit vide. Nous ensommes sûr pour d, par contre, il faut procéder à une analyse par cas poureSupp_ae(v, g). Considérons tout d’abord le cas eSupp_ae(v, g) = 〈〉.

A(eSupp_ae(v, g)) ∪ A(d)= Hypothèse

A(〈〉) ∪ A(d)= Définition de A et propriétés A.7 et A.9

A(d)

D’où l’équation gardée :

a = 〈g, d〉 →v ≤ max(A(g)) →

let r := eSupp_ae(v, g) inr = 〈〉 →

eSupp_ae(v, a) = dend

Page 197: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 187

Le second cas, eSupp_ae(v, g) = 〈〉, se fonde sur le cas général de la fonctiond’abstraction. Nous obtenons facilement l’équation gardée :

a = 〈g, d〉 →v ≤ max(A(g)) →

let r := eSupp_ae(v, g) inr = 〈〉 →

eSupp_ae(v, a) = 〈r, d〉end

Le cas v > max(A(g)) s’obtient par symétrie. Au total, nous avons calculé lareprésentation suivante de l’opération eSupp_ae(v, a) :

function eSupp_ae(v, a) ∈ N× eAe→ eAe =if a = 〈〉 → /*fausse suppression*/

〈〉| a = 〈n〉 →

if v = n → /*vraie suppression*/〈〉

| v = n → /*fausse suppression*/a

fi| a = 〈g, d〉 →

if v ≤ max(A(g)) → /*suppression à gauche*/let r := eSupp_ae(v, g) in

if r = 〈〉 →d

| r = 〈〉 →〈r, d〉

fiend

| v > max(A(g)) → /*suppression à droite*/...

fifi

Ainsi qu’il était prévisible, l’algorithme de suppression est plus simple que dansle cas des abr. En effet, contrairement aux abr, toutes les valeurs utiles sontsituées aux feuilles. La question du devenir des sous-arbres du nœud supprimé nese pose pas. Dans l’hypothèse où l’évaluation des gardes contenant l’expressionmax(A(. . .)) coûte une comparaison, le coût moyen de la suppression est enO(log(n)). Le coût le meilleur est en O(1) tandis que le coût le pire est en O(n).

6.5.5 Renforcement du support par décomposition de lafonction max

Les représentations des opérations eAjout_ae et eSupp_ae calculées ci-dessous ne peuvent être laissées en l’état. La raison est que la fonction max

Page 198: Structures de données et méthodes formelles ||

188 Structures de données et méthodes formelles

Fonctions décomposables

Considérons par exemple les arbres eAbr définis dans le support dutype eavl (cf. section 6.6.2, page 192). À l’exception des arbres vides(〈〉) ces arbres présentent trois champs (〈g, n, d〉) : un champ sous-arbregauche g, un champ sous-arbre droit d et un troisième champ n, de typeentier naturel. Soit T un type quelconque ; une fonction f ∈ eAbr → T estdite O(1)-décomposable sur eAbr (cf. [60, 61, 68]) s’il existe une opération⊕ ∈ T → T dont la complexité temporelle est en O(1) telle que

f(〈g, n, d〉) = f(g)⊕ f(d)

Ainsi par exemple la fonction w qui délivre le poids d’un arbre binaire(c’est-à-dire le nombre de nœuds présents dans l’arbre, cf. section 3.5.2)est O(1)-décomposable puisque l’opération ⊕, représentée ici par l’addi-tion +, se comporte en O(1).

L’avantage de travailler avec une fonction O(1)-décomposable est qu’ilest possible de faire abstraction de sa mise en œuvre jusqu’au moment deschoix d’implantation, où il suffit d’enrichir la représentation d’un nœudpar un champ supplémentaire destiné à contenir la valeur de la fonc-tion pour ce nœud (ou permettant d’y accéder aisément). Il s’agit d’uneopération intitulée « décomposition d’une fonction sur une structure dedonnées ». Toute mise à jour se fait en appliquant simplement la fonction⊕ avec comme argument le nouveau champ des nœuds fils.

Cette technique est à la base des algorithmes de programmation dy-namique. Nous l’appliquons également lors de la recherche de solutionsefficaces pour le type abstrait « tableaux fortement flexibles » (cf. sec-tion 10.5), ainsi que dans les raffinements utilisant les arbres externes.

utilisée dans ces représentations conduit à des calculs trop coûteux puisqu’ilsobligent à descendre jusqu’à une feuille à chaque évaluation.

Nous avons affirmé ci-dessus, lors du calcul de l’opération eAjout_ae, quenous pouvions différer la résolution du problème posé en renforçant le supportgrâce au caractère O(1)-décomposable de la fonction max. C’est le moment d’yrevenir. L’évaluation de max(A(g)) délivre la plus grande valeur du sous-arbregauche d’un arbre eAe. Or la fonction max appliquée à un nœud interne 〈g, d〉d’un arbre eAe est telle que

max(A(〈g, d〉)) = max(A(d))

max est donc O(1)-décomposable. Nous pouvons modifier le support concret eny ajoutant un champ qui représente la plus grande valeur présente dans l’arbre.Sur l’exemple de la page 178, introduire cette modification revient à disposer del’arbre suivant (sur le schéma, seuls les nœuds internes sont modifiés, concernantles feuilles, la valeur du nouveau champ est celle initialement présente dans lenœud) :

Page 199: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 189

35

24

7

4 7

24

10 24

20

15 20

24

35

27 35

30 35

La nature de l’arbre facilite la définition du nouveau support : d’une part unarbre 〈g, d〉 n’a jamais de sous-arbre vide et d’autre part la plus grande valeurest toujours dans le sous-arbre droit.

1) 〈〉 ∈ eAe′

2) n ∈ N ⇒ (〈n〉, n) ∈ eAe′

3) g ∈ eAe′ − {〈〉} ∧ d ∈ eAe′ − {〈〉} ∧max(A(g)) < min(A(d)) ∧m = max(A(d))

⇒(〈g, d〉,m) ∈ eAe′

La fonction d’abstraction est modifiée en conséquence. Son utilité étant à pré-sent réduite, la nouvelle version n’est pas présentée. Sur le plan de la conceptiondes algorithmes, la modification est mineure et n’exige pas de refaire le calculdes opérations. Nous présentons ci-dessous la nouvelle version de l’opérationeAjout_ae. Le cas des autres opérations est laissé en exercice.

function eAjout_ae(v, a) ∈ N× eAe′→ eAe′ =if a = 〈〉 →

(〈v〉, v)| a = (〈n〉, n) →

if v = n →a

| v > n →(〈〈n〉, 〈v〉〉, v)

| v < n →(〈〈v〉, 〈n〉〉, n)

fi| a = (〈g, d〉,m) →

Page 200: Structures de données et méthodes formelles ||

190 Structures de données et méthodes formelles

let (l,mg) := g inif v ≤ mg →(〈eAjout_ae(v, g), d〉 ,m )

| v > mg →(〈g, eAjout_ae(v, d)〉 ,max({v,m}) )

fiend

fi

Une vraie adjonction au niveau des feuilles conduit à créer un nœud interne.La valeur du nouveau champ pour ce nœud dépend de la position relative dela feuille et de la valeur ajoutée v. Concernant l’ajout dans un nœud interne,l’adjonction à gauche n’a pas d’impact sur le nouveau champ, par contre, pourl’adjonction à droite, une mise à jour est nécessaire si la valeur ajoutée v est laplus grande du nouvel arbre.

Remarque. Nous avons dérogé au principe consistant à enregistrer la valeurde la fonction à décomposer dans un champ de la structure, puisque nous enregis-trons max(A(a)) et non max(A(g)). Mais si nous voulions véritablement placerla valeur max(A(g)) dans un nouveau champ de 〈g, d〉, nous devrions (pour res-ter efficace) enregistrer également la valeur de max(A(d)). En effet, ainsi que lemontre la figure ci-dessous, qui reprend l’arbre de la page précédente mais avecstrictement la valeur du sous-arbre gauche placée à chaque nœud interne, en casde suppression de la valeur 24, il serait nécessaire de remplacer la valeur 24 dela racine par la nouvelle plus grande valeur du sous-arbre gauche, soit 20, valeurqui n’est pas accessible en temps constant.

24

7

4

4 7

10

10 20

15

15 20

24

27

27 30

30 35

6.5.6 Conclusion et remarques bibliographiquesLa technique des arbres externes pour représenter des sous-ensembles de Z est

originale et peu pratiquée sous cette forme. Son coût est en général légèrementsupérieur à celui des abr. Il suffit pour s’en convaincre de comparer les valeurs del’insertion moyenne I(n) dans chacun des cas. Mais, outre le fait que les arbresexternes constituent une base sur laquelle s’appuyer pour réaliser d’excellentsexercices sur les structures de données, le principe présente des avantages lorsqu’il

Page 201: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 191

s’agit de distinguer la partie « index » de la partie « données » dans une structureenregistrée sur deux niveaux de mémoire (mémoire vive et disque par exemple).De plus les suppressions sont facilitées par rapport aux arbres classiques puisque,par construction, la valeur à éliminer est toujours située sur une feuille. Nousverrons également que l’idée peut être exploitée avec profit pour la mise en œuvrede tableaux fortement flexibles (cf. section 10.5) ou d’une variante des B-arbres.

La technique utilisée ci-dessus, consistant à réaliser un premier développe-ment par arbres externes stricts, puis à raffiner explicitement en renforçant lesupport par décomposition d’une information utile sur la structure de données,a été proposée initialement par A. Kaldewaij et V.J. Dielissen [68]. Cependantle principe de la décomposition est bien antérieur et est utilisé plus ou moinsconsciemment, par exemple pour la mise en œuvre des B+-arbres. Voir aussi[116] pour un autre exemple concernant les minimiers de position.

Exercices

Exercice 6.5.1 Lors de l’étude des abr, nous nous sommes intéressés à différentes formes d’in-sertions outre l’insertion aux feuilles. Ceci n’a pas lieu d’être dans le cas des arbres externes derecherche. Pourquoi ? Nous pouvons tout de même nous poser la question du partitionnementd’un ensemble en deux sous-ensembles par rapport à une valeur donnée v.

1. Spécifier, au niveau du type abstrait, l’opération de partitionnement.2. Calculer une représentation de l’opération dans le cas d’une mise en œuvre par arbres

externes.

Exercice 6.5.2 Spécifier l’opération max puis calculer sa représentation max_ae dans le casd’une mise en œuvre par arbres externes.

6.6 Méthodes équilibrées : les Avl

6.6.1 IntroductionL’utilisation d’un arbre binaire de recherche ou d’un arbre externe de n

feuilles pour représenter un ensemble ne garantit pas que la complexité des opé-rations ne dépassera pas O(log n). Comment obtenir cette assurance ? L’idéalserait de disposer toujours d’un arbre p-équilibré (équilibré en poids) pour le-quel la recherche s’effectue en O(log n). L’inconvénient qui en résulte est que laconservation de cette propriété (très forte pour un abr) lors d’une mise à jourest techniquement difficile et entraîne une complexité supérieure à O(log n).

L’idée qui sous-tend cette section est de conserver la notion d’abr tout enlui superposant une forme affaiblie d’équilibre compatible avec des mises à jourefficaces (c’est-à-dire en O(log n)).

Dans le cas d’arbres n-aires quelconques, deux types de solutions existentselon que l’affaiblissement s’effectue en « largeur » ou en « hauteur ».

– En largeur : on admet un nombre variable de fils par nœud en optant pourdes :– arbres 2-3,– arbres 2-3-4,

Page 202: Structures de données et méthodes formelles ||

192 Structures de données et méthodes formelles

– B-arbres (cf. section 6.7),– etc.

– En hauteur : on admet un déséquilibre borné (par rapport à l’équilibreidéal : le p-équilibre). On peut retenir un arbre de recherche h-équilibré(équilibré en hauteur). C’est la solution Avl.

Le principe de base des Avl consiste à maintenir invariante, sur tous lesnœuds de l’arbre, la propriété d’équilibre suivante : « la différence de rayonentre le sous-arbre gauche et le sous-arbre droit ne dépasse jamais 1 en valeurabsolue. »

Traditionnellement, en programmation impérative, la mise en œuvre des opé-rations de mise à jour se fait selon une discipline « modification in situ » en in-tégrant dans chaque nœud, non pas le rayon mais la différence entre les rayons.Lors d’une insertion, un paramètre de sortie signale à l’appelant si l’opération aou non provoqué une augmentation du rayon. Si c’est le cas et que ceci conduità violer la propriété d’équilibre, une opération de rééquilibrage (rotation simpleou double) est appliquée.

Nous adoptons ici une démarche différente, qui tend à ne pas faire de choixprématurés. C’est en particulier le cas en ce qui concerne le mode d’exploitationdu rayon (cf. [47], ainsi que [28] pour une approche similaire). Pour l’algorithmed’insertion eAjout_v, le résultat obtenu présente des originalités par rapport àl’algorithme traditionnel 5 dans la mesure où, grâce au caractère persistant desstructures de données fonctionnelles, il est possible de connaître simultanémentle rayon d’un arbre avant et après l’insertion (le paramètre de sortie mentionnéplus haut devient inutile).

6.6.2 Définition et propriétés du support concret

Nous allons ci-dessous spécifier et représenter le type eavl, de support eAvl,qui raffine par Avl le type abstrait ensabst appliqué aux entiers naturels. UnAvl est un abr équilibré en hauteur. Formaliser le support correspondant d’unepart exige de définir ce qu’est un abr (cf. section 6.3, page 150) et d’autre part,puisque la hauteur n’est en toute rigueur pas définie pour un arbre vide (cf. sec-tion 3.5.2), de préférer l’usage de la fonction r qui délivre le rayon d’un arbrebinaire. Tout le développement est fait en considérant que cette fonction r estdisponible. Au stade de la mise en œuvre, après avoir constaté que l’invocationfréquente de la fonction r est rédhibitoire sur le plan de la complexité tempo-relle et après s’être assuré de son caractère O(1)-décomposable (cf. sections 1.10et 2.4, et encadré page 188), nous décidons de renforcer le support en décompo-sant cette fonction sur la structure de données afin que l’accès à cette informations’effectue simplement en consultant le nouveau champ.

Un Avl étant un arbre binaire de recherche respectant une contrainte liée aurayon, nous renvoyons le lecteur à la définition du support des abr, section 6.3.1(voir également la rubrique auxiliarySupports de la figure 6.6, page 197). Lesupport eAvl d’un Avl se définit inductivement par :

5. Il est cependant de même complexité asymptotique temporelle.

Page 203: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 193

1) 〈〉 ∈ eAvl2) 〈g, n, d〉 ∈ eAbr ∧ g ∈ eAvl ∧ d ∈ eAvl ∧ r(g)− r(d) ∈ −1 .. 1

⇒〈g, n, d〉 ∈ eAvl

La clause 2) formalise la condition qu’il faut imposer à un abr pour être aussiun Avl. Le conjoint r(g) − r(d) ∈ −1 .. 1 rend compte du fait que l’arbre estéquilibré en hauteur.

Trois exemples sont présentés ci-dessous. Tous trois concernent des abr, maisseuls les deux premiers sont desAvl. La valeur d’équilibre en hauteur est apposéeà chaque nœud : +1 (resp −1) pour un déséquilibre en faveur du sous-arbregauche (resp. droit), 0 pour un nœud équilibré. Concernant le troisième arbre,le (seul) nœud en défaut d’équilibre Avl est désigné par une flèche grisée.

23+1

17+1

10−1

50 14+1

120

20+1

190

31−1

270 370

340 410

Un Avl

12−1

7−1

40 8−1

110

22−1

15−1

170

30−1

270 31−1

340Un Avl

190

10+1

5−1

30 8+1

70

140

110 160

27−2

230 34+1

300

290 320

380

Un arbre abr qui n’est pas un Avl

Les contraintes imposées aux arbres h-équilibrés permettent de déterminer leslimites entre lesquelles varie le rayon d’un Avl. Nous avons le théorème suivant :

Théorème 7 (Adelson-Velsky et Landis). Soit n le poids d’un arbre h-équilibréet r son rayon.

log(n+ 1) ≤ r < 1, 4403 · log(n+ 1) (6.6.1)

Si nous parvenons à démontrer ce théorème 6, nous saurons en particulier quepour un arbre h-équilibré, son rayon est en O(log n) (et même en Θ(log n)) avecde surcroît un facteur multiplicatif proche de 1. Nous aurons la certitude que

6. Rappelons que par convention log exprime un logarithme à base 2.

Page 204: Structures de données et méthodes formelles ||

194 Structures de données et méthodes formelles

la recherche dans un Avl est toujours très efficace et qu’il est donc inutile denous lancer dans un calcul de complexité moyenne. Par contre, rien ne garantita priori qu’il existe des algorithmes de mise à jour permettant de préserver lapropriété d’équilibre ni, si c’était bien le cas, que ces algorithmes sont eux-mêmesen O(log n).

Démontrons à présent la première inégalité de la propriété 6.6.1. Quels sontles arbres h-équilibrés qui, pour un rayon r donné, possèdent un nombre denœuds maximum ? Ce sont les arbres pleins (cf. page 89). Un tel arbre satisfaitl’équation récurrente suivante, dans laquelle p′(r) est le poids d’un arbre pleinde rayon r :{

p′(0) = 0p′(r) = p′(r − 1) + p′(r − 1) + 1 pour r > 0

En effet, le poids d’un arbre vide (de rayon 0) est 0 et par ailleurs la secondeformule rend compte du fait que les deux sous-arbres d’un arbre plein sont eux-mêmes des arbres pleins. La solution de cette équation s’obtient facilement parla méthode des facteurs sommants : p′(r) =

∑r−1i=0 2

i, soit encore p′(r) = 2r − 1.Et donc tout arbre h-équilibré de rayon r est tel que son poids n est plus petit ouégal à celui de l’arbre plein de même hauteur : n ≤ p′(r). D’où le développementsuivant :

n ≤ p′(r)⇔ Calcul ci-dessus

n ≤ 2r − 1⇔ Arithmétique

n+ 1 ≤ 2r⇔ Propriété du loglog(n+ 1) ≤ r

Ce qui établit la première inégalité de la formule 6.6.1.

Pour démontrer la seconde inégalité de la formule, nous utilisons une ap-proche séduisante par sa simplicité, inspirée de [26]. Quels sont les arbresh-équilibrés qui, pour un rayon donné r, possèdent un nombre minimum denœuds ? Ce sont des arbres dans lesquels tout nœud (à l’exception des feuilles)présente un déséquilibre de +1 ou de −1. En effet, supprimer une feuille dans untel arbre soit diminue son rayon soit augmente le déséquilibre d’un nœud et faitperdre à l’arbre sa propriété de h-équilibre. Si p′′(r) est le poids d’un tel arbreet r son rayon, p′′(r) satisfait l’équation récurrente suivante :⎧⎨⎩p′′(0) = 0

p′′(1) = 1p′′(r) = p′′(r − 1) + p′′(r − 2) + 1 pour r > 1

En effet, le poids d’un arbre vide est 0, celui d’un arbre de rayon 1 est 1. Latroisième formule rend compte du fait que dans un tel arbre les deux sous-arbressont de même nature, que l’un a un rayon de r − 1 et l’autre un rayon de r − 2.

Lemme 1. Soit φ =1 +

√5

2. Pour n ≥ 2 :

Page 205: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 195

φn = φn−1 + φn−2 (6.6.2)

La démonstration (par récurrence) est laissée en exercice. La valeur φ est appeléenombre d’or (cf. [122] par exemple pour de plus amples développements sur lespropriétés de ce nombre) et est approximativement égale à 1, 6180. D’autre partφ est tel que 1, 4402 < 1

log φ < 1, 4403.

Lemme 2. Pour tout r ≥ 0 :

p′′(r) ≥ φr − 1 (6.6.3)

La démonstration se fait par récurrence sur r. Posons P = p′′(r) ≥ φr − 1.Compte tenu de la forme de l’équation récurrente pour p′′ nous prenons commeproposition à démontrer P ∧ [r := r + 1]P . Le principe de récurrence simple(cf. théorème 2, page 44) nous conduit alors à démontrer :1. l’étape de base [r := 0](P ∧ [r := r + 1]P ),2. l’étape inductive [r := r + 1](P ∧ [r := r + 1]P ) sous les hypothèses r ∈ N

et P ∧ [r := r + 1]P .Le cas de base est simple à démontrer :

[r := 0](P ∧ [r := r + 1]P )⇔ Substitution[r := 0]P ∧ [r := 1]P

⇔ Définition de P et substitutionp′′(0) ≥ φ0 − 1 ∧ p′′(1) ≥ φ1 − 1

⇔ Définition de p′′ et substitution0 ≥ 1− 1 ∧ 1 ≥ φ− 1

⇔ Définition de φ et calcul sur R+

Concernant l’étape inductive de la démonstration, les hypothèses sont d’une partr ∈ N et d’autre part (hypothèse d’induction) P ∧ [r := r+1]P , tandis que nousdevons démontrer [r := r + 1](P ∧ [r := r + 1]P ) :

[r := r + 1](P ∧ [r := r + 1]P )= Définition de la substitution et arithmétique[r := r + 1]P ∧ [r := r + 2]P

Nous constatons que le premier facteur à démontrer est déjà en hypothèse, il suffitdonc de démontrer [r := r + 2]P , soit encore p′′(r + 2) ≥ φr+2 − 1. Débutons lecalcul avec p′′(r + 2) :

p′′(r + 2)= Définition de p′′ (r ∈ N)

p′′(r + 1) + p′′(r) + 1≥ Propriété 6.6.3

φr+1 − 1 + φr − 1 + 1= Calcul sur R+ et propriété 6.6.2

φr+2 − 1

Page 206: Structures de données et méthodes formelles ||

196 Structures de données et méthodes formelles

Cette inégalité vaut pour un arbre h-équilibré ne contenant aucun nœud interneéquilibré. Pour un arbre h-équilibré quelconque de poids n nous avons n ≥p′′(r) ≥ φr − 1. D’où :

φr − 1 ≤ n⇔ Calcul sur R+

φr ≤ n+ 1⇔ Propriété du logφ

r ≤ logφ(n+ 1)⇔ Propriété du log

r ≤ log(n+ 1)log φ

⇒ Valeur de 1log φ et calcul sur R+

r < 1, 4403 · log(n+ 1)

Le théorème est prouvé. Nous pouvons donc affirmer que le rayon d’un arbreh-équilibré (et donc d’un Avl) ne fait jamais plus de 45% de plus que la hauteurde son homologue p-équilibré.

6.6.3 Définition de la fonction d’abstractionAlors que jusqu’à présent les fonctions d’abstraction rencontrées avaient

comme domaine le support du type considéré, nous sommes contraint cette foisde déroger à cette règle. En effet, lors des mises à jour, l’arbre manipulé, tout enrestant un abr, peut momentanément ne plus être un Avl. Il faut malgré toutraisonner sur la structure abstraite qu’il représente. C’est pourquoi nous retrou-vons ici la fonction d’abstraction A déjà rencontrée dans la section portant surla représentation des ensembles par abr (cf. page 151).

function A(a) ∈ eAbr � ensAbst(N) =if a = 〈〉 →∅

| a = 〈g, n, d〉 →A(g) ∪ {n} ∪ A(d)

fi

Notons que A est surjective : tout élément de ensAbst(N) peut être représentépar un arbre eAbr. Il en est de même de sa restriction au support eAvl. Parailleurs sa corestriction à ∅ est injective (la seule solution à l’équation A(x) = ∅est x = 〈〉).

6.6.4 Spécification des opérations concrètesLa figure 6.6, page ci-contre, synthétise les principales informations sur la

spécification du type eavl. Le nom des opérations dérive du nom des opéra-tions abstraites par ajout du suffixe _v. La fonction auxiliaire r, qui délivre lerayon d’un arbre binaire, est supposée disponible telle qu’elle a été définie à lasection 3.5.2.

Page 207: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 197

concreteType eavl = (eAvl, (eV ide_v, eAjout_v, eSupp_v),(eApp_v, eEstV ide_v))

uses bool,Nrefines ensabst(N)auxiliarySupports

1) 〈〉 ∈ eAbr2) n ∈ N ∧ g ∈ eAbr ∧ d ∈ eAbr ∧ max(A(g)) < n ∧ min(A(d)) > n

⇒〈g, n, d〉 ∈ eAbr

support1) 〈〉 ∈ eAvl2) 〈g, n, d〉 ∈ eAbr ∧ g ∈ eAvl ∧ d ∈ eAvl ∧ r(g)− r(d) ∈ −1 .. 1

⇒〈g, n, d〉 ∈ eAvl

abstractionFunctionfunction A(a) ∈ eAbr � ensAbst(N) = . . .

operationSpecifications...

function eAjout_v(v, a) ∈ N× eAvl→ eAvl =b : (b ∈ eAvl ∧ A(b) = eAjout(v,A(a)))

;function eSupp_v(v, a) ∈ N× eAvl→ eAvl =b : (b ∈ eAvl ∧ A(b) = eSupp(v,A(a)))

...end

Figure 6.6 – Spécification du type concret eavl.Il s’agit d’un spécification concrète du type ensabst de la figure 6.1,page 149. Cette spécification exige un support auxiliaire puisque la fonc-tion d’abstraction est définie sur les abr, et non sur les Avl. La fonctiond’abstraction est détaillée page ci-contre.

6.6.5 Rotations

À la section 3.5.2, page 94, nous avons étudié le principe des rotations ap-pliquées aux arbres binaires. Notre motivation première était la préservation duparcours infixé. Nous avons cependant mentionné d’autres usages dont certainssont en relation avec les Avl. C’est le moment d’y revenir.

Cette section est organisée de la manière suivante. Nous revenons toutd’abord sur la définition de la rotation droite 7 pour un abr (et donc pour unAvl) en rappelant la propriété de l’invariance du parcours infixé. Nous nousfocalisons ensuite sur les propriétés des rotations appliquées aux Avl, selon lecontexte d’utilisation.

7. La rotation gauche se définit se manière similaire et possède des propriétés analogues.

Page 208: Structures de données et méthodes formelles ||

198 Structures de données et méthodes formelles

Rotation simple droite

L’opération de rotation droite rd introduite à la section 3.5.2, page 91, estprésentée ci-dessous sous sa forme monolithique pour des abr :

function rd(〈g, u, d〉) ∈ eAbr �→ eAbr =pre

g = 〈〉then

let 〈gg, ug, dg〉 := g in〈gg, ug, 〈dg, u, d〉〉

endend

Théorème 8. Soit a ∈ eAbr, a = 〈〈gg, ug, dg〉, u, d〉 alors A(a) = A(rd(a)) (larotation droite préserve la structure abstraite).

La démonstration de ce théorème et des théorèmes 9, 10, 11 et 12 est l’objet del’exercice 6.6.1, page 215.

Le contexte d’application de l’opération rd que nous considérons est celuioù l’arbre présente un déséquilibre de 2 en faveur du sous-arbre gauche (soitr(g)− r(d) = 2). Nous verrons que c’est la valeur maximale que peut atteindrele déséquilibre lors d’une mise à jour. L’arbre considéré n’est alors plus unAvl. Sila seule entorse à la propriété d’être un Avl se limite à ce déséquilibre de 2, il estpossible de rétablir l’équilibre par une rotation. Trois sous-cas de rotation droitedoivent alors être envisagés selon le propre déséquilibre de g. Ils correspondentaux trois théorèmes qui suivent.

Théorème 9. Soit a ∈ eAbr, a = 〈g, u, d〉, g ∈ eAvl, d ∈ eAvl, r(g)− r(d) = 2,g = 〈gg, ug, dg〉 et r(gg) = r(dg) + 1. Alors :

1. rd(a) ∈ eAvl (la rotation droite rétablit l’équilibre Avl),2. r(rd(a)) = r(a) − 1 (la rotation droite fait diminuer de 1 le rayon de

l’arbre).

Le schéma ci-dessous illustre cette situation ainsi que le résultat de l’applica-tion de l’opération rd. Cette situation se caractérise par le fait que le déséquilibreà la racine est de 2 et que le déséquilibre du sous-arbre gauche est du même signe.L’arbre de racine ug ainsi que les trois arbres gg, dg et d sont supposés être desAvl. Le rayon des arbres gg, dg et d est noté en bas des rectangles les maté-rialisant, et la valeur d’équilibre est apposée à chaque nœud. Le résultat de larotation est représenté dans la partie droite du schéma. L’arbre est devenu unAvl, son rayon diminue de 1.

Page 209: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 199

Le rôle des schémas en spécification

Si l’on considère la situation des schémas en tant qu’outil de repré-sentation de concepts (et notamment de structures de données), les in-formaticiens se classent selon deux catégories : les « doctrinaires » et les« pragmatiques ». Les premiers considèrent que, puisqu’un schéma ne re-présente jamais qu’une situation (et non un ensemble de situations), leurutilisation est trompeuse : ils sont donc à proscrire dans toute modélisa-tion. E.W. Dijkstra [30] (1930-2002) était un ardent défenseur de ce pointde vue.

À l’inverse, les « pragmatiques » considèrent que dans toute démarchede développement le point de départ est une description informelle (pou-vant contenir des schémas) et que, même après avoir formalisé l’applica-tion, la description initiale ne doit pas être rejetée, car elle présente encoreun intérêt (au moins pour faciliter la compréhension du problème). J.-R.Abrial, à travers les cours dispensés à l’iut de Nantes [4], montre qu’ilest un tenant de ce point de vue. Nous nous plaçons également dans cettecatégorie.

ggdg

d

ug 1

u 2

k

k − 1k − 1

Avant rotation

ggdg d

ug 0

u 0

k k − 1 k − 1

Après rotation

Abordons maintenant le cas où le sous-arbre gauche est équilibré (r(gg) =r(dg)).

Théorème 10. Soit a ∈ eAbr, a = 〈g, u, d〉, g ∈ eAvl, d ∈ eAvl, r(g)−r(d) = 2,g = 〈gg, ug, dg〉 et r(gg) = r(dg). Alors :

1. rd(a) ∈ eAvl (la rotation droite rétablit l’équilibre Avl),2. r(rd(a)) = r(a) (la rotation droite ne change pas le rayon de l’arbre).

Le schéma ci-dessous illustre ce théorème. Nous verrons que ce théorèmene s’applique pas dans le cas d’une adjonction (puisque le sous-arbre excéden-taire est toujours déséquilibré). Par contre, il peut s’appliquer dans le cas d’unesuppression.

Page 210: Structures de données et méthodes formelles ||

200 Structures de données et méthodes formelles

gg dg

d

ug 0

u 2

k k

k − 1

Avant rotation

gg

dgd

ug -1

u 1

k

k

k − 1

Après rotation

Le dernier cas, qui se caractérise par un sous-arbre gauche déséquilibré enfaveur de la droite, est pris en compte par le théorème suivant.

Théorème 11. Soit a ∈ eAbr, a = 〈g, u, d〉, g ∈ eAvl, d ∈ eAvl, r(g)−r(d) = 2,g = 〈gg, ug, dg〉 et r(gg) = r(dg)− 1. Alors rd(a) /∈ eAvl (l’arbre résultant de larotation n’est pas un Avl).

Le schéma ci-dessous illustre informellement ce théorème.

ggdg

d

ug -1

u 2

k − 1k

k − 1

Avant rotation

gg

dgd

ug -2

u 1

k − 1

k

k − 1

Après rotation

Cette situation peut survenir aussi bien dans le cas d’une adjonction que danscelui d’une suppression. La rotation simple n’est donc pas une solution. Il fautnous tourner vers une rotation double.

Rotation double gauche-droite

La rotation gauche-droite rgd utilisée dans la gestion des Avl se définitcomme suit (cf. section 3.5.2 pour une présentation générale de la rotationgauche-droite) :

function rgd(〈〈gg, ug, dg〉, u, d〉) ∈ eAbr �→ eAbr =pre

r(〈gg, ug, dg〉)− r(d) = 2 ∧ gg = 〈〉then

rd(〈rg(〈gg, ug, dg〉), u, d〉)end

Page 211: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 201

La précondition implique que le sous-arbre gauche n’est pas vide. Le théorèmesuivant montre que, dans le cas d’un déséquilibre de 2 de la racine en faveur dusous-arbre gauche, lorsqu’il est impossible de rééquilibrer par une rotation simplerd alors une rotation double rgd permet le rééquilibrage Avl ; en outre l’arbrediminue de rayon.

Théorème 12 (De la rotation gauche-droite des Avl). Soit a = 〈g, u, d〉, a ∈eAbr, g = 〈gg, ug, dg〉, g ∈ eAvl, d ∈ eAvl et a satisfait la précondition del’opération rgd. Alors :

1. A(rgd(a)) = A(a) (la rotation gauche-droite préserve la structure abs-traite),

2. rgd(a) ∈ eAvl (le résultat de la rotation gauche-droite est un Avl),3. r(rgd(a)) = r(a)− 1 (la rotation gauche-droite fait diminuer de 1 le rayon

de l’arbre).

Les trois schémas qui suivent illustrent les trois cas qui justifient une rotationgauche-droite. Ils se caractérisent par le fait que le déséquilibre à la racine estde 2 et que le déséquilibre du sous-arbre gauche est de signe opposé. Les arbresayant comme racine ug et ugd ainsi que les quatre arbres gg, ggd , dgd et d sontsupposés être des Avl. Le rayon des arbres gg, ggd , dgd et d est noté en bas durectangle les matérialisant et la valeur d’équilibre est apposée à chaque nœud.Le résultat de la rotation est représenté dans la partie droite du schéma. Danschacun des cas, l’arbre est devenu un Avl et son rayon diminue de 1.

Le premier schéma illustre le cas où, avant rotation, le sous-arbre droit dusous-arbre gauche, bien que toujours un Avl, est déséquilibré en faveur de ladroite.

Le schéma ci-dessous illustre le cas où, avant rotation, le sous-arbre droit dusous-arbre gauche est équilibré.

ggggd

dgd

d

ugd -1

ug -1

u 2

k k − 1k

k

Avant rotation

ggggd

dgd d

ug 1 u 0

ugd 0

k

k − 1k k

Après rotation

Page 212: Structures de données et méthodes formelles ||

202 Structures de données et méthodes formelles

gg

ggd dgd

d

ugd 0

ug -1

u 2

k

k k

k

Avant rotation

gg ggd dgd d

ug 0 u 0

ugd 0

k k k k

Après rotation

Enfin le schéma ci-dessous illustre le cas où, avant rotation, le sous-arbredroit du sous-arbre gauche, bien que toujours un Avl, est déséquilibré en faveurde la gauche.

gg

ggddgd

d

ugd 1

ug -1

u 2

k

k

k − 1k

Avant rotation

gg ggddgd

d

ug 0 u -1

ugd 0

k k

k − 1k

Après rotation

6.6.6 Calcul de la représentation des opérations concrètesLe calcul d’une représentation des opérations eV ide_v, eApp_v et

eEstV ide_v est laissé en exercice. Nous nous limitons au calcul des opérationseAjout_v et eSupp_v.

Calcul d’une représentation de l’opération eAjout_v

Le calcul de l’opération eAjout_v(v, a) se fait par induction sur la structurede a. Cependant, le développement traditionnel ne peut se faire sans une hypo-thèse d’induction complémentaire. Pratiquer une démarche purement construc-tive se ferait en constatant qu’une hypothèse manque pour poursuivre le déve-loppement et en réitérant le calcul après avoir intégré la nouvelle hypothèse, cecijusqu’à temps que le développement puisse être réalisé avec succès (ou doive êtreabandonné !). Cette démarche est longue et les calculs fastidieux mais elle estdifficile à éviter au quotidien. Nous proposons d’emblée l’hypothèse complémen-taire nécessaire, mais invitons le lecteur à réaliser un développement constructifintégral. Cette hypothèse complémentaire est dénommée Aug(a).

Page 213: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 203

Hypothèse d’induction 1 (Aug(a)).

Aug(a) = r(eAjout_v(v, a))− r(a) ∈ {0, 1}

Cette propriété affirme qu’effectuer une insertion dans un Avl provoque uneaugmentation du rayon d’au plus 1. Le calcul d’une représentation de l’opérationeAjout_v débute comme suit :

A(eAjout_v(v, a))= Propriété caractéristique de eAjout_v

A(a) ∪ {v} (6.6.4)

Procédons à une induction structurelle sur a. Le cas de base a = 〈〉 est trivial.Il conduit à la première équation gardée :

a = 〈〉 →eAjout_v(v, a) = 〈〈〉, v, 〈〉〉

La démonstration a posteriori de la propriété Aug(a) est aisée.Considérons à présent le cas inductif a = 〈〉, posons a = 〈g, u, d〉. Nous

repartons de la formule 6.6.4 ci-dessus.

A(a) ∪ {v}= HypothèseA(〈g, u, d〉) ∪ {v}

= Définition de A et propriété A.7A(g) ∪ {v} ∪ {u} ∪ A(d) (6.6.5)

À ce stade du développement, nous ne pouvons poursuivre le calcul sans distin-guer les trois cas v = u, v < u et v > u. Le cas v > u se déduit par symétrie ducas v < u. Concernant le cas v = u, nous avons :

A(g) ∪ {v} ∪ {u} ∪ A(d)= Hypothèse et propriété A.9

A(g) ∪ {u} ∪ A(d)= Définition de A

A(〈g, u, d〉)= Hypothèse

A(a)

Il s’agit d’un cas de fausse insertion, qui conduit à l’équation gardée suivante :

a = 〈g, u, d〉 →v = u →

eAjout_v(v, a) = a

La figure 6.7, page suivante, illustre le cas v < u. Elle montre les différents sous-cas qui peuvent être répertoriés après insertion d’une valeur dans le sous-arbregauche d’un Avl, selon que le rayon du sous-arbre gauche augmente de 1 ou de0 (hypothèse Aug(g)) après insertion.

Pour le cas v < u, repartons de la formule 6.6.5 :

Page 214: Structures de données et méthodes formelles ||

204 Structures de données et méthodes formelles

Figure 6.7 – Insertion dans le sous-arbre gauche d’un Avl.Cette figure montre les différents cas d’insertion dans le sous-arbregauche d’un Avl. Le rayon des sous-arbres est noté sous chaque sous-arbre, l’équilibre des nœuds est apposé à chaque nœud (négatif s’il est enfaveur de la droite, positif s’il est en faveur de la gauche, nul si l’arbreest équilibré). La première colonne montre les différentes situations pos-sibles avant l’insertion, la colonne centrale montre, pour chacun destrois cas avant insertion, les deux cas possibles selon que le sous-arbregauche a vu son rayon augmenter ou non (hypothèse Aug(g)). Les cinqsous-cas (a), (b), (c), (d) et (f) montrent des arbres h-équilibrés. Lecas (e) montre un arbre qui n’est plus h-équilibré. La troisième colonnedétaille les deux sous-cas possibles (le troisième sous-cas, celui où lesous-arbre gauche serait équilibré, n’est pas possible).

•−1

g′gk − 1

d′g

k

• 2

d

k − 1

g′g

k

d′gk − 1

d

k − 1

•• 2

1

g′

k + 1

d

k − 1

• 2

g′

k

d

k − 1

• 1g

k

d

k − 1

• 1

g′

k

d

k

• 0

g′

k − 1d

k

•−1

g′

k + 1

d

k

• 1

g′

k

d

k

• 0

g

k − 1d

k

•−1

g

k

d

k

• 0

Avant insertion Après insertion Détails

(1)

(2)

(3)

(a)

(b)

(c)

(d)

(e)

(f)

(e′)

(e′′)

Page 215: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 205

A(g) ∪ {v} ∪ {u} ∪ A(d)= Propriété A.7(A(g) ∪ {v}) ∪ {u} ∪ A(d)

= Propriété caractéristique de l’opération eAjout_vA(eAjout_v(v, g)) ∪ {u} ∪ A(d)

= Définition de AA(〈eAjout_v(v, g), u, d〉)

Nous savons que eAjout_v(v, g) ∈ eAvl (c’est l’hypothèse d’induction « natu-relle » de la démonstration). Nous savons également que r(eAjout_v(v, g)) −r(g) ∈ {0, 1} (c’est l’hypothèse d’induction Aug(g)). Ainsi que le montre lacolonne « Après insertion » de la figure 6.7, page ci-contre, en général l’arbrerésultant de l’insertion est un Avl (cas (a), (b), (c), (d) et (f)) mais il subsisteun cas (le cas (e) de la figure) où l’arbre 〈eAjout_v(v, g), n, d〉 n’est pas un Avl.Dans ce cas, d’après l’hypothèse d’induction Aug(g), le rayon gauche a aug-menté et le déséquilibre à la racine est donc de 2 : r(eAjout_v(v, g))− r(d) = 2.La décision sur la suite du développement se fait donc selon deux possibili-tés : r(eAjout_v(v, g)) − r(d) ∈ −1 .. 1 (qui recouvre les cinq cas précités) our(eAjout_v(v, g))−r(d) = 2. Si la première condition est satisfaite, nous sommesen mesure de conclure puisque le résultat est un Avl. Sinon, il faut procéder àune rotation.

Peut-on poursuivre le développement en utilisant la fonction r sans compro-mettre l’efficacité de l’opération ? Autrement dit, la fonction r est-elle décompo-sable sur un Avl (cf. encadré page 188) ? La réponse à cette dernière questionest à l’évidence positive. Nous devrons donc raffiner le développement dans uneétape ultérieure (cf. section 6.6.7, page 213).

Revenons au développement de l’opération en considérant tout d’abord le casr(eAjout_v(v, g))− r(d) ∈ −1 .. 1. Il nous conduit immédiatement à l’équationgardée suivante :

a = 〈g, u, d〉 →v < u →

r(eAjout_v(v, g))− r(d) ∈ −1 .. 1 →eAjout_v(v, a) = 〈eAjout_v(v, g), u, d〉

Démontrer a posteriori la propriété Aug(a) est facile. Nous nous li-mitons à ébaucher cette démonstration. Nous devons évaluer l’expressionr(eAjout_v(v, a)) − r(a). Nous savons (hypothèse d’induction) que Aug(g), etdonc r(eAjout_v(v, g))− r(g), est égal soit à 0 soit à 1. Le premier cas est tri-vial. Le second cas, celui où le rayon du sous-arbre gauche augmente (cas (b) et(d) de la figure, où r(eAjout_v(v, g))− r(g) = 1) conduit à réaliser une analysepar cas incidente pour laquelle deux sous-cas sont à considérer vis-à-vis de laconfiguration de l’arbre avant l’insertion :

– r(g) = r(d) (cas (1) de la figure),– r(g) = r(d)− 1 (cas (2) de la figure).

Le premier sous-cas fournit comme résultat une augmentation de rayon de 1.Pour le deuxième cas, le rayon ne change pas. Le troisième cas, r(g) = r(d) + 1n’est pas à envisager, car dans cette hypothèse la condition r(eAjout_v(v, g))−

Page 216: Structures de données et méthodes formelles ||

206 Structures de données et méthodes formelles

r(d) ∈ −1 .. 1 ne serait pas satisfaite. La propriété Aug(a) est donc établie pourcette équation gardée.

Revenons au calcul de l’opération eAjout_v. Le second cas, celui oùr(eAjout_v(v, g)) − r(d) = 2, est représenté en partie (e) de la figure 6.7. Ilse décompose en deux sous-cas, qui sont ceux représentés dans la colonne « Dé-tails » de la figure. L’arbre résultant de l’insertion n’est pas h-équilibré à laracine : nous devons donc appliquer une rotation. Nous savons, depuis la sec-tion 6.6.5, page 197, que la nature de la rotation dépend de la valeur du dés-équilibre du sous-arbre gauche : s’il est du même signe que le déséquilibre à laracine, une rotation simple (droite ici) suffit, sinon il faut appliquer une rotationdouble (gauche-droite ici). Le cas où le sous-arbre gauche est équilibré ne peutsurvenir. Nous pouvons démontrer cette dernière affirmation par l’absurde : si lesous-arbre gauche g′ était équilibré après une insertion qui s’est soldée par l’aug-mentation (de 1) du rayon de l’un de ses sous-arbres c’est que l’autre sous-arbreavait un rayon supérieur au premier et donc le rayon de g n’a pas augmenté.Posons eAjout_v(v, g) = 〈g′g, ng, d

′g〉 et considérons le cas où les déséquilibres

sont de même signe (r(eAjout_v(v, g)) − r(d) = 2 et r(g′g) − r(d′g) = 1, cf. cas(e′) de la figure). L’équation gardée correspondante s’écrit :

a = 〈g, u, d〉 →v < u →

r(eAjout_v(v, g))− r(d) /∈ −1 .. 1 →let 〈g′g, ug, d

′g〉 := eAjout_v(v, g) in

r(g′g)− r(d′g) = 1 →eAjout_v(v, a) = rd(〈〈g′g, ug, d

′g〉, u, d〉)

end

La démonstration de la propriété Aug(a) est laissée en exercice (cf. exercice 6.6.4,page 215).

Le cas où les déséquilibres sont de signes différents (r(eAjout_v(v, g)) −r(d) = 2 et r(g′g) − r(d′g) = −1, cf. cas (e′′) de la figure) conduit à l’équationgardée suivante :

a = 〈g, u, d〉 →v < n →

r(eAjout_v(v, g))− r(d) /∈ −1 .. 1 →let 〈g′g, ug, d

′g〉 := eAjout_v(v, g) in

r(g′g)− r(d′g) = −1 →eAjout_v(v, a) = rgd(〈〈g′g, ug, d

′g〉, u, d〉)

end

Il est facile de montrer que la propriété Aug(a) est vérifiée pour ce dernier cas.La démonstration est proposée en exercice (cf. exercice 6.6.4, page 215).

Les équations gardées correspondant à la garde v > n se déduisent par symé-trie. Elles ne sont pas calculées ici. En intégrant les différentes équations gardéescalculées, nous obtenons la représentation suivante de l’opération eAjout_v :

Page 217: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 207

function eAjout_v(v, a) ∈ N× eAvl→ eAvl =if a = 〈〉 → /*vraie insertion*/

〈〈〉, v, 〈〉〉| a = 〈g, u, d〉 →

if v = u → /*fausse insertion*/a

| v < u → /*insertion à gauche*/if r(eAjout_v(v, g))− r(d) ∈ −1 .. 1 →

〈eAjout_v(v, g), u, d〉| r(eAjout_v(v, g))− r(d) /∈ −1 .. 1 →

let 〈g′g, ug, d′g〉 := eAjout_v(v, g) in

if r(g′g)− r(d′g) = 1 →rd(〈〈g′g, ug, d

′g〉, u, d〉)

| r(g′g)− r(d′g) = −1 →rgd(〈〈g′g, ug, d

′g〉, u, d〉)

fiend

fi| v > u → /*insertion à droite*/

...fi

fi

L’interprétation opérationnelle de cette solution est la suivante. L’insertions’effectue sur une feuille. En remontant, si l’équilibre Avl est violé, une rotation,simple ou double selon le cas, le rétablit.

Abordons à présent le problème de la complexité de cette opération. Faisonsl’hypothèse que le rayon d’unAvl estO(1)-décomposable (cf. sections 1.10 et 2.4,et encadré page 188) sur la structure de données (cf. section 6.6.7). Ensuite,notons qu’il est possible de démontrer qu’une insertion dans un Avl exige auplus une rotation (cf. exercice 6.6.5). Par ailleurs, le théorème d’Adelson-Velskyet Landis (cf. formule 6.6.1, page 193) nous apprend que le rayon d’un Avl depoids n est inférieur à 1, 45 · log(n+1). Enfin, les rotations, simples ou doubles,entraînent un nombre constant de comparaisons. Il est facile d’en conclure quela complexité temporelle d’une insertion est en O(log n).

Calcul d’une représentation de l’opération eSupp_v

De même que pour l’opération eAjout_v, le développement de l’opérationeSupp_v(v, a) se fait en utilisant une hypothèse d’induction complémentaire.Celle-ci affirme que suite à une suppression, le rayon diminue au plus de 1.

Hypothèse d’induction 2 (Dim(a)).

Dim(a) = r(a)− r(eSupp_v(v, a)) ∈ {0, 1}Cette hypothèse doit être démontrée séparément à chacune des étapes de

calcul. Ces démonstrations ne sont pas réalisées ici, mais sont proposées à l’exer-cice 6.6.4, page 215. Nous réalisons une induction sur a. Le cas de base a = 〈〉

Page 218: Structures de données et méthodes formelles ||

208 Structures de données et méthodes formelles

est trivial. Il correspond à une fausse suppression et se matérialise par l’équationgardée suivante :

a = 〈〉 →eSupp_v(v, a) = 〈〉

Pour le cas inductif, posons a = 〈g, u, d〉.

A(eSupp_v(v, a))= Propriété caractéristique de l’opération eSupp_v

A(a)− {v}= Hypothèse (a = 〈g, u, d〉)

A(〈g, u, d〉)− {v}= Définition de A(A(g) ∪ {u} ∪ A(d)) − {v}

= Propriété A.8(A(g)− {v}) ∪ ({u} − {v}) ∪ (A(d)− {v}) (6.6.6)

La suite du calcul distingue le cas v = u du cas v = u. Débutons par le casv = u.

(A(g)− {v}) ∪ ({u} − {v}) ∪ (A(d)− {v})= Cf. développement de la propriété 6.3.11, page 162

A(g) ∪ A(d) (6.6.7)

Deux cas sont à considérer : A(g) ∪ A(d) = ∅ et A(g) ∪ A(d) = ∅. Le premiercas se traduit facilement en g = 〈〉∧d = 〈〉. Considérons le cas A(g)∪A(d) = ∅ :

A(g) ∪ A(d)= Hypothèse∅

= Définition de AA(〈〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), puisquel’arbre 〈〉 est un Avl, la première équation gardée :

a = 〈g, u, d〉 →v = u →

g = 〈〉 ∧ d = 〈〉 →eSupp_v(v, a) = 〈〉

En supposant toujours que v = u, le second cas est conditionné par l’expres-sion g = 〈〉 ∨ d = 〈〉. Il se traite à la manière de la suppression dans les abr(cf. page 161 et suivantes), en mettant en évidence le plus grand élément dusous-arbre gauche g ou le plus petit élément du sous-arbre droit d. Cependant,le choix du sous-arbre à considérer ici n’est pas indifférent. En effet, il faut éviterde rechercher une valeur dans un sous-arbre vide. Une solution consiste à sélec-tionner le sous-arbre ayant le plus grand rayon. Ce choix présente un avantage

Page 219: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 209

supplémentaire : suite à la suppression, et compte tenu de l’hypothèse d’induc-tion Dim, l’arbre reste équilibré. Dans la suite nous traitons uniquement le casr(g) ≥ r(d), le cas r(g) ≤ r(d) s’en déduit par symétrie 8. De r(g) ≥ r(d) et deg = 〈〉 ∨ d = 〈〉 nous déduisons que g = 〈〉. A(g) possède donc un plus grandélément. Nous repartons de la formule 6.6.7 ci-dessus.

A(g) ∪ A(d)= Propriété A.10(A(g)− {max(A(g))}) ∪ {max(A(g))} ∪ A(d)

= Propriété caractéristique de eSupp_vA(eSupp_v(max(A(g)), g)) ∪ {max(A(g))} ∪ A(d)

= Définition de AA(〈eSupp_v(max(A(g)), g),max(A(g)), d〉)

De même que la fonction r, la fonction max est décomposable sur un Avl.Nous poursuivons donc le développement en faisant abstraction du raffinementultérieur qu’il faudra réaliser pour disposer du maximum d’un Avl. Il faut main-tenant nous assurer que l’argument de la fonction A est bien un Avl. Posonsg′ = eSupp_v(max(A(g), g)). Nous sommes dans le cas où r(g) ≥ r(d) (et donc,puisque a est un Avl, 0 ≤ r(g) − r(d) ≤ 1). D’après l’hypothèse d’inductionDim(g), 0 ≤ r(g) − r(g′) ≤ 1, soit encore −1 ≤ r(g′) − r(g) ≤ 0. En ajoutantles deux doubles inégalités, nous obtenons −1 ≤ r(g′) − r(d) ≤ 1. Soit encorer(eSupp_v(max(A(g), g)))− r(d) ∈ −1 .. 1. L’arbre résultant de la suppressionest bien un Avl. D’où la seconde équation gardée :

a = 〈g, u, d〉 →v = u →

g = 〈〉 ∨ d = 〈〉 →r(g) ≥ r(d) →

eSupp_v(v, a) = 〈eSupp_v(max(A(g)), g),max(A(g)), d〉

Le cas r(g) ≤ r(d) s’obtient par des considérations de symétrie. Abordons àprésent le cas v = u. Deux sous-cas sont à considérer : v > u et v < u. Dévelop-pons le premier sous-cas en repartant de la formule 6.6.6, page ci-contre. Ce casest analysé à la figure 6.8 (page suivante), qui montre les différentes situationspossibles suite à la suppression d’une valeur dans le sous-arbre droit (colonne« Après suppression »).

v > u implique que {u} ∩ {v} = ∅. Par ailleurs, d’après le théorème 4 desabr (page 151), A(g) ∩ {v} = ∅ :

(A(g)− {v}) ∪ ({u} − {v}) ∪ (A(d)− {v})= Propriété A.16

A(g) ∪ {u} ∪ (A(d)− {v})= Propriété caractéristique de eSupp_v

A(g) ∪ {u} ∪ A(eSupp_v(v, d))= Définition de A

A(〈g, u, eSupp_v(v, d)〉)8. Depuis le calcul de l’opération eAjout_v nous savons que nous pouvons décomposer la

fonction r sur un Avl ; nous utilisons donc cette fonction sans autres précautions.

Page 220: Structures de données et méthodes formelles ||

210 Structures de données et méthodes formelles

•−1

gg

k − 1dg

k

• 2

d′

k − 1

gg

k

dg

k

d′

k − 1

•• 2

0

gg

k

dg

k − 1

d′

k − 1

•• 2

1

g

k + 1

d′

k − 1

• 2

g

k + 1

d′

k

• 1

g

k + 1

d

k

• 1

g

k − 1d′

k − 1

• 0

g

k − 1d′

k

•−1

g

k

d′

k − 1

• 1

g

k

d′

k

• 0

g

k − 1d

k

•−1

g

k

d

k

• 0

Avant suppression Après suppression Détails

(1)

(2)

(3)

(a)

(b)

(c)

(d)

(e)

(f)

(e′)

(e′′)

(e(3))

Figure 6.8 – Suppression dans le sous-arbre droit d’un Avl.Cette figure montre les différents cas de suppression dans le sous-arbredroit d’un Avl. Le rayon des sous-arbres est noté sous chaque sous-arbre, l’équilibre des nœuds est apposé à chaque nœud (négatif s’il esten faveur de la droite, positif s’il est en faveur de la gauche, nul sil’arbre est équilibré). La première colonne montre les différentes situa-tions possibles avant la suppression ; la colonne centrale montre, pourchacun des trois cas avant suppression, les deux cas possibles selonque le sous-arbre droit a vu son rayon diminuer ou non (hypothèseDim(d)). Les cinq sous-cas ((a), (b), (c), (d) et (f)) montrent des ar-bres h-équilibrés. Le cas (e) montre un arbre qui n’est plus h-équilibré.La troisième colonne détaille les trois sous-cas possibles pour (e).

Page 221: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 211

L’arbre 〈g, u, eSupp_v(v, d)〉 est représenté dans la colonne centrale de la fi-gure 6.8. En général, le résultat est h-équilibré (c’est ce que montrent les cinqcas (a), (b), (c), (d) et (f) pour lesquels r(g) − r(eSupp_v(v, d)) ∈ −1 .. 1). Lecas (e) est par contre problématique dans la mesure où la suppression dans lesous-arbre d fait diminuer le rayon et conduit à un déséquilibre inacceptable(r(g)− r(eSupp_v(v, d)) = 2). Il faut alors procéder à une rotation.

Abordons tout d’abord le cas où l’arbre résultant de la suppression est unAvl (cas (a), (b), (c), (d) et (f)). L’équation gardée est immédiate :

a = 〈g, u, d〉 →v = u →

v > u →r(g)− r(eSupp_v(v, d)) ∈ −1 .. 1 →

eSupp_v(v, a) = 〈g, u, eSupp_v(v, d)〉

Abordons maintenant le cas où, suite à la suppression dans le sous-arbredroit, l’arbre n’est plus h-équilibré (cas (e) de la figure). Il faut procéder à unerotation 9.

Ainsi que nous l’avons vu à la section 6.6.5, page 197, la nature de la rotationdépend de l’équilibre du sous-arbre excédentaire (g ici). Posons g = 〈gg, ug, dg〉.Si r(gg) ≥ r(dg) nous pouvons procéder, d’après les théorèmes 9 et 10, à unerotation droite rd (cas (e′) et (e′′) de la figure). D’où l’équation gardée :

a = 〈g, u, d〉 →v > u →

r(g)− r(eSupp_v(v, d)) /∈ −1 .. 1 →let 〈gg, ug, dg〉 := g in

r(gg) ≥ r(dg) →eSupp_v(v, a) = rd(〈g, u, eSupp_v(v, d)〉)

end

Sinon, d’après le théorème 12, page 201, nous pouvons rétablir l’équilibre Avlpar une rotation double gauche-droite. D’où l’équation gardée :

a = 〈g, u, d〉 →v > u →

r(g)− r(eSupp_v(v, d)) /∈ −1 .. 1 →let 〈gg, ug, dg〉 := g in

r(gg) < r(dg) →eSupp_v(v, a) = rgd(〈g, u, eSupp_v(v, d)〉)

end

Le cas v < u se traite de façon analogue. Nous obtenons au total la versionsuivante de l’opération eSupp_v :

9. Contrairement à l’insertion, le cas où le sous-arbre gauche de g est équilibré peut survenir.Il suffit que g soit équilibré avant la suppression puisque celle-ci, par construction, ne modifiepas g (cf. théorème 10, page 199).

Page 222: Structures de données et méthodes formelles ||

212 Structures de données et méthodes formelles

function eSupp_v(v, a) ∈ N× eAvl→ eAvl =if a = 〈〉 → /*fausse suppression*/

〈〉| a = 〈g, u, d〉 →

if v = u → /*suppression de la racine*/if g = 〈〉 ∧ d = 〈〉 → /*la racine est une feuille*/

〈〉| g = 〈〉 ∨ d = 〈〉 → /*la racine n’est pas une feuille*/

if r(g) ≥ r(d) →let m := max(A(g)) in

〈eSupp_v(m, g),m, d〉end

| r(g) ≤ r(d) →let m := min(A(d)) in

〈g,m, eSupp_v(m,d)〉end

fifi

| v > u → /*suppression à droite*/let l := eSupp_v(v, d) in

if r(g)− r(l) ∈ −1 .. 1 →〈g, u, l〉

| r(g)− r(l) /∈ −1 .. 1 →let 〈gg, ug, dg〉 := g in

if r(gg) ≥ r(dg) →rd(〈g, u, l〉)

| r(gg) < r(dg) →rgd(〈g, u, l〉)

fiend

fiend

| v < u → /*suppression à gauche*/...

fifi

L’interprétation opérationnelle de cette version est la suivante. Si la valeur àsupprimer v est une feuille, le résultat est un arbre vide. Si la valeur à supprimerest un nœud interne, on supprime la valeur la plus proche (qui est une feuille).Celle-ci vient se substituer à v. Si la valeur à supprimer n’est pas la racine u, lasuppression se fait dans le sous-arbre gauche ou droit, selon la position relativede v et de u. L’équilibre Avl est rétabli par rotations (simples ou doubles) enremontant.

L’exercice 6.6.6 illustre le fait que la suppression dans un Avl peut exigerune rotation sur tous les niveaux situés entre la valeur à supprimer et la racine.Sur le plan de la complexité, nous sommes donc dans une situation légèrement

Page 223: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 213

différente de l’insertion. Cependant, toujours dans l’hypothèse d’un renforcementdu support par une O(1)-décomposition de l’opération r sur la structure dedonnées, la complexité de la suppression est à nouveau en O(log n) puisquele nombre de comparaisons par rotation est constant. Par ailleurs, on montreempiriquement que pour la suppression, le nombre de rotations est en moyennede une pour cinq suppressions alors qu’il est de une pour deux adjonctions !

6.6.7 Renforcement du support par décompositiondu rayon

Les deux opérations calculées ci-dessus ne peuvent être laissées en l’état.Toutes deux utilisent la fonction r qui délivre le rayon d’un Avl. Dans sa versionde la section 3.5.2, r est une opération qui exige d’accéder à toutes les feuillesà chaque invocation. Le coût qui en résulte est excessif et incompatible avecl’objectif d’efficacité visé.

Par ailleurs, l’opération eSupp_v fait usage des fonctions max et min ap-pliquées à des ensembles représentés par des Avl. Nous sommes là dans unesituation similaire à celle rencontrée lors de l’étude de l’opération eSupp_a desuppression dans les abr : il est nécessaire de transformer ces appels. Les troissolutions évoquées ou implantées alors (raffiner les opérations max et min sur desensembles en des opérations sur des Avl, renforcer le support en décomposantles fonctions max et min sur la structure de données, ou fusionner l’opération desuppression avec l’opération de recherche du max au sein d’une seule opération,cf. page 164) restent d’actualité.

Concernant le cas de la fonction r, nous proposons ci-dessous de renforcerle support en décomposant le rayon sur la structure de données. Quant à latransformation des appels aux fonctions max et min, nous laissons le choix aulecteur dans le cadre de l’exercice 6.6.8. Décomposer le rayon sur la structurede données est une opération qui se scinde en deux parties. Pour cela, il fautbien entendu enrichir chaque nœud d’un champ contenant la valeur du rayonde l’arbre considéré. C’est ce que nous faisons en considérant qu’un nœud nonvide est une structure de la forme 〈g, u �→ s, d〉 où g et d sont des sous-arbres,u la clé et s le rayon de l’arbre. Il faut également remplacer la fonction r de lasection 3.5.2 par la description r′ suivante :

function r′(a) ∈ eAvl→ N =if a = 〈〉 →0

| a = 〈g, u �→ s, d〉 →s

fi

Reste le problème des rotations. Compte tenu de la nouvelle structure desnœuds, qui comprend un champ pour le rayon, les quatre opérations de rotationdoivent être aménagées. Les nouvelles versions sont dénommées rg′, rd′, rgd′,rdg′. Dans la suite, elles sont supposées disponibles.

Nous sommes maintenant à même de proposer un raffinement pour l’opéra-tion eAjout_v. Les modifications à apporter sont d’une part la prise en compte

Page 224: Structures de données et méthodes formelles ||

214 Structures de données et méthodes formelles

de la nouvelle structure incluant le rayon des arbres et d’autre part l’utilisationdes nouvelles versions pour le rayon et les rotations. L’opération eAjout_v seraffine alors comme suit :

function eAjout_v(v, a) ∈ N× eAvl→ eAvl =if a = 〈〉 →

〈〈〉, v �→ 1, 〈〉〉| a = 〈g, u �→ s, d〉 →

if v = u →a

| v < u →if r′(eAjout_v(v, g))− r′(d) ∈ −1 .. 1 →⟨ eAjout_v(v, g),

u �→ max({r′(eAjout_v(v, g)), r′(d)}) + 1,d

⟩| r′(eAjout_v(v, g))− r′(d) /∈ −1 .. 1 →

let 〈g′g, ug �→ s′, d′g〉 := eAjout_v(v, g) inif r′(g′g)− r′(d′g) = 1 →

rd( 〈〈g′g, ug �→ s′, d′g〉, u �→ s′, d〉 )| r′(g′g)− r′(d′g) = −1 →

rgd( 〈〈g′g, ug �→ s′, d′g〉, u �→ s′, d〉 )fi

endfi

| v > u →...

fifi

Les appels multiples à la fonction eAjout_v peuvent facilement être évités enutilisant une expression let. Le cas de l’opération eSupp_v est laissé en exercice.

6.6.8 Conclusion et remarques bibliographiques

Le lecteur averti note que les algorithmes de mise à jour des Avl présentésci-dessus, outre le fait qu’il s’agisse de versions fonctionnelles et calculées, sedémarquent de ceux traditionnellement proposés dans la littérature, par l’usagequi est fait de la persistance, qui donne accès au rayon courant ainsi qu’aurayon précédant la mise à jour. L’utilisation explicite du rayon (plutôt que de ladifférence de rayons) facilite le calcul en supprimant le dernier niveau d’analyse.C’est pédagogiquement parlant un avantage, qui se paye en terme de complexitéspatiale. Un autre inconvénient est la difficulté que présente la traduction d’uneversion fonctionnelle persistante en une version impérative.

Page 225: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 215

Les Avl nous ont permis d’atteindre l’un de nos objectifs en ce qui concernela représentation des ensembles (de scalaires dotés d’une structure d’ordre) :une bonne efficacité dans toutes les situations. Cette qualité résulte d’une partde l’absence de dégénérescence de la structure de données (cf. le théorèmed’Adelson-Velsky et Landis) et d’autre part d’un coût constant des opérationsde rotation, qui dotent les algorithmes de mise à jour d’une complexité asymp-totique identique à celle de la recherche. Par contre, certaines situations mettenten lumière l’un des défauts des Avl (et des arbres binaires en général). Il s’agitde leur utilisation dans le contexte des mémoires auxiliaires (comme les disquesmagnétiques ou les disques ssd 10) pour lesquelles l’unité de mémoire est grande(typiquement un secteur de 512 octets, parfois plus). Il n’est alors pas raison-nable, tant sur le plan de l’occupation que sur celui de la vitesse de transfertentre mémoire centrale et mémoire auxiliaire, d’occuper une unité d’allocationpar nœud. C’est pourquoi des structures de données adaptées, qui contournentces inconvénients ont été mises au point. L’exemple le plus typique est celui desB-arbres (cf. section 6.7).

Découverte en 1962 par les mathématiciens soviétiques G.M. Adelson-Velskyet E.M. Landis, la forme d’arbre binaire de recherche dénomméeAvl par C.C. Fos-ter [36] est depuis considérée comme l’archétype des arbres équilibrés. L’opéra-tion de suppression n’apparaît pas dans l’article de 1962. Il faut attendre 1965 etun rapport interne de la société Goodyear Aerospace (cité dans C.C. Foster [36])pour la parution d’une première solution au problème de la suppression. Bien queconcurrencés par d’autres formes d’arbres équilibrés, les Avl font souvent partiedu catalogue de structures de données avancées offert aux étudiants en informa-tique. La découverte des Avl a initié une longue liste de structures de donnéesexplicitement équilibrées comme les B-arbres, les arbres équilibrés en hauteur,les arbres semi-équilibrés [94], les arbres 2-3, les arbres 2-3-4, les arbres équilibrésen poids [89], etc. Dans un article récent [108], S. Sen et R. Tarjan proposentune forme relâchée d’Avl (les « relaxed Avl ») qui, tout en restant efficaces,permettent des suppressions sans rééquilibrage. Cette simplification s’obtient auprix d’une reconstruction périodique de l’arbre. Pour ce qui concerne l’analysedes algorithmes, dans [75], D. Knuth présente une analyse détaillée de la com-plexité de la recherche et de l’insertion dans un Avl.

Exercices

Exercice 6.6.1 Démontrer les théorèmes 9, 10, 11 et 12, page 198 et suivantes.

Exercice 6.6.2 Dans le texte nous montrons par l’absurde que lors d’une insertion dans unAvl, lorsque le rayon augmente, alors le déséquilibre de la racine est de 1 en valeur absolue.Faire une démonstration par induction de cette proposition.

Exercice 6.6.3 Montrer directement (sans utiliser le théorème 8) que la rotation droite rdpréserve la structure abstraite. Faire de même pour la rotation double rgd.

Exercice 6.6.4 Démontrer l’hypothèse d’induction Aug(a) (resp. Dim(a)) dans le cas où unerotation est exigée dans le calcul de l’opération eAjout_v (resp. eSupp_v).

10. ssd : Solid State Drive, unité de stockage permanent sans pièce mobile.

Page 226: Structures de données et méthodes formelles ||

216 Structures de données et méthodes formelles

Exercice 6.6.5 Montrer que l’insertion dans un Avl exige au plus une rotation.

Exercice 6.6.6 Fournir un exemple d’un Avl de poids minimum 12 dans lequel la suppressiond’une feuille exige une rotation à chaque nœud du chemin de la recherche.

Exercice 6.6.7 Certains auteurs suggèrent d’effectuer la suppression d’un nœud interne endescendant la valeur à supprimer sur une feuille, par rotations simples ou doubles (de façonà préserver l’équilibre Avl), puis à supprimer la feuille avant de rééquilibrer par rotations enremontant. Cette solution est erronée : la première étape n’est pas toujours possible. Identifierau moins un cas où l’équilibre Avl est violé quelle que soit la rotation (simple ou double) quel’on effectue en descendant la valeur vers les feuilles.

Exercice 6.6.8 Poursuivre le développement de l’opération de suppression dans un Avl(eSupp_v) en transformant l’utilisation des fonctions min et max par l’une des méthodesévoquées page 213.

Exercice 6.6.9 Spécifier par Avl les opérations abstraites complémentaires décrites dansl’exercice 6.2.2, page 149. Calculer une représentation de ces opérations.

Exercice 6.6.10 Définir et étudier la notion d’Avl appliquée aux arbres externes. Calculerles opérations concrètes. Discuter par rapport à la solution développée ci-dessous.

Exercice 6.6.11 Jusqu’à présent, nous avons recherché une représentation efficace pour lesensembles de scalaires. Il est cependant fréquent d’avoir à représenter et à mettre à jourdes ensembles de couples de scalaires (en d’autres termes des relations binaires de scalaires).C’est le thème de la section 7.2. Étudier une solution où chaque relation est représentée parun couple d’Avl. Le premier Avl (resp. le second) représente l’ensemble des origines (resp.des destinations). En outre, à chaque nœud est associé l’ensemble des valeurs qui constituentl’image (resp. l’image inverse) de la coordonnée considérée.

Exercice 6.6.12 Un « 1-2 arbre frère » (cf. [96]) est soit un arbre binaire étiqueté (par unentier) soit un arbre unaire non étiqueté (cf. section 3.5) satisfaisant aux contraintes suivantes :

1. le frère d’un arbre unaire est un arbre binaire,2. toutes les feuilles sont à la même hauteur,3. c’est un arbre de recherche.

Ainsi par exemple l’arbre ci-dessous est un « 1-2 arbre frère » :

20

7

4

10

• 15

30

27

24 •

37

Sur cette base, proposer une spécification concrète pour le raffinement des ensembles dotésd’une relation d’ordre. Calculer les différentes opérations concrètes et leurs complexités.

6.7 Méthodes équilibrées : les B-arbres

6.7.1 IntroductionLes Avl constituent une bonne solution pour une représentation efficace des

ensembles en mémoire centrale. Cette solution n’est cependant pas viable lors-qu’on la transpose aux mémoires auxiliaires, pour au moins deux raisons com-plémentaires : d’une part l’unité d’allocation (dans les années 2010 : un secteur

Page 227: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 217

disque 11 ou un bloc selon les cas) est en général trop volumineuse pour représen-ter un seul nœud d’un Avl. D’autre part, dans les représentations arborescentes,le nombre d’accès disque varie avec la hauteur : celle des Avl est en généraltrop élevée par rapport au nombre de valeurs représentées pour pouvoir utiliserraisonnablement un support auxiliaire. Il est donc nécessaire d’adapter l’unitéd’allocation logique (typiquement un nœud de l’arbre) à la taille des unités phy-siques (les secteurs ou les blocs).

Le h-équilibre des Avl préserve la largeur (le nombre de clés) des nœuds quireste constante (et égale à 1), au détriment d’un équilibre en hauteur où un légerdéséquilibre est autorisé. Au contraire, l’équilibre des B-arbres est tel que toutesles feuilles sont à la même hauteur mais la largeur des nœuds est légèrementvariable.

De même que dans le cas des Avl, les B-arbres modélisent des ensemblesdotés d’une structure d’ordre total. Dans la suite nous allons (sans sacrifier lagénéralité du propos) considérer des ensembles d’entiers naturels.

Les B-arbres d’ordre n (n > 0) non vides se caractérisent par les propriétéssuivantes :1. Pour un nœud donné, tous les sous-arbres ont le même rayon.2. Chaque nœud, à l’exception de la racine, contient entre n et 2 · n valeurs

organisées en tableau.2 bis. La racine contient entre 1 et 2 · n valeurs.3. Les valeurs situées dans les nœuds sont triées strictement par ordre croissant.4. Chaque nœud constitué de p valeurs désigne p + 1 B-arbres, tous de même

rayon.4 bis. Chaque feuille constituée de p valeurs « désigne » p+ 1 B-arbres vides.5. Un B-arbre est un arbre de recherche : le parcours infixé gauche-droite ren-

contre les valeurs dans l’ordre strictement croissant.Un arbre respectant à la lettre ces propriétés sera dans la suite appelé B-

arbre strict. Un B-arbre strict est donc, selon la terminologie de la section 3.2,un arbre 2 · n-aire. Afin de mettre en œuvre les opérations de mise à jour, noussommes amené à assouplir certaines de ces contraintes. Lorsque la condition 2vaut également pour la racine, nous avons affaire à un B-arbre régulier.

En l’absence de la propriété 2 bis, un B-arbre devrait soit ne posséder aucunevaleur (cas d’un B-arbre vide) soit au moins n valeurs. Cette limitation estcontraire à la spécification abstraite et serait inacceptable. Cette propriété 2 bispermet donc de représenter des ensembles ayant un nombre fini quelconque devaleurs. En revanche, le fait que les nœuds ne soient pas uniformément de mêmenature (la racine est un cas particulier) complexifie la description du supportconcret comme nous le verrons ci-dessous.

Concernant l’aspect recherche dans un B-arbre, la technique utilisée est uneextension de celle appliquée dans les arbres binaires de recherche. L’insertionquant à elle se fait toujours aux feuilles. Une insertion pouvant provoquer ledébordement d’un nœud, il peut être nécessaire d’éclater un nœud plein. Cetéclatement peut se faire « en remontant » (insertion dite ascendante) ou « en

11. Que ce soit un disque « dur » classique ou un ssd.

Page 228: Structures de données et méthodes formelles ||

218 Structures de données et méthodes formelles

descendant » (insertion descendante). Nous développons la démarche ascendanteet proposons d’étudier l’autre démarche à l’exercice 6.7.4.

Sur l’exemple de la figure 6.9, qui représente un B-arbre d’ordre 2, nousnotons que :

– la largeur des nœuds est supérieure ou égale à deux, sauf celle de la racinequi est de un ;

– toutes les feuilles sont à la même hauteur 2 ;– les valeurs situées dans chaque nœud sont triées strictement par ordrecroissant ;

– tout nœud différent d’une feuille et contenant p valeurs désigne p+1 sous-arbres non vides ;

– le parcours infixé de l’arbre rencontre successivement les valeurs 2, 3, 5, 7,10, 11, 12, 14, 16, 17, 23, 24, 25, 29, 30, 32, 34, 37, 38, 39, 40, 43, 44, 49,51 et 57, qui constituent l’ensemble représenté par l’arbre.

Figure 6.9 – Un exemple de B-arbre strict d’ordre 2.Dans un B-arbre strict d’ordre 2 non vide, tous les nœuds ont entre 2 et4 clés, à l’exception de la racine qui possède entre 1 (c’est le cas ici) et 4clés. Le parcours infixé rencontre les clés dans l’ordre croissant. Toutesles feuilles sont à la même distance de la racine (2 ici). Le rayon decet arbre est de 3 (3 niveaux). À l’exception des feuilles, un nœud de pclés désigne p+ 1 sous-B-arbres.

6.7.2 Définition du support concretDéfinir rigoureusement le support nBA des B-arbres est une entreprise com-

plexe que nous allons réaliser en trois étapes. La première définition que nousallons fournir tient compte de ce que dans un B-arbre non vide d’ordre n, laracine possède un statut particulier par le fait que sa largeur varie entre 1 et2 · n alors que les autres nœuds ont tous entre n et 2 · n éléments. Pour tenircompte de cette particularité, nous proposons de définir le type nba en le do-tant de deux paramètres n et inf. n représente l’ordre du B-arbre tandis queinf représente la largeur minimale de la racine. L’en-tête se présente alors de lamanière suivante :

2 3 7 10 11 12 16 17 23 25 29 32 34 38 39 40 44 49 51 57

5 14 24 37 43

30

Page 229: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 219

concreteType nba(n, inf) . . .constraints

n ∈ N1 ∧inf ∈ {1, n}

Chaque nœud est un triplet constitué :– d’un tableau de valeurs, de taille physique 2 · n et de taille logique lg, définisur l’intervalle 1 .. (2 · n). lg est le troisième élément du triplet ;

– d’un tableau défini sur l’intervalle 0 .. (2 · n) désignant lg+ 1 arbres. Dansle cas de feuilles, les arbres désignés sont vides ;

– de lg, largeur du nœud représenté (la taille logique de ce nœud).

Le support du tableau de valeurs se définit par tt(lg), où lg est la largeur dutableau. Une formalisation possible pour tt(lg) est :

t ∈ 1 .. 2 · n → N ∧ lg ∈ inf .. 2 · n ∧ ∀i ·(i ∈ 1 .. lg − 1⇒ t(i) < t(i+ 1))⇔

t ∈ tt(lg)

Le premier conjoint précise qu’un tableau du type tt(lg) est une fonction totaledéfinie sur l’intervalle 1 .. 2 · n. Le deuxième conjoint fournit le domaine de va-riation de la largeur lg (1 .. 2 · n dans le cas de la racine, n .. 2 · n dans les autrescas). Le troisième conjoint formalise le fait que la partie utile du tableau (sa res-triction à l’intervalle 1..lg) est triée strictement par ordre croissant. Remarquonsque ces conditions impliquent que, si t ∈ tt(lg), alors 1 .. lg� t ∈ 1 .. lg�N : larestriction à 1 .. lg est injective (il n’y a pas de doublon dans la partie utile dutableau).

La formalisation de la définition du nœud d’un B-arbre exige de disposerde deux fonctions qui sont présentées ci-dessous : r, qui délivre le rayon d’unB-arbre, et A, qui délivre l’ensemble des clés présentes dans un B-arbre. Cettedernière fonction n’est autre que la fonction d’abstraction.

Le type nBA(n, inf) (un nœud d’un B-arbre) se définit alors inductivementpar :

1) a = 〈〉 ⇒ a ∈ nBA(n, inf) (6.7.1)2) a = 〈te, tl, lg〉 ∧ (6.7.2)

lg ∈ inf .. 2 · n ∧ (6.7.3)te ∈ tt(lg) ∧ (6.7.4)tl ∈ 0 .. 2 · n → nBA(n, n) ∧ (6.7.5)ran(0 .. lg � tl ; r) = {r(tl(0))} ∧ (6.7.6)

∀i ·

⎛⎝ i ∈ 1 .. lg⇒

max(A(tl(i− 1))) < te(i) ∧ min(A(tl(i))) > te(i)

⎞⎠ (6.7.7)

⇒a ∈ nBA(n, inf)

La formule 6.7.1 définit un B-arbre vide d’ordre n. Le conjoint 6.7.2 précisequ’un B-arbre non vide est un triplet. Le conjoint 6.7.3 précise le domaine de

Page 230: Structures de données et méthodes formelles ||

220 Structures de données et méthodes formelles

variation de la largeur. Le conjoint 6.7.4 type le premier constituant du triplet, letableau des clés. Le conjoint 6.7.5 type le second constituant comme un tableauqui désigne des B-arbres (dont la largeur des racines est au moins égale à n, sices B-arbres ne sont pas vides). Le conjoint 6.7.6 formalise le fait que toutes lesfeuilles sont à la même hauteur. Enfin le conjoint 6.7.7 exprime que le parcoursinfixé rencontre les valeurs dans le sens croissant 12.

Figure 6.10 – Insertion par éclatement dans un B-arbre strict.Cette figure montre l’évolution d’un B-arbre strict d’ordre deux lorsde l’insertion de la valeur 36. La partie (1) montre la localisation dela feuille où se fait l’insertion. La partie (2) illustre l’insertion propre-ment dite. La feuille modifiée devient excédentaire. La partie (3) montrel’éclatement de la feuille excédentaire suivi de l’insertion de la médianedans le nœud père. La racine devient excédentaire. Dans la partie (4)elle est éclatée, ce qui provoque l’augmentation de la hauteur de l’arbre.

La fonction r, qui délivre le rayon d’un B-arbre, se spécifie par :

function r(x) ∈ nBA(n, inf)→ N =if x = 〈〉 →

12. À cette occasion, nous rappelons que nous admettons que max(∅) = −∞ et quemin(∅) = +∞.

3 5 7 10 12 14 16 17 25 29 30 32 35 38 39 40 44 49 51 57

11 24 34 43 (1)

3 5 7 10 12 14 16 17 25 29 30 32 35 36 38 39 40 44 49 51 57

11 24 34 43 (2)

3 5 7 10 12 14 16 17 25 29 30 32 35 36 39 40 44 49 51 57

11 24 34 38 43 (3)

3 5 7 10 12 14 16 17 25 29 30 32 35 36 39 40 44 49 51 57

11 24 38 43

34 (4)

Page 231: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 221

0| x = 〈te, tl, lg〉 →

r(tl(0)) + 1fi

Cette spécification exploite le fait que les sous-arbres d’un même nœud ont tousle même rayon (celui par exemple de tl(0)) pour définir le rayon d’un B-arbrenon vide comme le rayon de son sous-arbre gauche plus un.

Les opérations de mise à jour (ajout et suppression d’un élément) rendentcependant le paramétrage du type nba plus délicat qu’il n’y paraît. Débutonsnotre réflexion par les incidences de l’adjonction d’une valeur dans un B-arbred’ordre n. Considérons le B-arbre d’ordre deux de la figure 6.10, page ci-contre,partie (1), dans lequel nous souhaitons introduire la valeur 36.

Les parties (1) et (2) montrent que la clé 36 est ajoutée dans la quatrièmefeuille de la racine, entre 35 et 38, afin de respecter la propriété qui veut qu’unnœud soit trié. Ce faisant, la feuille devient momentanément excédentaire : ellecontient 5 = 2 · n + 1 valeurs. Elle ne peut rester plus longtemps en l’état, uneadjonction ultérieure risquant d’augmenter à nouveau sa largeur.

La transition entre les parties (2) et (3) illustre l’éclatement de la feuilleexcédentaire : sa valeur médiane, 38, est remontée vers le père, entre 34 et 43.Cependant, nous avons simplement déplacé le problème : c’est maintenant lepère (la racine) qui devient excédentaire.

Il est certes possible d’éclater la racine en deux nœuds autour de la valeurmédiane 34, par contre nous ne pouvons remonter 34 dans le nœud père, celui-cin’existant pas. Il est nécessaire de le créer de toutes pièces, mais ceci se fait auprix d’un traitement ad hoc ! C’est ce qui est montré dans la partie (4).

Il est cependant parfois possible d’éviter un éclatement. En effet, si le nœudexcédentaire est frère d’un nœud pouvant encore recevoir un élément sans lui-même devenir excédentaire, il est possible d’effectuer une rotation (droite ougauche, selon que l’on s’accorde avec le frère gauche ou avec le frère droit) quiaura pour effet de retirer un élément du nœud considéré et d’en ajouter un aufrère choisi. L’avantage de cette solution est qu’une fois la rotation effectuée, iln’y aura plus aucun éclatement dans la suite du traitement puisque les rotationsdélivrent des B-arbres stricts. C’est ce que montre la figure 6.11, page suivante,dans laquelle (partie (2)) les deux frères du nœud excédentaire peuvent accueillirune valeur. La partie (3) montre le résultat d’une rotation avec le frère droit.L’arbre obtenu est un B-arbre strict. Cette décision de composer si possible avecun frère n’est pas exploitée dans le développement ci-dessous. Par contre, elle faitl’objet de l’exercice 6.7.3, page 244, dans lequel l’étude de la stratégie « rotationd’abord » est proposée.

Ce qu’il faut retenir de cette réflexion à propos de l’insertion c’est d’une partqu’un nœud doit pouvoir contenir momentanément 2 · n + 1 valeurs et d’autrepart qu’il est pratique de faire l’hypothèse que l’adjonction dans un B-arbre nechange pas son rayon. Ceci est manifestement faux dans deux cas particuliers :le cas de l’insertion dans un arbre vide (le rayon passe de zéro à un) et le cas où,après insertion, la racine devient excédentaire (il faut un traitement ad hoc afinde remonter la valeur médiane, ce qui entraîne une augmentation du rayon). Lesconséquences portent à la fois sur la définition du support et sur l’intérêt qu’il y

Page 232: Structures de données et méthodes formelles ||

222 Structures de données et méthodes formelles

a à utiliser une opération auxiliaire. Pour ce qui concerne l’opération auxiliaireeAjoutAux_b(v, b), celle-ci exploite l’hypothèse que l’insertion ne provoque pasd’augmentation du rayon de l’arbre mais, en contrepartie, elle délivre non pasun B-arbre strict mais un B-arbre dans lequel la contrainte sur la largeur de laracine est abandonnée pour accepter une racine de largeur maximum 2 · n+ 1.

Figure 6.11 – Insertion par rotation dans un B-arbre.Cette figure montre l’évolution d’un B-arbre d’ordre deux lors de l’in-sertion, par la méthode des rotations, de la valeur 36. la partie (1)montre la localisation de la feuille où se fait l’insertion. La partie (2)illustre l’insertion proprement dite. La feuille ainsi modifiée devient ex-cédentaire. La partie (3) montre comment, par une rotation droite, lafeuille rétablit son équilibre en s’allégeant d’une clé qui est transféréevers le père, alors que le père transmet une valeur au frère droit (quipouvait encore recevoir une clé sans devenir lui-même excédentaire).

Du point de vue du support concret, ceci nous oblige à ajouter un argumentau type nba, afin de rendre compte de la possibilité pour un nœud d’avoir uneborne supérieure qui peut être soit 2 · n soit 2 · n+ 1 :

concreteType nba(n, inf, sup) . . .constraints

n ∈ N1 ∧ inf ∈ N ∧ sup ∈ N ∧inf .. sup ∈ {1 .. 2 · n, n .. 2 · n, 1 .. (2 · n+ 1), n .. (2 · n+ 1)}

3 5 7 10 12 14 16 17 25 29 30 35 38 39 40 44 49 51

11 24 34 43 (1)

3 5 7 10 12 14 16 17 25 29 30 35 36 38 39 40 44 49 51

11 24 34 43 (2)

3 5 7 10 12 14 16 17 25 29 30 35 36 4338 39 44 49 51

11 24 34 40 (3)

Page 233: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 223

t ∈ 1 .. 2 · n+ 1→ N ∧ lg ∈ inf .. sup ∧ ∀i ·(i ∈ 1 .. lg − 1⇒ t(i) < t(i+ 1))⇔

t ∈ tt(lg)

1) a = 〈〉 ⇒ a ∈ nBA(n, inf, sup)2) a = 〈te, tl, lg〉 ∧

lg ∈ inf .. sup ∧te ∈ tt(lg) ∧tl ∈ 0 .. (2 · n+ 1)→ nBA(n, n, 2 · n) ∧ran(0 .. lg � tl ; r) = {r(tl(0))} ∧

∀i ·

⎛⎝ i ∈ 1 .. lg⇒

max(A(tl(i− 1))) < te(i) ∧ min(A(tl(i))) > te(i)

⎞⎠⇒

a ∈ nBA(n, inf, sup)

Considérons enfin le cas de l’opération de suppression. Soit à supprimer lavaleur 19 du B-arbre d’ordre deux de la figure 6.12, page suivante, partie (1).Supprimer simplement la valeur 19 du nœud où elle est située est impossible :d’une part il resterait encore trois sous-arbres dont l’un n’aurait pas de père etd’autre part la contrainte sur la largeur du nœud serait violée. À l’instar de cequi a été fait dans la suppression d’un arbre binaire de recherche, nous déter-minons le plus grand élément du sous-arbre à gauche de la valeur à supprimerainsi que le sous-arbre gauche privé de ce plus grand élément. Cette valeur (18ici) vient remplacer la valeur 19 supprimée (cf. figure 6.12, partie (2)). Cepen-dant, la suppression de la plus grande valeur du sous-arbre gauche produit unsous-arbre qui n’est pas un B-arbre strict : sa racine est déficitaire 13 (cf. tou-jours figure 6.12, partie (2)). La structure ne peut rester en l’état. Une solutionconsiste à fusionner le nœud déficitaire avec l’un de ses frères en y incluant le pèrecommun (cf. figure 6.12, partie (3)) 14. Ce faisant, nous n’avons fait que déplacerle problème puisque le nœud contenant 23 est momentanément déficitaire. Nouspouvons à nouveau appliquer la technique de la fusion (cf. figure 6.12, partie (4)).Une conséquence est que la racine ne contient maintenant plus aucun élément !Il faut, par une technique ad hoc, supprimer cette racine devenue inutile afind’obtenir l’arbre de la figure 6.12, partie (4), qui est un B-arbre strict.

Il faut retenir de cet exemple de suppression qu’un nœud peut devenir défi-citaire. Il faut également garder présent à l’esprit qu’une opération auxiliaire estnécessaire quand la suppression ne se fait pas sur une feuille. Cette opérationdélivre le plus grand élément d’un B-arbre strict ainsi que le B-arbre corres-pondant privé de son plus grand élément. Enfin il faut prendre conscience quenous avons implicitement fait l’hypothèse que la suppression dans un B-arbrene change pas son rayon. Cette affirmation est mise en défaut dans la situationoù la largeur de la racine est de un, l’un des fils est déficitaire et la largeur de

13. Un nœud est déficitaire s’il contient n − 1 valeurs (ou aucune valeur pour la racine« initiale »).14. Cette fusion pourrait produire un nœud excédentaire, elle n’est donc pas toujours pos-

sible. Il faut envisager une autre solution. Là encore c’est vers une « rotation » que nous noustournerons.

Page 234: Structures de données et méthodes formelles ||

224 Structures de données et méthodes formelles

Figure 6.12 – Suppression dans un B-arbre.Cette figure décrit la suppression de la valeur 19 dans un B-arbred’ordre deux. La partie (1) montre comment se fait la localisation dela valeur à supprimer. La partie (2) décrit la recherche et la suppres-sion de la plus grande clé du sous-arbre gauche de la clé supprimée. Lafeuille ainsi modifiée devient déficitaire. La partie (3) montre commentce nœud fusionne avec son frère droit et leur père en un seul nœud.La partie (4) montre la nécessité de la suppression de la racine quandcelle-ci devient vide.

1 3 5 7 8 9 11 12 13 15 18 20 22 25 29 31 34

4 10 19 23

14 (1)

1 3 5 7 8 9 11 12 13 15 20 22 25 29 31 34

4 10 18 23

14 (2)

1 3 5 7 8 9 11 12 13 15 18 20 22 25 29 31 34

4 10 23

14 (3)

1 3 5 7 8 9 11 12 13 15 18 20 22 25 29 31 34

4 10 14 23

(4)

1 3 5 7 8 9 11 12 13 15 18 20 22 25 29 31 34

4 10 14 23 (5)

Page 235: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 225

l’autre est exactement n 15 puisque nous sommes conduit à effectuer une fusionqui entraîne une diminution du rayon. Les incidences sur la structure du sup-port concret se limitent au fait que la rubrique constraints est modifiée afin derendre compte des nouvelles possibilités pour l’intervalle inf .. sup :

concreteType nba(n, inf, sup) . . .constraints

n ∈ N1 ∧ inf ∈ N ∧ sup ∈ N ∧inf .. sup ∈

{1 .. 2 · n, n .. 2 · n, 1 .. 2 · n+ 1,n .. (2 · n+ 1), 0 .. 2 · n, n− 1 .. 2 · n

}Par contre, la définition du support concret reste inchangée.

Le cas général de la suppression est traité par l’opération auxiliaireeSuppAux_b(v, b) qui exploite notamment l’hypothèse que, pour cette opéra-tion, le rayon ne change pas. Le cas particulier mentionné ci-dessus est traité demanière ad hoc par l’opération eSupp_b.

Théorème 13 (des B-arbres). Soit a ∈ nBA(n, inf, sup) tel que a = 〈te, tl, lg〉,soit v ∈ N et i ∈ 1 .. lg.

1. v ≥ te(i) ⇒ v /∈ ⋃ j ·(j ∈ 0 .. i− 1 | A(tl(j))),2. v ≤ te(i) ⇒ v /∈ ⋃ j ·(j ∈ i .. lg | A(tl(j))).

Ce théorème montre que si une valeur v est supérieure ou égale (resp. inférieureou égale) à la clé située en position i dans te, alors v n’est pas situé dans lessous-arbres placés à gauche (resp. à droite) de cette clé. La démonstration de cethéorème est laissée en exercice. Un corollaire intéressant de ce théorème est lesuivant :

Corollaire 1 (du théorème 13). Soit a ∈ nBA(n, inf, sup) tel que a = 〈te, tl, lg〉,soit v ∈ N et i ∈ 1 .. lg.(v < min(te[i .. lg]) ∧ v > max(te[1 .. i− 1])) ⇒ (v ∈ A(a)⇔ v ∈ A(tl(i− 1)))Ce corollaire affirme que si dans un B-arbre a, la valeur v est supérieure à toutesles clés de la racine situées avant la position i et inférieure à toutes les clés dela racine situées après la position i − 1, alors, si l’élément est dans l’arbre, ilest dans le sous-arbre tl(i − 1). La démonstration de ce corollaire est laissée enexercice.

Dans les calculs de complexité réalisés sur les structures de données implan-tées sur support physique externe, les opérations les plus coûteuses sont lesopérations de lecture et d’écriture depuis/vers ce support physique 16. Il est engénéral légitime de négliger les opérations réalisées sur des données présentes enmémoire centrale pour se focaliser sur le nombre d’entrées-sorties. Dans le casd’un B-arbre, ce nombre est (c’est pour le moment une simple intuition) lié aurayon de l’arbre. C’est pourquoi nous proposons d’étudier les relations qu’entre-tiennent le poids et le rayon d’un B-arbre. Nous avons le théorème suivant.

15. Cette dernière contrainte est nécessaire car, comme nous le verrons ci-dessous, si le frèrede la racine déficitaire possède plus de n éléments, il peut en céder un. Une opération derotation permet alors de préserver le rayon.16. Ces opérations sont de plusieurs ordres de grandeur plus coûteuses que les opérations en

mémoire centrale.

Page 236: Structures de données et méthodes formelles ||

226 Structures de données et méthodes formelles

Théorème 14. Dans un B-arbre d’ordre n de rayon r et de poids p

r ≤ logn+1

(p+ 1)

2+ 1. (6.7.8)

Démontrons ce théorème. Soit p(r) le poids minimum d’un B-arbre b d’ordren et de rayon r. Soit p′(r) le poids minimum d’un B-arbre régulier (c’est-à-direun B-arbre dont la racine possède au moins n clés, cf. page 217) de rayon r.Nous avons la relation suivante :

p(r) = 1 + 2 · p′(r − 1) (6.7.9)

puisque b n’a qu’une seule clé à la racine et qu’elle désigne deux B-arbres réguliersde rayon r − 1. p′ satisfait l’équation récurrente suivante :{

p′(0) = 0p′(r) = (n+ 1) · p′(r − 1) + n pour r > 0

En effet, un B-arbre de rayon 0 ne contient aucune clé et un B-arbre régulier depoids minimum et de rayon r possède n + 1 descendants de rayon r − 1 tandisque la racine héberge n clés. Il est facile d’obtenir la forme close suivante :

p′(r) = n ·r−1∑i=0

(n+ 1)i

Et, puisque, pour a = 1, ∑ki=0 a

i = ak+1−1a−1 , nous obtenons :

p′(r) = (n+ 1)r − 1

D’où, en reportant ce résultat dans la formule 6.7.9 :

p(r) = 2 ·(n+ 1)r−1 − 1

Pour un poids p quelconque, p est supérieur ou égal à p(r) :

2 ·(n+ 1)r−1 − 1 ≤ p⇔ Arithmétique

(n+ 1)r−1 ≤ p+ 1

2⇔ Passage au logn+1 et arithmétique

r ≤ logn+1

p+ 1

2+ 1

Pour n = 100, le tableau ci-dessous fournit le nombre minimum de clés (lepoids minimum) qu’il est possible d’enregistrer dans un B-arbre de rayon r.

r Poids min.2 2013 20 4014 2 060 601

Nous pouvons constater qu’un B-arbre est en général très plat (c’était l’un desobjectifs, il est atteint), il n’exige donc qu’un petit nombre d’accès pour êtreconsulté.

Page 237: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 227

6.7.3 Définition de la fonction d’abstraction

La fonction A, qui délivre l’ensemble des valeurs présentes dans un B-arbre,se définit par :

function A(x) ∈ nBA(n, inf, sup)� ensAbst =if x = 〈〉 →∅

| x = 〈te, tl, lg〉 →te[1 .. lg] ∪ ⋃ i ·(i ∈ 0 .. lg | A(tl(i)))

fi

Dans le cas d’un B-arbre non vide, cette définition affirme que l’ensemble repré-senté est l’union de l’ensemble des valeurs à la racine (te[1 .. lg]) et de l’union detoutes les valeurs présentes dans les sous-arbres de cette racine (

⋃i ·(i ∈ 0 .. lg |

A(tl(i)))).

concreteType nba(n, inf, sup) = (nBA, (eV ide_b, eAjout_b, eSupp_b),(eApp_b, eEstV ide_b))

uses bool,N,N1

constraints

n ∈ N1 ∧ inf .. sup ∈{1 .. 2 · n, n .. 2 · n, 1 .. 2 · n+ 1,n .. 2 · n+ 1, 0 .. 2 · n, n− 1 .. 2 · n

}refines ensabst(N)auxiliarySupportst ∈ 1..2 · n+ 1→ N ∧ lg ∈ inf..sup ∧ ∀i ·(i ∈ 1 .. lg − 1⇒ t(i) < t(i+ 1))

⇔t ∈ tt(lg)

support1) a = 〈〉 ⇒ a ∈ nBA(n, inf, sup)2) a = 〈te, tl, lg〉 ∧ lg ∈ inf .. sup ∧ te ∈ tt(lg) ∧

tl ∈ 0 .. 2 · n+ 1→ nBA(n, n, 2 · n+ 1) ∧ran(0 .. lg � tl ; r) = {r(tl(0))} ∧∀i ·(i ∈ 1 .. lg⇒max(A(tl(i− 1))) < te(i) ∧ min(A(tl(i))) > te(i))

⇒a ∈ nBA(n, inf, sup)

abstractionFunctionfunction A(x) ∈ nBA(n, inf, sup)� ensAbst = . . .

operationSpecifications...

end

Figure 6.13 – Spécification du type concret nba – partie 1.Cette partie concerne la définition du support.

Page 238: Structures de données et méthodes formelles ||

228 Structures de données et méthodes formelles

6.7.4 Spécification des opérations concrètes

Les figures 6.13 (page précédente) et 6.14 (page ci-contre) définissent formel-lement le type nba. Elles comprennent en particulier la spécification des deuxopérations eAjout_b et eSupp_b. Nous y retrouvons également la spécificationdu support concret ainsi que les rubriques auxiliaryOperationSpecificationset auxiliaryOperationRepresentations contenant la représentation de l’opé-ration auxiliaire r (qui fournit le rayon d’un B-arbre) et la spécification des opéra-tions eAjoutAux_b et eSuppAux_b. Notons que la précondition de l’opérationeAjoutAux_b exclut, conformément à la remarque formulée à la section 6.7.2,que b soit un arbre vide. Son codomaine précise que la racine du résultat peutêtre excédentaire. De même, le codomaine de l’opération eSuppAux_b stipuleque le résultat peut posséder une racine déficitaire.

6.7.5 Calcul de la représentation des opérations concrètes

Dans cette section nous développons le calcul de la représentation de l’opé-ration eAjout_b. Le principe de l’opération eSupp_b est évoqué et son calculest proposé en exercice.

Calcul d’une représentation de l’opération eAjout_b

Ainsi que nous l’avons dit ci-dessus, nous allons procéder à une insertionascendante, c’est-à-dire à une insertion qui effectue les rééquilibrages lors de laremontée vers la racine. Nous calculons tout d’abord la représentation de l’opéra-tion auxiliaire eAjoutAux_b(v, b). Deux hypothèses d’induction accompagnentce calcul et y sont exploitées. Elles doivent être démontrées à chaque étape decalcul. La première hypothèse postule que suite à l’insertion d’une valeur parl’opération eAjoutAux_b, la largeur de la racine s’accroît au plus de 1.

Hypothèse d’induction 3. Soit v ∈ N et b ∈ nBA(n, 1, 2 · n) − {〈〉}. Posonsb = 〈te, tl, sz〉 et eAjoutAux_b(v, b) = 〈te′, tl′, sz′〉 alors sz′ ∈ {sz, sz + 1}.

La seconde hypothèse d’induction postule que le rayon reste constant.

Hypothèse d’induction 4. Soit v ∈ N et b ∈ nBA(n, 1, 2 · n) − {〈〉}. Nousavons r(eAjoutAux_b(v, b)) = r(b).

Par ailleurs nous avons besoin d’une fonction (dénommée place) qui localisela place où devrait venir s’insérer un élément v dans un nœud t de façon àpréserver l’ordre croissant des clés. Cette fonction se spécifie dans la rubriqueauxiliaryOperationSpecifications de la manière suivante :

concreteType nba(n, inf, sup) = · · ·...

auxiliaryOperationSpecificationsfunction place(v, l, t) ∈ N× (inf .. sup)× tt(l) → 1 .. l + 1 =p : (p ∈ 1 .. l + 1 ∧ v > max(t[1 .. p− 1]) ∧ v ≤ min(t[p .. l]))

end

Page 239: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 229

concreteType nba(n, inf, sup) = · · ·...

operationSpecifications...

function eAjout_b(v, b) ∈ N× nBA(n, 1, 2 · n)→ nBA(n, 1, 2 · n) =a : (a ∈ nBA(n, 1, 2 · n) ∧ A(a) = eAjout(v,A(b)))

;function eSupp_b(v, b) ∈ N× nBA(n, 1, 2 · n)→ nBA(n, 1, 2 · n) =a : (a ∈ nBA(n, 1, 2 · n) ∧ A(a) = eSupp(v,A(b)))

...auxiliaryOperationSpecifications

function eAjoutAux_b(v, b) ∈

⎛⎝ N× nBA(n, 1, 2 · n)�→

nBA(n, 1, 2 · n+ 1)

⎞⎠ =pre

b = 〈〉then

a : (a ∈ nBA(n, 1, 2 · n+ 1) ∧ A(a) = eAjout(v,A(b)))end

;

function eSuppAux_b(v, b) ∈

⎛⎝ N× nBA(n, 1, 2 · n)→

nBA(n, 1, 2 · n)

⎞⎠ =a : (a ∈ nBA(n, 1, 2 · n) ∧ A(a) = eSupp(v,A(b)))

auxiliaryOperationRepresentationsfunction r(a) ∈ nBA(n, inf, sup)→ N = . . .

end

Figure 6.14 – Spécification du type concret nba – partie 2.La rubrique operationSpecifications du type nba spécifie deux desopérations concrètes. La rubrique auxiliaryOperationSpecificationsspécifie deux opérations : eAjoutAux_b et eSuppAux_b, qui sont desopérations auxiliaires pour l’adjonction et la suppression d’une clé. Larubrique auxiliaryOperationRepresentations fournit la signaturede l’opération r, qui délivre le rayon d’un B-arbre.

Notons que le codomaine de cette fonction précise que la valeur délivrée parl’appel peut être la borne supérieure du tableau t plus 1. C’est le cas si v estsupérieur à tous les éléments du t. Le raffinement de cette fonction est laissé enexercice.

Compte tenu de la précondition de l’opération eAjoutAux_b (b = 〈〉), il estpossible de poser b = 〈te, tl, lg〉. Le calcul débute par :

A(eAjoutAux_b(v, b))

Page 240: Structures de données et méthodes formelles ||

230 Structures de données et méthodes formelles

= Propriété caractéristique de eAjoutAux_bA(b) ∪ {v}

= HypothèseA(〈te, tl, lg〉) ∪ {v}

= Définition de Ate[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j))) ∪ {v} (6.7.10)

Nous pouvons réaliser une analyse par cas selon que v ∈ te[1 .. lg] (v estprésent dans le nœud) ou non. Si v ∈ te[1 .. lg] nous avons :

te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j))) ∪ {v}= Propriétés A.7 et A.9

te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j)))= Définition de A

A(〈te, tl, lg〉)= Hypothèse

A(b)

D’où l’équation gardée :

let 〈te, tl, lg〉 := b inv ∈ te[1 .. lg] →

eAjoutAux_b(v, b) = aend

Dans le cas où v /∈ te[1 .. lg], nous réalisons une induction sur la structure deb. Repartons de la formule 6.7.10 en supposant que le nœud considéré est unefeuille (

⋃j ·(j ∈ 0 .. lg | A(tl(j))) = ∅ ou si l’on préfère tl(0) = 〈〉). Découpons

le calcul en deux parties. La première se préoccupe de la formule te[1 .. lg] ∪ {v}et la seconde de

⋃j ·(j ∈ 0 .. lg | A(tl(j))). De façon à conserver un nœud trié,

l’insertion se fait à la position d’indice i = place(v, lg, te). Il faut donc « décaler »les clés situées entre i et lg afin de laisser un emplacement pour y enregistrer v.Commençons par éclater le tableau en deux parties :

te[1 .. lg] ∪ {v}= Propriétés B.52, D.17, B.57 puis B.121(1 .. i− 1� te)[1 .. lg] ∪ (i .. lg � te)[1 .. lg] ∪ {v} (6.7.11)

Le nouveau domaine sera l’intervalle 1 .. lg + 1. Nous allons tenter d’exprimerchacune des trois sous-formules de la formule 6.7.11 comme une image du mêmeintervalle 1 .. lg + 1. Débutons par la première sous-formule :

(1 .. i− 1� te)[1 .. lg]= Propriétés B.52 et A.26(1 .. i− 1� te)[1 .. lg + 1] (6.7.12)

Concernant la seconde formule, la restriction doit elle-même être décalée. Nousavons :

Page 241: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 231

(i .. lg � te)[1 .. lg]= Propriété B.74((i .. lg � te)� 1)[(1 .. lg)�� 1]

= Propriété D.24((i .. lg)�� 1� (te� 1))[(1 .. lg)�� 1]

= Définition 1.7.1, page 38((i+ 1 .. lg + 1)� (te� 1))[2 .. lg + 1]

= Propriété B.52(te� 1)[i+ 1 .. lg + 1 ∩ 2 .. lg + 1]

= Propriété A.26(te� 1)[i+ 1 .. lg + 1 ∩ 1 .. lg + 1]

= Calcul inverse((i .. lg � te)� 1)[1 .. lg + 1] (6.7.13)

Traitons enfin l’ensemble {v} :

{v}= Propriété B.60{i �→ v}[1 .. lg + 1] (6.7.14)

Nous pouvons à présent reprendre la formule 6.7.11 et y substituer chaque sous-formule par les résultats 6.7.12, 6.7.13 et 6.7.14 :

(1 .. i− 1� te)[1 .. lg] ∪ (i .. lg � te)[1 .. lg] ∪ {v}= Calculs ci-dessus⎛⎜⎜⎜⎜⎝

(1 .. i− 1� te)[1 .. lg + 1]∪

{i �→ v}[1 .. lg + 1]∪

((i .. lg � te)� 1)[1 .. lg + 1]

⎞⎟⎟⎟⎟⎠= Propriété B.57((1 .. i− 1� te) ∪ {i �→ v} ∪ (i .. lg � te)� 1)[1 .. lg + 1] (6.7.15)

Préoccupons-nous à présent de la seconde partie de la formule 6.7.10,⋃

j ·(j ∈0 .. lg | A(tl(j))). En prolongeant le tableau 0 .. lg � tl par un élément identiqueaux autres éléments (valant 〈〉) nous ne changeons pas la valeur de l’expression :⋃

j ·(j ∈ 0 .. lg + 1 | A((tl �− {j + 1 �→ 〈〉}(j)))) (6.7.16)= Calculs non détaillés⋃

j ·(j ∈ 0 .. lg | A(tl(j)))

La formule 6.7.10 peut maintenant se réécrire à partir des deux résultats 6.7.15et 6.7.16 :

te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j))) ∪ {v}= Calculs incidents ci-dessus⎛⎝ ((1 .. i− 1)� te ∪ {i �→ v} ∪ (i .. lg � te � 1))[1 .. lg + 1]

∪⋃j ·(j ∈ 0 .. lg + 1 | A(tl �− {lg + 1 �→ 〈〉})(j))

⎞⎠

Page 242: Structures de données et méthodes formelles ||

232 Structures de données et méthodes formelles

= Définition de A

A

⎛⎝⟨ (1 .. i− 1)� te ∪ {i �→ v} ∪ (i .. lg � te � 1),tl �− {lg + 1 �→ 〈〉},lg + 1

⟩⎞⎠Les contraintes imposées par le type nBA sont respectées, en particulier cellesportant sur les rayons et sur le caractère « arbre de recherche » de la struc-ture. D’où, d’après la propriété de l’équation à membres identiques (page 67), lapremière équation gardée pour l’opération eAjoutAux_b :

let 〈te, tl, lg〉 := b inv /∈ te[1 .. lg]→

let i := place(v, lg, te) intl(0) = 〈〉 →

eAjoutAux_b(v, b) =⟨ (1 .. i− 1� te) ∪ {i �→ v} ∪ (i .. lg � te � 1),tl �− {lg + 1 �→ 〈〉},lg + 1

⟩end

end

Les hypothèses d’induction 3 et 4 (page 228) sont satisfaites puisque d’une partla largeur du nœud s’accroît de un et d’autre part le rayon ne change pas.

Le cas inductif se caractérise par le fait que les sous-arbres ne sont pas vides.En particulier tl(0) = 〈〉. Soit i = place(v, lg, te) la position d’insertion de v dansle tableau 1 .. lg � te. En repartant de la formule 6.7.10 nous avons donc :

te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j))) ∪ {v}= Propriété A.12⎛⎜⎜⎜⎜⎜⎜⎜⎜⎝

te[1 .. lg]∪⋃j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j)))∪⋃j ·(j = i− 1 | A(tl(j)))∪

{v}

⎞⎟⎟⎟⎟⎟⎟⎟⎟⎠= Propriété A.15

te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j))) ∪ A(tl(i− 1)) ∪ {v}= Propriété caractéristique de eAjoutAux_b⎛⎝ te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j)))

∪A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠ (6.7.17)

Posons 〈te′, tl′, lg′〉 = eAjoutAux_b(v, tl(i−1)). Deux cas sont alors à considérerselon la situation de lg′ par rapport à 2 · n + 1. Si lg′ = 2 · n + 1, le sous-arbre〈te′, tl′, lg′〉 est un B-arbre strict, il peut être « accroché » à la position i − 1,« à la place » de tl(i− 1) puisque, d’après l’hypothèse d’induction 4, le rayon de〈te′, tl′, lg′〉 est égal à celui de tl(i− 1). C’est ce que nous exprimons ci-dessous :

Page 243: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 233

⎛⎝ te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j)))∪

A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠= Propriété A.15⎛⎝ te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j)))

∪⋃j ·(j = i− 1 | A(eAjoutAux_b(v, tl(i− 1))(j)))

⎞⎠= Propriété A.12 et propriété de A⎛⎝ te[1 .. lg]

∪⋃j ·(j ∈ 0 .. lg | A(tl �− {i− 1 �→ eAjoutAux_b(v, tl(i− 1))}(j)))

⎞⎠Il est alors possible d’appliquer la fonctionA à l’ensemble, car l’arbre « accroché »en i− 1 a le même rayon que les autres sous-arbres, le tout est bien un B-arbrestrict.⎛⎝ te[1 .. lg]

∪⋃j ·(j ∈ 0 .. lg | A(tl �− {i− 1 �→ eAjoutAux_b(v, tl(i− 1))}(j)))

⎞⎠= Définition de A

A(〈te, tl �− {i− 1 �→ eAjoutAux_b(v, tl(i− 1))}, lg〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), la se-conde équation gardée pour l’opération eAjoutAux_b :

let 〈te, tl, lg〉 := b inv /∈ te[1 .. lg] →

tl(0) = 〈〉 →let i, 〈te′, tl′, lg′〉 := place(v, lg, te), eAjoutAux_b(v, tl(i− 1)) in

lg′ = 2 · n+ 1→eAjoutAux_b(v, b) =

〈te, tl �− {i− 1 �→ eAjoutAux_b(v, tl(i− 1))}, lg〉end

end

Les deux hypothèses d’induction sont satisfaites : ni la largeur ni le rayon n’aug-mentent.

Si par contre lg′ = 2 · n + 1, l’arbre 〈te′, tl′, lg′〉 n’est pas un B-arbre strict.Nous ne pouvons pas simplement « accrocher » 〈te′, tl′, lg′〉 « à la place » detl(i − 1). Une solution consiste, comme nous l’avons vu dans l’exemple de lafigure 6.10, page 220, à éclater l’arbre 〈te′, tl′, lg′〉 autour de sa valeur médiane,celle-ci venant s’insérer en position i de la racine. Cette opération se spécifie dela manière suivante :

function eclatement(〈ge, gl, lg〉, 〈pe, pl, 2 · n+ 1〉, i) ∈nBA(n, 1, 2·n)× nBA(n, n, 2·n+1)× 1 .. lg+1 �→ nBA(n, 1, 2·n+1) =

prer(〈ge, gl, lg〉) = r(〈pe, pl, 2 · n+ 1〉) + 1 ∧i = place(pe(n+ 1), lg, 〈ge, gl, lg〉) ∧

Page 244: Structures de données et méthodes formelles ||

234 Structures de données et méthodes formelles

∃v ·(

v ∈ N ∧ place(v, lg, 〈ge, gl, lg〉) = i ∧A(〈pe, pl, 2 · n+ 1〉) = A(gl(i− 1)) ∪ {v}

)then

any c, re, rl wherec ∈ nBA(n, 1, 2 · n+ 1) ∧ (6.7.18)〈re, rl, lg + 1〉 ∈ nBA(n, 1, 2 · n+ 1) ∧c = 〈re, rl, lg + 1〉 ∧ (6.7.19)

A(c) =

⎛⎝ A(〈ge, gl, lg〉)−A(gl(i− 1))∪

A(〈pe, pl, 2 · n+ 1〉)

⎞⎠ ∧ (6.7.20)

r(c) = r(〈ge, gl, lg〉) (6.7.21)then

cend

end

Le premier paramètre de l’opération eclatement est l’arbre objet de l’insertion.C’est la racine. Le second paramètre est l’arbre objet de l’éclatement. Cet arbreest excédentaire, il possède une racine de longueur 2 · n+1. L’éclatement se faiten coupant cet arbre en deux moitiés plus la médiane. Le troisième paramètreest la position à laquelle se fait l’insertion de la médiane dans la racine. Dans laprécondition, le premier conjoint exprime que les rayons diffèrent de un, le secondconjoint exprime la relation qui lie le troisième paramètre aux deux premiers :c’est la position où se ferait l’insertion de la médiane dans la racine. Le troisièmeconjoint concerne une valeur v qui « aurait sa place en position i de ge ». Ilexprime que le second arbre résulte de l’insertion de cette valeur dans le sous-arbre gauche de la position d’insertion dans la racine (gl(i − 1)). Cette valeurest bien entendu celle qui a été insérée.

L’expression any exprime que l’opération délivre un B-arbre c(conjoint 6.7.18), non vide, de largeur lg + 1 (conjoint 6.7.19), représentant unensemble correspondant au premier arbre moins l’ensemble correspondant ausous-arbre gauche de la position d’insertion, union l’ensemble correspondantau second arbre (conjoint 6.7.20). Le conjoint (6.7.21) exprime que le résultatrecherché est un arbre ayant le même rayon que l’arbre 〈ge, gl, lg〉.

Cette spécification est peut-être trop forte pour avoir une solution algorith-mique ! C’est pourquoi il est important d’en exhiber une. C’est ce que nousferons ci-dessous. Pour le moment nous revenons au développement principal,en supposant disposer d’une mise en œuvre de l’opération eclatement.

Pour ce second cas, lg′ = 2 · n + 1, en repartant de la formule 6.7.17, nousavons le développement suivant :

⎛⎝ te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg − {i− 1} | A(tl(j)))∪

A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠= Propriété A.13

Page 245: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 235

⎛⎝ te[1 .. lg] ∪ (⋃ j ·(j ∈ 0 .. lg | A(tl(j)))−⋃ j ·(j = i− 1 | A(tl(j)))∪

A(eAjoutAux_b(v, tl(i− 1))))

⎞⎠= Propriété A.15⎛⎝ te[1 .. lg] ∪ (⋃ j ·(j ∈ 0 .. lg | A(tl(j)))−A(tl(i− 1)))

∪A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠= Propriété A.16⎛⎝ te[1 .. lg]−A(tl(i− 1)) ∪ (⋃ j ·(j ∈ 0 .. lg | A(tl(j)))−A(tl(i− 1)))

∪A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠= Propriété A.17⎛⎝ (te[1 .. lg] ∪ ⋃ j ·(j ∈ 0 .. lg | A(tl(j))))−A(tl(j − 1))

∪A(eAjoutAux_b(v, tl(i− 1)))

⎞⎠= Définition de A

A(b)−A(tl(i− 1)) ∪ A(eAjoutAux_b(v, tl(i− 1)))= Spécification de l’opération eclatement

A(eclatement(b, eAjoutAux_b(v, tl(i− 1)), i))

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée suivante pour l’opération eAjoutAux_b :

let 〈te, tl, lg〉 := b inv /∈ te[1 .. lg] →

let i := place(v, lg, te) intl(0) = 〈〉 →

let 〈te′, tl′, lg′〉 := eAjoutAux_b(v, tl(i− 1)) inlg′ = 2 · n+ 1→

eAjoutAux_b(v, b) =eclatement(b, eAjoutAux_b(v, tl(i− 1)), i)

endend

end

En outre, de par la spécification de l’opération eclatement, le résultat satisfaitles hypothèses d’induction 3 et 4 : la largeur de l’arbre augmente de 1, son rayonne change pas.

Au total, sous réserve de l’existence d’une mise en œuvre de l’opé-ration eclatement, nous avons calculé la version suivante de l’opérationeAjoutAux_b(v, b) :

Page 246: Structures de données et méthodes formelles ||

236 Structures de données et méthodes formelles

function eAjoutAux_b(v, b) ∈ N× nBA(n, 1, 2 · n) �→ nBA(n, 1, 2 · n+ 1) =pre

b = 〈〉then

let 〈te, tl, lg〉 := b inif v ∈ te[1 .. lg] → /*fausse insertion*/

a| v /∈ te[1 .. lg] →

let i := place(v, lg, te) inif tl(0) = 〈〉 → /*insertion aux feuilles*/⟨ (1 .. i− 1� te) ∪ {i �→ v} ∪ (i .. lg � te � 1),

tl �− {lg + 1 �→ 〈〉},lg + 1

⟩| tl(0) = 〈〉 → /*insertion nœud interne*/

let 〈te′, tl′, lg′〉 := eAjoutAux_b(v, tl(i− 1)) inif lg′ = 2 · n+ 1→

〈te, tl �− {i− 1 �→ eAjoutAux_b(v, tl(i− 1))}, lg〉| lg′ = 2 · n+ 1→

eclatement(b, eAjoutAux_b(v, tl(i− 1)), i)fi

endfi

endfi

endend

La garde v ∈ te[1 .. lg] n’est bien entendu pas implantable directement, mais ilest facile de la raffiner (par exemple en utilisant la fonction place).

Recherche d’une mise en œuvre pour l’opération eclatement

Revenons à présent sur l’opération eclatement dans le but de mettre enévidence une mise en œuvre qui satisfasse la spécification. Schématiquement, laspécification se présente sous la forme 17 :

gl(0) gl(i− 1) gl(lg) pl(0) pl(n) pl(n+ 1) pl(2 · n+ 1)

geG geD peG m peD

1 i lg 1 n+ 1 2 · n+ 1

où l’arbre de gauche (〈ge, gl, lg〉) représente l’arbre dans sa configuration ini-tiale tandis que celui de droite (〈pe, pl, 2 · n + 1〉) est le sous-arbre résultant del’adjonction dans gl(i− 1). Le schéma ci-dessous fournit une solution pour par-venir à un arbre c = 〈re, rl, lg + 1〉 répondant à la spécification de l’opérationd’éclatement.17. Voir encadré page 199.

Page 247: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 237

pl(0) pl(n) pl(n+ 1) pl(2·n+ 1)

peG peD

geG m geD

gl(0) gl(lg)

1 i lg + 1

rl(i− 1) rl(i)

re

Les arbres rl(i− 1) et rl(i) sont des B-arbres stricts ayant même rayon quegl(0) puisque l’arbre 〈pe, pl, 2 · n + 1〉 a le même rayon que gl(0). Par ailleursce sont des arbres de recherche, c satisfait donc la spécification de l’opérationd’éclatement. Dans le cas où l’invocation de l’opération eAjoutAux_b se réduità l’appel de l’opération d’éclatement, c satisfait également les hypothèses d’in-duction 3 et 4 (page 228) puisque la largeur de c est égale à celle de 〈ge, gl, lg〉plus un, et que le rayon de c est égale à celui de 〈ge, gl, lg〉. La mise en œuvrede l’opération d’éclatement se présente comme suit :

function eclatement(〈ge, gl, lg〉, 〈pe, pl, 2 · n+ 1〉, i) ∈ nBA(n, 1, 2 · n)×nBA(n, n, 2 · n+ 1)× 1 .. lg + 1 �→ nBA(n, 1, 2 · n+ 1)

prer(〈ge, gl, lg〉) = r(〈pe, pl, 2 · n+ 1〉) + 1 ∧i = place(pe(n+ 1), lg, 〈ge, gl, lg〉) ∧

∃v ·

⎛⎝ v ∈ N ∧place(v, lg, 〈ge, gl, lg〉) = i ∧A(〈pe, pl, 2 · n+ 1〉) = A(gl(i− 1)) ∪ {v}

⎞⎠then

〈(1 .. i− 1� ge) ∪ {i �→ pe(n+ 1)} ∪ (i .. lg � ge � 1),⎛⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎝

0 .. i− 2� gl∪

{i− 1 �→ 〈1 .. n� pe, 0 .. n� pl, n〉}∪⎧⎨⎩i �→⟨ (n+ 2 .. 2 · n+ 1� pe)�−(n+ 1),(n+ 1 .. 2 · n+ 1� pl)�−(n+ 1),n

⟩⎫⎬⎭∪

(i .. lg � gl)� 1

⎞⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎠,

lg + 1〉

end

Pour ce qui concerne la complexité, nous négligeons les traitements réalisés enmémoire principale pour ne retenir que le nombre de nœuds transférés entredeux niveaux de mémoire et qui est en O(1).

Page 248: Structures de données et méthodes formelles ||

238 Structures de données et méthodes formelles

Fichiers séquentiels indexés

Si aujourd’hui réaliser un système d’information ne se conçoit pas sansavoir à sa disposition un système de base de données, il n’en a pas été tou-jours ainsi. Nous avons vu (cf. encadré page 79) que les premiers systèmesd’information réalisés furent totalement « séquentiels » puisqu’implantéssur bandes magnétiques. La transition vers les bases de données s’est dé-roulée progressivement. Les mémoires secondaires à accès aléatoire (lesdisques ou tambours magnétiques) ont rendu possible l’accès direct à l’in-formation. On a alors voulu marier les avantages des deux systèmes enautorisant pour un même fichier l’accès séquentiel et l’accès direct. C’estl’origine du mode séquentiel indexé apparu dans les systèmes de gestionde fichiers au cours des années 1960.

Les schémas ci-dessus, fondés sur la métaphore de l’organisation d’unappartement de quatre pièces, illustrent les trois modes d’accès cités ci-dessus. Le schéma de gauche porte sur l’accès séquentiel : depuis le couloiron accède à la première pièce qui elle-même permet l’accès à la secondepièce, etc. Pour accéder à une pièce donnée de l’appartement il est né-cessaire de traverser toutes les pièces qui précèdent. Le schéma du milieureprésente l’accès direct : quelle que soit la pièce, il est possible de s’yintroduire directement depuis le couloir. Enfin le schéma de droite illustrele mariage des deux types d’accès : séquentiel ou direct, au choix. Notonsque l’existence de l’accès direct permet de simuler efficacement l’accès sé-quentiel. L’inverse n’est pas vrai.

Il ne restait plus, si l’on peut dire, qu’à implanter efficacement ces fi-chiers séquentiels indexés. Différentes techniques ont été proposées ayantle plus souvent en commun l’utilisation d’une variante des B-arbres. Celleconnue sous le nom de B+-arbre (cf. section 6.5.6) présente de ce pointde vue quelques avantages : un accès direct efficace rendu possible grâceà l’index, un accès séquentiel possible en tant que sous-produit du chaî-nage des enregistrements. Les fichiers séquentiels indexés n’ont pas pourautant disparu à l’avènement des bases de données, ils ont simplementquitté le devant de la scène, puisque l’implantation physique d’une re-lation dans une base de données relationnelle se fait en général par unfichier séquentiel indexé comportant un index pour l’identifiant et, selonle degré d’efficacité souhaité, un index pour les attributs les plus sollicités.

Page 249: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 239

Retour sur l’opération eAjout_b(v, b)

Souvenons-nous que l’opération eAjoutAux_b est une opération auxiliairetraitant le cas général de l’insertion dans un B-arbre à l’exclusion de l’inser-tion dans un B-arbre vide et que le résultat n’est en général pas un B-arbrestrict. Nous allons maintenant réaliser le développement de l’opération eAjout_ben introduisant, ainsi que nous l’avons prévu, un appel à la fonction auxiliaireeAjoutAux_b. Nous réalisons une analyse par cas.

A(eAjout_b(v, b))= Spécification de l’opération eAjout_b

eAjout(v,A(b))

Nous considérons tout d’abord le cas b = 〈〉 :

eAjout(v,A(b))= Hypothèse

eAjout(v,A(〈〉))= Spécification de A et de eAjout et propriété A.9

{v}= Définition de A

A(〈{1 �→ v}, {0 �→ 〈〉, 1 �→ 〈〉}, 1〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), la pre-mière équation gardée :

b = 〈〉 →eAjout_b(v, b) = 〈{1 �→ v}, {0 �→ 〈〉, 1 �→ 〈〉}, 1〉

Le second cas de l’analyse se caractérise par la condition b = 〈〉. Posonsb = 〈te, tl, lg〉. Par hypothèse b ∈ nBA(n, 1, 2 · n).

eAjout(v,A(b))= Spécification de l’opération eAjoutAux_b

A(eAjoutAux_b(v, b))

À ce stade, nous ne devons pas commettre l’erreur d’en conclure que, sousl’hypothèse de la garde b = 〈〉, eAjout_b(v, b) = eAjoutAux_b(v, b) puisquel’expression eAjoutAux_b(v, b) peut ne pas être du type requis par l’opérationeAjout_b(v, b) : en effet, par hypothèse, nous avons d’une part eAjout_b(v, b) ∈nBA(n, 1, 2 · n) et d’autre part eAjoutAux_b(v, b) ∈ nBA(n, 1, 2 · n + 1).Il convient de réaliser une (sous-)analyse par cas selon que la racine del’arbre eAjoutAux_b(v, b) est ou non excédentaire. Posons 〈te′, tl′, lg′〉 =eAjoutAux_b(v, b). Si lg′ = 2 · n + 1, la racine n’est pas excédentaire, nousavons affaire à un B-arbre strict, d’où l’équation gardée :

b = 〈te, tl, lg〉 →let 〈te′, tl′, lg′〉 := eAjoutAux_b(v, b) in

lg′ = 2 · n+ 1→eAjout_b(v, b) = 〈te′, tl′, lg′〉

end

Page 250: Structures de données et méthodes formelles ||

240 Structures de données et méthodes formelles

Si par contre lg′ = 2 · n+ 1, la racine est excédentaire, il faut ériger la médianede l’arbre 〈te′, tl′, lg′〉 en racine, comme le montre la figure 6.15 ci-dessous.

tl′(0) tl′(n) tl′(n+ 1) tl′(2 · n+ 1)

te′ te′G m te′D

1 n+ 1 2 · n+ 1(1)

tl′(0) tl′(n) tl′(n+ 1) tl′(2 · n+ 1)

te′G

1 n

te′D

1 n

m

1

(2)

Figure 6.15 – Opération eAjout_b, cas particulier.L’un des cas particuliers à traiter lors de l’adjonction d’une clé estcelui où, après l’ajout, la racine est excédentaire. Il faut alors éclaterla racine en deux parties autour de la médiane. Ces deux parties sontdes B-arbres stricts, ils deviennent fils de la médiane qui elle-mêmedevient la nouvelle racine. Le rayon augmente de un. La partie (1)présente la précondition de ce traitement tandis que la partie (2) montrela postcondition.

Il est facile d’en déduire l’équation gardée suivante :

b = 〈te, tl, lg〉 →let 〈te′, tl′, lg′〉 := eAjoutAux_b(v, b) in

lg′ = 2 · n+ 1 →eAjout_b(v, b) =〈

{1 �→ te′(n+ 1)},⎧⎪⎪⎨⎪⎪⎩0 �→ 〈1 .. n� te′, 0 .. n� tl′, n〉,

1 �→⟨ (n+ 2 .. 2 · n+ 1� te′)�−(n+ 1),(n+ 1 .. 2 · n+ 1� tl′)�−(n+ 1),n

⟩ ⎫⎪⎪⎬⎪⎪⎭ ,

1〉

end

Au total, nous avons calculé la représentation suivante de l’opérationeAjout_b :

Page 251: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 241

function eAjout_b(v, b) ∈ N× nBA(n, 1, 2 · n)→ nBA(n, 1, 2 · n) =if b = 〈〉 →

〈{1 �→ v}, {0 �→ 〈〉, 1 �→ 〈〉)}, 1〉| b = 〈te, tl, lg〉 →

let 〈te′, tl′, lg′〉 := eAjoutAux_b(v, b) inif lg′ = 2 · n+ 1→

〈te′, tl′, lg′〉| lg′ = 2 · n+ 1 →

〈{1 �→ te′(n+ 1)},⎧⎪⎪⎨⎪⎪⎩0 �→ 〈1 .. n� te′, 0 .. n� tl′, n〉,

1 �→⟨ (n+ 2 .. 2 · n+ 1� te′)�−(n+ 1),(n+ 1 .. 2 · n+ 1� tl′)�−(n+ 1),n

⟩ ⎫⎪⎪⎬⎪⎪⎭ ,

1〉

fiend

fi

Notons que l’accroissement d’un B-arbre se fait toujours par la racine. Lorsquecelle-ci est excédentaire, elle est éclatée en deux nœuds qui deviennent fils de lamédiane, cette dernière devenant la nouvelle racine.

Le nombre de nœuds lus ou écrits lors d’une insertion dans un B-arbre d’ordren et de poids p est enO(logn+1 p). En effet, l’insertion se faisant aux feuilles, pourinsérer un élément il faut descendre dans l’arbre en traversant tous les niveaux.Lors de la remontée, il peut être nécessaire de réaliser un éclatement à chaqueniveau, ce qui exige jusqu’à quatre opérations de lecture/écriture. Une écrituresupplémentaire peut être nécessaire si l’arbre voit son rayon augmenter. Comptetenu des propriétés des logarithmes, cette complexité s’exprime également sous laforme O(log p), cependant le facteur multiplicatif sous-jacent doit nous mettreen garde pour le cas où nous serions tentés d’assimiler les performances d’unB-arbre avec ceux d’un Avl dans le cas d’une utilisation pour des supportsphysiques externes : pour une même cardinalité, le rayon d’un B-arbre est engénéral très inférieur à celui d’un Avl, c’est donc une solution incomparablementplus efficace en nombre d’accès mémoire.

L’opération de suppression eSupp_b

Cette opération n’est pas calculée ici. Elle est proposée à l’exercice 6.7.1.Cependant plusieurs remarques sont à formuler. À la section 6.7.2, nous avonsdisséqué une suppression particulière (cf. figure 6.12, page 224). Nous voulonsinsister ici sur les différences qui existent entre adjonction et suppression. Alorsqu’il est toujours possible (mais pas forcément judicieux) d’effectuer les adjonc-tions en ne procédant que par éclatement, il n’est pas toujours possible de réali-ser des suppressions en n’utilisant que des fusions. La figure 6.16, page suivante,montre :

Page 252: Structures de données et méthodes formelles ||

242 Structures de données et méthodes formelles

1. un premier schéma où une fusion est impossible (les nœuds frères sontpleins) mais une rotation est alors possible (l’un des nœuds frères peutcéder une valeur) ;

2. un second schéma où une rotation est impossible (les nœuds frères sont auminimum) mais une fusion l’est (avec n’importe lequel des frères) ;

3. enfin un troisième schéma où fusion et rotation sont toutes deux possibles.À partir des deux premiers schémas de la figure 6.16, nous pouvons conclure

que si une opération (fusion ou rotation) n’est pas possible, l’autre l’est. Et àpartir du dernier schéma, nous déduisons qu’il est possible d’adopter (au moins)deux types de stratégie : « fusion d’abord » ou « rotation d’abord ». De mêmeque dans le cas des adjonctions, l’avantage d’une rotation est qu’elle bloque toutenécessité de rééquilibrage au-dessus du nœud pivot de la rotation puisque l’arbreobtenu est un B-arbre strict. La stratégie « rotation d’abord » est donc, dans lecas des suppressions ascendantes, la meilleure des deux.

Figure 6.16 – Rééquilibrage après suppression dans un B-arbre.Cette figure décrit différentes façons de rééquilibrer un B-arbre d’ordre2 présentant un nœud déficitaire suite à une suppression. La partie (1)décrit une situation où une fusion n’est pas possible mais une rotationl’est. La partie (2) montre au contraire une situation où une rotationn’est pas possible mais une fusion l’est. Enfin la partie (3) décrit unesituation où fusion et rotation sont possibles. La rotation permet tou-jours d’obtenir un B-arbre strict. Ce n’est pas toujours le cas de lafusion ainsi que le montrent les parties (2) et (3).

7 8 12 14 20 27 29 32 41

17 22(1)

7 8 12 14 20 27 29 32 41

17 22Rotation

7 8 12 15 19

10 14(2)

7 8 10 12 15 19

14Fusion

7 8 9 12 15 19

10 14(3) 7 8 9 12 14 15 19

10

7 8 10 12 15 19

9 14

Fusion

Rotation

Page 253: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 243

6.7.6 Conclusion et remarques bibliographiquesLes B-arbres ont été découverts en 1970 par R. Bayer et E. McCreight, et

publiés en 1972 [12]. Ils constituent une bonne solution pour implanter des en-sembles sur mémoires secondaires, notamment sur le plan de la complexité tem-porelle. L’administrateur doit cependant être vigilant sur l’adéquation entre lataille des unités physiques de la mémoire et la taille des nœuds. L’inconvénientprincipal concerne la place occupée puisque, dans le pire des cas, seule la moi-tié de la place allouée est véritablement occupée par de l’information utile (enmoyenne le taux de remplissage après insertion aléatoire est cependant de ln 2,cf. [75], page 489). De nombreuses variantes ont émergé depuis la découverte desB-arbres. Certaines sont proposées en exercice ci-dessous, d’autres ont déjà étéévoquées en introduction.

Rappelons tout d’abord la stratégie consistant, pour une adjonction, à ef-fectuer si possible une rotation de préférence à un éclatement (cf. figure 6.11et exercice 6.7.3). Cette variante a été suggérée par R. Bayer et E. McCreight(cf. [12], p. 256). Elle présente le double avantage de mieux remplir les nœudset de bloquer le processus d’éclatement en remontant le long du chemin de larecherche puisque dans ce cas la largeur de la racine n’augmente pas. Dans unarticle récent [107], S. Sen et R. Tarjan proposent une forme relâchée de B-arbresqui, tout en restant efficaces, permet des suppressions sans rééquilibrage. Cettesimplification s’obtient au prix d’une reconstruction périodique de l’arbre.

Nous avons vu ci-dessus la méthode des arbres externes appliquée aux ar-bres binaires. Il est possible de retenir cette technique dans le cas des B-arbres(cf. exercice 6.7.5 dans lequel nous proposons de réaliser les calculs d’opérationsavec des arbres externes, puis de renforcer le support en décomposant le min et lemax sur la structure de données lors d’un ultime raffinement). Le résultat, connusous le nom de B+-arbre, présente plusieurs avantages sur les B-arbres classiques.Le premier concerne le volume (et donc le temps de lecture ou d’écriture) d’unnœud : les niveaux intermédiaires n’ont pas besoin de contenir l’information (engénéral) associée à chaque clé. À taille égale, un nœud interne est à même derecevoir plus de clés.

Le second avantage concerne l’ouverture vers un autre type d’accès : commetoute l’information est contenue aux feuilles (les niveaux internes constituentun index), il est possible de chaîner entre elles toutes les feuilles (chaînage uni-directionnel ou bidirectionnel). Cette structure complémentaire ajoute à l’accèsdirect (ou indexé) une possibilité d’accès séquentiel aux clés depuis une clé quel-conque. Cependant, la structure ainsi complétée n’est pas « fonctionnelle » : ilest probablement impossible de la définir par un support inductif.

Exercices

Exercice 6.7.1 Calculer une version ascendante de la suppression dans les B-arbres selon lastratégie « rotation d’abord ».

Exercice 6.7.2 Considérons des B-arbres d’ordre 2 dans lesquels les mises à jour se fontde manière ascendante, l’insertion se fait par éclatement et la suppression selon la stratégie« rotation d’abord ».

Page 254: Structures de données et méthodes formelles ||

244 Structures de données et méthodes formelles

1. Montrer l’évolution que subit un B-arbre vide lors de l’ajout successif des valeurs 10,21, 32, 27, 16, 8, 19, 29, 39, 35, 23, 30, 31, 15, 17, 18 et 20.

2. Montrer l’évolution depuis un B-arbre vide en prenant la liste inverse de la liste ci-dessus.

3. On considère de manière générale les B-arbres obtenus par insertion de deux permuta-tions différentes d’une même liste de valeurs. Que peut-on dire à propos de :(a) l’identité des deux arbres,(b) le nombre de nœuds des deux arbres,(c) le taux d’occupation des deux arbres,(d) le rayon des deux arbres ?

Justifier vos réponses.4. On considère l’arbre obtenu à l’issue de la première question. Montrer comment évolue

cet arbre si l’on supprime les clés dans l’ordre inverse de l’ordre d’insertion.

Exercice 6.7.3 À la page 221 nous avons vu qu’il est parfois possible et intéressant d’effectuerdes rotations quand, lors d’une insertion, un nœud devient excédentaire. Dans cet exercice,nous proposons de réfléchir à cette solution.

1. Spécifier les opérations de rotation droite et gauche.2. Fournir une mise en œuvre de ces deux opérations.3. Dans le cas où l’insertion conduit à un nœud excédentaire, calculer une solution fondée

sur la stratégie « rotation d’abord ».

Exercice 6.7.4 Pour ce qui concerne l’insertion dans un B-arbre, ci-dessus nous n’avons déve-loppé que la méthode dite de l’insertion ascendante (celle dans laquelle l’éclatement éventuelse fait en remontant, après l’insertion dans une feuille). Il est possible d’envisager une insertiondescendante, dans laquelle les éclatements se font lors de la descente. Nous nous proposonsd’étudier cette méthode ici. Le principe est le suivant. Lors de la recherche dans un nœud a,si le fils de a dans lequel va se poursuivre la recherche est plein, la valeur médiane de ce nœudfils est remontée dans a et le nœud fils est éclaté en 2 nœuds contenant les valeurs restantes,qui deviennent les fils de la valeur remontée. Lorsque l’on atteint une feuille, celle-ci n’est paspleine (le cas échéant elle aurait été éclatée), on peut donc y effectuer l’insertion directement.

1. Montrer, sur l’exemple de la figure 6.10, page 220, comment s’effectue l’insertion de lavaleur 36.

2. La structure du support des B-arbres doit être remise en cause. Pourquoi ? Définir lenouveau support.

3. Calculer la représentation de l’opération eAjout_b qui réalise l’insertion descendante.4. L’insertion descendante revient à éclater un nœud dès que c’est possible (et non plus

dès que c’est nécessaire comme dans l’insertion ascendante). On pourrait de mêmedéfinir une suppression descendante dans laquelle la fusion de 2 nœuds se ferait dèsque c’est possible. Discuter de l’utilisation conjointe de l’insertion et de la suppressiondescendante.

Exercice 6.7.5 La version « arbre externe » des B-arbres se dénomme B+-arbres. Spécifierles B+-arbres puis calculer les différentes opérations. Raffiner par renforcement de support, endécomposant les fonctions auxiliaires utilisées sur la structure de données.

Exercice 6.7.6 (B∗-arbres) On appelle B∗-arbre d’ordre n un arbre 3 · n-aire ayant lesmêmes propriétés que les B-arbres (cf. page 216) à l’exception des points 2 et 2 bis qui sontremplacés par :

2. Chaque nœud contient entre n et 3 · n valeurs organisées en tableau, à l’exception de laracine.

2 bis. La racine contient entre 1 et 3 · n valeurs.

Étudier les B∗-arbres (spécification concrète, calcul des principales opérations) et discuter desavantages et inconvénients par rapport aux B-arbres.

Page 255: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 245

6.8 Structures autoadaptatives et analyse amor-tie : les arbres déployés

6.8.1 Introduction

Si l’on écarte les B-arbres et les techniques connexes, qui sont destinés auxensembles implantés sur des supports externes, l’intérêt des arbres équilibrés ré-side principalement dans une complexité faible et uniforme pour les opérationsclassiques. Par contre, on peut leur reprocher de conduire à des algorithmes dif-ficiles à construire qui nécessitent souvent de l’espace mémoire supplémentairepour accueillir une information sur l’équilibre des nœuds. Est-il possible d’évitercet inconvénient tout en préservant les avantages ? La réponse est oui à conditiond’avoir une exigence différente (et un peu affaiblie) pour ce qui concerne la com-plexité. Il faut alors se tourner vers des structures de données autoadaptativesauxquelles est en général associée la notion d’analyse amortie de la complexité.L’objectif de cette section est d’étudier un archétype de ces méthodes : les ar-bres déployés. Un autre exemple est étudié au chapitre 9 portant sur les files depriorité : les minimiers obliques.

Dans les arbres déployés, le rééquilibrage se fait de manière aveugle et sys-tématique. Nul besoin alors d’une information complémentaire sur l’état d’équi-libre du nœud. Concernant la complexité des opérations, celle-ci est calculéeen réalisant une (forme de) moyenne s’appliquant sur une séquence d’appels del’opération considérée. Le prix à payer est une complexité non uniforme : cer-tains appels, qui se traduisent par une profonde réorganisation de la structurede données, se révèlent alors très coûteux, mais les appels ultérieurs tirent profitde la restructuration effectuée. En moyenne, sur plusieurs appels consécutifs àl’opération, les coûts se compensent, la complexité devient acceptable. C’est leprincipe de la complexité amortie (cf. section 4.3).

Nous allons tout d’abord étudier les fondamentaux de l’insertion dans unarbre déployé. Nous calculons ensuite une représentation de l’opération d’inser-tion avant d’effectuer une analyse amortie de sa complexité. L’étude des autresopérations est proposée en exercice.

6.8.2 Principe de l’insertion dans un arbre déployé

Précisons d’emblée que le qualificatif « déployé » porte, non pas sur le supportde l’arbre, qui est celui des arbres binaires de recherche (cf. section 6.3), maissur le principe de la réorganisation qui s’applique à chaque opération. L’insertiondans un arbre déployé s’effectue toujours à la racine. Cependant, de même quedans le cas des abr quelconques (cf. section 6.3) elle peut se réaliser :

– soit par rotations après une insertion temporaire aux feuilles ;– soit en partitionnant par rapport à la valeur à insérer.

Mais dans un cas comme dans l’autre, le déploiement se caractérise par l’uti-lisation de rotations particulières. Dans cette section, nous nous intéressons àl’insertion déployée par partitionnement.

Une fois le partitionnement déployé réalisé, l’adjonction proprement dite estobtenue en enracinant les deux arbres résultant du partitionnement sur la valeur

Page 256: Structures de données et méthodes formelles ||

246 Structures de données et méthodes formelles

à insérer.Il ne s’agit pas pour l’instant de démontrer que le partitionnement réalise

effectivement une partition de l’arbre a par rapport à la valeur v. Notre objectifse limite à comprendre comment se fait la réorganisation dans le cas général.Le calcul de l’opération de partitionnement part(v, a) réalisé à la section 6.8.4montre, par induction, que le résultat est bien celui souhaité.

Dans le cas général, le partitionnement d’un arbre déployé saute d’une géné-ration à chaque étape lors de la remontée. On considère le nœud n, grand-pèrede l’arbre qui a subi le partitionnement par rapport à v. Le résultat du partition-nement à la racine n (par rapport à v) dépend de la position relative du petit-filset de son aïeul. Quatre cas peuvent être répertoriés : petit-fils gauche-gauche,gauche-droit, droit-droit et droit-gauche. Des considérations de symétrie auto-risent à n’envisager que deux cas. Pour cette raison, nous limitons notre étudeaux cas gauche-gauche (également appelé zig-zig) et gauche-droit (zig-zag).

La figure 6.17 considère le cas gauche-gauche (zig-zig) et se fonde sur l’hy-pothèse que v < m < n et donc que c’est l’arbre g qui a été partitionné parrapport à v, en fournissant le couple (g′, g′′). Le résultat est le couple à droitede la figure.

n

m

g d

r

m

g′′ n

d r

zig-zig ( g′ , )a

l l′

a′

Figure 6.17 – Déploiement de type zig-zig pour un partitionnement.Il s’agit du cas v < m < n. Le partitionnement de g a fourni le coupled’arbres (g′, g′′). Le partitionnement de l’arbre a (de racine n) fournitun couple dont les composants sont d’une part l’arbre g′ et d’autre partl’arbre 〈g′′,m, 〈d, n, r〉〉.

Le cas gauche-droite (zig-zag) est représenté à la figure 6.18, page ci-contre,et se fonde sur l’hypothèse que, puisque m < v < n, c’est le sous-arbre d qui asubi le partitionnement déployé en fournissant le couple (d′, d′′).

Ces quatre cas font tous l’hypothèse qu’il existe bien un petit-fils par rapportauquel partitionner. Si ce n’est pas le cas, aucune réorganisation n’est réaliséeet l’un des arbres du couple obtenu est vide, comme le montre le calcul de lasection 6.8.4.

6.8.3 Support concret et fonction d’abstractionRappelons tout d’abord que le type abstrait que nous cherchons à raffiner

par des arbres déployés est celui des ensembles de scalaires présenté à la fi-gure 6.1, page 149. Comme annoncé ci-dessus, la différence entre arbres binairesde recherche et arbres déployés ne porte pas sur la nature du support (ni sur lafonction d’abstraction) mais uniquement sur le traitement réalisé lors de chaqueopération. En conséquence, le type concret que nous allons utiliser est celui déjà

Page 257: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 247

n

m

g d

r

n

d′′ r

m

g d′zig-zag ( , )a

l

a′′a′

Figure 6.18 – Déploiement de type zig-zag pour un partitionnement.Il s’agit du cas m < v < n. Le partitionnement de d a fourni le coupled’arbres (d′, d′′). Le partitionnement de l’arbre a (de racine n) fournitun couple dont les composants sont les arbres a′ = 〈g,m, d′〉 et a′′ =〈d′′, n, r〉.

décrit pour les arbres binaires de recherche. La version dédiée aux arbres déployésest présentée à la figure 6.19, page 248. Celle-ci se complète de la figure 6.20,page 249, qui introduit l’opération de partitionnement part dans la spécification.

Une remarque doit être formulée à propos de l’opération eApp_ad dont leprofil n’est pas celui attendu. En principe, les opérations eApp ont comme co-domaine bool puisqu’elles délivrent soit true soit false. Ici, le domaine estbool × ead. La raison est que, comme c’est souvent le cas pour les structuresautoadaptatives, les opérations qui consultent l’état de la structure en profitentpour également réorganiser la structure. Dans le cas présent, eApp_ad effectueune consultation déployée. Elle doit donc délivrer l’arbre résultant de cette réor-ganisation. Pour des raisons de cohérence, la spécification abstraite devrait êtremodifiée en conséquence.

6.8.4 Calcul de l’opération eAjout_ad

De même que pour l’opération eAjout_a (cf. page 158), il est pratique deconsidérer que le partitionnement par rapport à v s’effectue sur un arbre privé dela clé v. Le développement de l’opération eAjout_ad se fait alors comme celuide l’opération eAjout_a, en utilisant l’opération de partitionnement part. Nousobtenons :

function eAjout_ad(v, a) ∈ N× ead→ ead =if v ∈ A(a) →

a| v /∈ A(a) →

let (l, r) := part(v, a) in〈l, v, r〉

endfi

Ici aussi un raffinement ultérieur est nécessaire afin de supprimer les référencesà la fonction d’abstraction. Cette étape est laissée en exercice.

Concernant l’opération part(v, a), dans le cas d’un arbre vide, le calcul del’équation gardée est identique à celui réalisé pour l’opération part des abr(cf. page 158) et donne :

Page 258: Structures de données et méthodes formelles ||

248 Structures de données et méthodes formelles

concreteType ead = (ead, (eV ide_ad, eAjout_ad, eSupp_ad),(eApp_ad, eEstV ide_ad))

uses bool,Nrefines ensabst(N)support

1) 〈〉 ∈ ead2) n ∈ N ∧ g ∈ ead ∧ d ∈ ead ∧ max(A(g)) < n ∧ min(A(d)) > n

⇒〈g, n, d〉 ∈ ead

abstractionFunctionfunction A(a) ∈ ead� ensAbst(N) =if a = 〈〉 →∅

| a = 〈g, n, d〉 →A(g) ∪ {n} ∪ A(d)

fioperationSpecifications

...function eAjout_ad(v, a) ∈ N× ead→ ead =b : (b ∈ ead ∧ A(b) = eAjout(v,A(a)))

;function eSupp_ad(v, a) ∈ N× ead→ ead =b : (b ∈ ead ∧ A(b) = eSupp(v,A(a)))

;function eApp_ad(v, a) ∈ N× ead� bool× ead =(eApp(v,A(a)), b : (b ∈ ead ∧ A(b) = A(a)))

...end

Figure 6.19 – Spécification du type concret ead – partie 1.Cette figure définit ou spécifie les constituants du type concret ead

permettant de représenter des ensembles par des arbres déployés. Cettespécification est complétée par la figure 6.20.

a = 〈〉 →part(v, a) = (〈〉, 〈〉)

Dans le cas d’un arbre non vide, posons a = 〈l, n, r〉 :

A′(part(v, 〈l, n, r〉))= Spécification de part

A(〈l, n, r〉)= Définition de A

A(l) ∪ {n} ∪ A(r) (6.8.1)

Page 259: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 249

concreteType ead = · · ·...

auxiliaryAbstractionFunctionfunction A′((a, b)) ∈ ead× ead� ensAbst(N) = A(a) ∪ A(b)...

auxiliaryOperationSpecificationsfunction part(v, a) ∈ N× ead �� ead× ead =pre

v /∈ A(a)then

(g, d) :

⎛⎜⎜⎜⎜⎝g, d ∈ ead× ead ∧

⎛⎜⎜⎜⎜⎝A′((g, d)) = A(a)

∧max(A(g)) < v

∧v < min(A(d))

⎞⎟⎟⎟⎟⎠⎞⎟⎟⎟⎟⎠

endend

Figure 6.20 – Spécification du type concret ead – partie 2.Cette figure complète la figure 6.19 et présente la spécification de l’opé-ration part et la fonction d’abstraction A′ qui l’accompagne.

Nous procédons à une première analyse par cas, selon la position relative de n etde v. Si v < n nous coupons « à gauche ». Une seconde analyse par cas s’imposealors, selon que l = 〈〉 ou non. Si l = 〈〉, nous poursuivons par :

A(l) ∪ {n} ∪ A(r)= Hypothèse et propriété A.9

A(〈〉) ∪ ∅ ∪ {n} ∪ A(r)= Définition de A

A(〈〉) ∪ A(〈〉) ∪ {n} ∪ A(r)= Définition de A

A(〈〉) ∪ A(〈〈〉, n, r 〉)= Définition de A′

A′((〈〉, 〈〈〉, n, r 〉))

Nous obtenons bien une partition de l’arbre a par rapport à la valeur v. D’oùl’équation gardée :

a = 〈l, n, r〉 →v < n →

l = 〈〉 →part(v, a) = (〈〉, 〈〈〉, n, r〉)

Pour le cas l = 〈〉, posons l = 〈g,m, d〉 et repartons de la formule 6.8.1 :

Page 260: Structures de données et méthodes formelles ||

250 Structures de données et méthodes formelles

A(l) ∪ {n} ∪ A(r)= Hypothèse

A(〈g,m, d〉) ∪ {n} ∪ A(r)= Définition de A

A(g) ∪ {m} ∪ A(d) ∪ {n} ∪ A(r) (6.8.2)

Afin d’obtenir une partition par rapport à v, nous allons partitionner soit l’arbreg soit l’arbre d selon la position relative de v et de m. Si v < m, nous supposons(hypothèse d’induction) que part(v, g) = (g′, g′′) :

A(g) ∪ {m} ∪ A(d) ∪ {n} ∪ A(r)= Définition de A

A(g) ∪ {m} ∪ A(〈d, n, r〉)= Spécification de part, hypothèse

A′((g′, g′′)) ∪ {m} ∪ A(〈d, n, r〉)= Définition de A′

A(g′) ∪ A(g′′) ∪ {m} ∪ A(〈d, n, r〉)= Définition de A

A(g′) ∪ A(〈g′′,m, 〈d, n, r〉〉)= Définition de A′

A′((g′, 〈g′′,m, 〈d, n, r〉〉))

Il s’agit bien d’une partition de l’arbre a par rapport à v. D’où l’équation gardée :

a = 〈l, n, r〉 →v < n →

let 〈g,m, d〉 := l inv < m →

let (g′, g′′) := part(v, g) inpart(v, a) = (g′, 〈g′′,m, 〈d, n, r〉〉)

endend

Le cas v > m se traite de manière similaire en posant (d′, d′′) = part(v, d) et enrepartant de la formule 6.8.2 :

A(g) ∪ {m} ∪ A(d) ∪ {n} ∪ A(r)= Spécification de part, hypothèse

A(g) ∪ {m} ∪ A′((d′, d′′)) ∪ {n} ∪ A(r)= Définition de A′

A(g) ∪ {m} ∪ A(d′) ∪ A(d′′) ∪ {n} ∪ A(r)= Définitions de A et de A′

A′((〈g,m, d′〉, 〈d′′, n, r〉))

Nous obtenons bien une partition de l’arbre a par rapport à v. D’où l’équationgardée :

a = 〈l, n, r〉 →v < n →

Page 261: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 251

let 〈g,m, d〉 := l inv > m →

let (d′, d′′) := part(v, d) inpart(v, a) = (〈g,m, d′〉, 〈d′′, n, r〉)

endend

Le cas v > n se traite de manière analogue. Le cas v = m ne peut survenir(v n’est pas dans l’arbre) pas plus que le cas v = n. Au total nous avons calculéla représentation suivante de part :

function part(v, a) ∈ N× ead �� ead× ead =pre

v /∈ A(a)then

if a = 〈〉 →(〈〉, 〈〉)

| a = 〈l, n, r〉 →if v < n →

if l = 〈〉 →(〈〉, 〈〈〉, n, r〉)

| l = 〈g,m, d〉 →if v < m →

let (g′, g′′) := part(v, g) in(g′, 〈g′′,m, 〈d, n, r〉〉)

end| v > m →

let (d′, d′′) := part(v, d) in(〈g,m, d′〉, 〈d′′, n, r〉)

endfi

fi| v > n →

...fi

fiend

6.8.5 Analyse amortie de l’opération eAjout_ad

Le calcul de la complexité amortie de l’opération eAjout_ad se fait bienentendu à partir du calcul de la complexité amortie de l’opération part, quiconstitue notre point de départ.

Après avoir introduit les notations et rappelé les définitions, une premièreétape consiste à mettre sous forme récurrente la fonction M(part(v, a)) quidonne la complexité amortie de l’opération part(v, a) (cf. section 4.3). La se-conde étape calcule un majorant de M(part(v, a)). Nous pourrons alors nous

Page 262: Structures de données et méthodes formelles ||

252 Structures de données et méthodes formelles

préoccuper de la complexité amortie de l’opération eAjout_ad. Au préalable,démontrons le lemme suivant qui est appliqué dans la seconde étape.

Lemme 3. Si x, y et z sont des réels positifs tels que y + z ≤ x alors

1 + log y + log z < 2 · log x (6.8.3)

Nous pouvons supposer que y ≤ z, le cas dual se traitant de manière analogue.

y + z ≤ x⇒ Hypothèse, minoration de z

y + y ≤ x⇔ Propriétés du logarithme1 + log y ≤ log x (6.8.4)

Par ailleurs :

y + z ≤ x⇒ Calcul sur R+, y > 0

z < x⇔ Propriétés du logarithmelog z < log x (6.8.5)

En ajoutant les deux inégalités 6.8.4 et 6.8.5 nous obtenons la propriété 6.8.3,ce qui achève la démonstration.

Notation. Si f est un abr, nous appelons f la fonction f ∈ ead → N1 quidélivre le poids de f plus 1 : f = w(f) + 1.

Une conséquence de cette définition est que la fonction peut aussi êtredéfinie de la manière suivante :

a ∈ ead→ N1{〈〉 = 1〈g, r, d〉 = g + d

(6.8.6)

Selon la définition 4.3.2, page 125, le coût amortiM(part(v, a)) de l’opérationde partitionnement de l’arbre a par rapport à la valeur v est donné par :

M(part(v, a)) = T (part(v, a)) + Φ(part(v, a))− Φ(a) (6.8.7)

où T (part(v, a)) est le coût « réel » d’une opération de partitionnement. Φ lafonction de potentiel à valeur dans R+ est telle que Φ(part(v, a)) est le potentielde la structure de données résultant du partitionnement et Φ(a) est le potentielde l’arbre a. Nous définissons la fonction T comme la fonction qui délivre lenombre d’appels à la fonction part. La représentation calculée ci-dessus de lafonction part permet de fournir une définition formelle de T (part(v, a)) parl’équation récurrente suivante :

Page 263: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 253

⎧⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎩

T (part(v, 〈〉)) = 1T (part(v, 〈〈〉, n, r〉)) = 1 Si v < nT (part(v, 〈l, n, 〈〉〉)) = 1 Si v > n

T (part(v, 〈〈g,m, d〉, n, r〉)) = 1 +{T (part(v, g)) Cas zig-zigT (part(v, d)) Cas zig-zag

T (part(v, 〈l, n, 〈g,m, d〉〉)) = 1 +{T (part(v, d)) Cas zig-zigT (part(v, g)) Cas zig-zag

Quant à la fonction de potentiel Φ(a), nous choisissons :⎧⎨⎩ Φ(〈〉) = 0Φ(〈g, r, d〉) = Φ(g) + ϕ(〈g, r, d〉) + Φ(d)Φ((g, d)) = Φ(g) + Φ(d)

où ϕ(a) est le logarithme de a. Dans le cas d’un arbre unique a, Φ(a) se définitdonc comme la somme, pour tous les arbres et sous-arbres s de a, de la valeurlog(s). La fonction Φ(a) satisfait les conditions imposées par la définition del’analyse amortie (cf. formule 4.3.2, page 125).

Nous sommes prêt à rechercher une forme récurrente de M(part(v, a)). Enutilisant la représentation de l’opération part calculée ci-dessus, nous procédonsà une induction sur la structure de a. Pour le cas de base a = 〈〉 nous avons :

M(part(v, a))= Hypothèse

M(part(v, 〈〉))= Définition de M

T (part(v, 〈〉)) + Φ(part(v, 〈〉))− Φ(〈〉)= Définition de T et représentation de part1 + Φ((〈〉, 〈〉))− 0

= Définition de Φ et calcul sur R+

1 + Φ((〈〉)) + Φ((〈〉))= Définition de Φ et calcul sur R+

1

Le cas de base a = 〈〈〉, n, r〉 conduit au calcul ci-dessous pour v < n :

M(part(v, a))= Hypothèse

M(part(v, 〈〈〉, n, r〉))= Définition de M

T (part(v, 〈〈〉, n, r〉)) + Φ(part(v, 〈〈〉, n, r〉))− Φ(〈〈〉, n, r〉)= Définition de T et représentation de part1 + Φ((〈〉, 〈〈〉, n, r〉))− Φ(〈〈〉, n, r〉)

= Définition de Φ et calcul sur R+

1 + Φ(〈〉) + Φ(〈〈〉, n, r〉)− Φ(〈〈〉, n, r〉)= Définition de Φ et calcul sur R+

1

Le cas inductif zig-zig, pour lequel a = 〈〈g,m, d〉, n, r〉 et v < m < n se traite dela manière suivante (les notations utilisées sont celles de la figure 6.17, page 246) :

Page 264: Structures de données et méthodes formelles ||

254 Structures de données et méthodes formelles

M(part(v, a))= Définition de M

T (part(v, a)) + Φ(part(v, a))− Φ(a) (6.8.8)= Définition de T et de part1 + T (part(v, g)) + Φ((g′, a′))− Φ(a)

= Définition de Φ et calcul sur R+

1 + T (part(v, g)) + Φ(g′) + Φ(a′)− Φ(a)

La définition deM(part(v, a)) nous permet d’exprimer T (part(v, g)) à partir deM(part(v, g)) :

T (part(v, g)) =M(part(v, g))− Φ(part(v, g)) + Φ(g)

dont la partie droite vient se substituer à T (part(v, g)) dans la formule précé-dente :

1 + T (part(v, g)) + Φ(g′) + Φ(a′)− Φ(a)= Substitution suite à la remarque ci-dessus1 +M(part(v, g))− Φ(part(v, g)) + Φ(g) + Φ(g′) + Φ(a′)− Φ(a)

= Hypothèses de la figure 6.171 +M(part(v, g))− Φ((g′, g′′)) + Φ(g) + Φ(g′) + Φ(a′)− Φ(a)

= Définition de Φ et calcul sur R+

1 +M(part(v, g))− Φ(g′)− Φ(g′′) + Φ(g) + Φ(g′) + Φ(a′)− Φ(a)= Calcul sur R+

1 +M(part(v, g))− Φ(g′′) + Φ(g) + Φ(a′)− Φ(a)= Définition de Φ et calcul sur R+

1 +M(part(v, g)) +

⎛⎝ (−Φ(g′′) + Φ(g))+(Φ(g′′) + ϕ(a′) + Φ(d) + ϕ(l′) + Φ(r))−(Φ(g) + ϕ(l) + Φ(d) + ϕ(a) + Φ(r))

⎞⎠= Calcul sur R+

1 +M(part(v, g)) + ϕ(a′) + ϕ(l′)− ϕ(a)− ϕ(l)

Le cas inductif zig-zag, pour lequel a = 〈〈g,m, d〉, n, r〉 et m < v < n se traitede manière similaire en utilisant les notations de la figure 6.18, page 247, et enrepartant de la formule 6.8.8. Nous obtenons au total :⎧⎪⎪⎨⎪⎪⎩M(part(v, 〈〉)) = 1M(part(v, 〈〈〉, n, r〉)) = 1M(part(v, a)) = 1 +

{M(part(v, g)) + ϕ(a′) + ϕ(l′)− ϕ(a)− ϕ(l) Zig-zigM(part(v, d)) + ϕ(a′) + ϕ(a′′)− ϕ(a)− ϕ(l) Zig-zag

Pour le cas du partitionnement à droite (zag-zag et zag-zig), l’expression deM(part(v, a)) est analogue, elle n’est pas représentée.

Passons à la seconde étape pour tenter de démontrer que

M(part(v, a)) < 2 + 2 · ϕ(a)

à partir de la forme récurrente deM(part(v, a)). Pour le cas de base a = 〈〉 nousavons :

Page 265: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 255

M(part(v, a)) < 2 + 2 · ϕ(a)⇔ Hypothèse

M(part(v, 〈〉)) < 2 + 2 · ϕ(〈〉)⇔ Propriétés de M(part(v, a)) et de ϕ1 < 2 + 2 · 0

⇔ Arithmétique�

Pour le second cas de base, a = 〈〈〉, n, r〉, le calcul se développe comme suit :

M(part(v, a)) < 2 + 2 · ϕ(a)⇔ Hypothèse

M(part(v, 〈〈〉, n, r〉)) < 2 + 2 · ϕ(〈〈〉, n, r〉)⇔ Propriétés de M(part(v, a)) et définition de ϕ

1 < 2 + 2 · log( 〈〈〉, n, r〉)⇔ Définition de 1 < 2 + 2 · log(〈〉+ r)

⇔ Définition de 1 < 2 + 2 · log(1 + r)

⇔ Arithmétique r ≥ 1�

Pour la partie inductive zig-zig, en utilisant les notations de la figure 6.17,page 246, et en exploitant l’hypothèse d’induction M(part(v, g)) < 2 + 2 · ϕ(g)nous avons :

M(part(v, a))= Hypothèse, cas zig-zig1 +M(part(v, g)) + ϕ(a′) + ϕ(l′)− ϕ(a)− ϕ(l)

< Hypothèse d’induction1 + 2 + 2 · ϕ(g) + ϕ(a′) + ϕ(l′)− ϕ(a)− ϕ(l)

< ϕ(g) < ϕ(l) et ϕ(a′) < ϕ(a)1 + 2 + ϕ(g) + ϕ(l) + ϕ(a) + ϕ(l′)− ϕ(a)− ϕ(l)

= Calcul sur R+

1 + 2 + ϕ(g) + ϕ(l′)< Définition de ϕ

1 + 2 + log g + log l′

< Propriété 6.8.3, page 252 (g + l′ ≤ a)2 + 2 · log a

= Définition de ϕ2 + 2 · ϕ(a)

Le cas inductif zig-zag se traite de manière similaire en utilisant les notationsde la figure 6.18, page 247 :

M(part(v, a))= Hypothèse, cas zig-zag1 +M(part(v, d)) + ϕ(a′) + ϕ(a′′)− ϕ(a)− ϕ(l)

Page 266: Structures de données et méthodes formelles ||

256 Structures de données et méthodes formelles

< Hypothèse d’induction1 + 2 + 2 · ϕ(d) + ϕ(a′) + ϕ(a′′)− ϕ(a)− ϕ(l)

< ϕ(d) < ϕ(l) et ϕ(d) < ϕ(a)1 + 2 + ϕ(l) + ϕ(a) + ϕ(a′) + ϕ(a′′)− ϕ(a)− ϕ(l)

= Calcul sur R+

1 + 2 + ϕ(a′) + ϕ(a′′)= Définition de ϕ

1 + 2 + log a′ + log a′′

< Propriété 6.8.5 (a′ + a′′ ≤ a)2 + 2 · log a

= Définition de ϕ2 + 2 · ϕ(a)

Les cas zag-zag et zag-zig sont analogues aux cas zig-zig et zig-zag. Nousavons donc démontré que

M(part(v, a)) < 2 + 2 · ϕ(a)

Il est alors facile, en exploitant la représentation de l’opérationeAjout_ad(v, a) de la page 247, d’obtenir un majorant de son coût amorti.

M(eAjout_ad(v, a))= Partitionnement + enracinement

M(part(v, a)) + 1 + Φ(〈l, v, r〉)− Φ(l)− Φ(r)

où le couple (l, r) est le résultat du partitionnement. Comment cette dernièreformule est-elle obtenue ? L’opération eAjout_ad se décompose en deux étapes,la première est le partitionnement, la seconde l’enracinement. La complexitéamortie est donc la somme de la complexité amortie de chacune des deux étapes.Celle du partitionnement M(part(v, a)) a été évaluée. Celle de l’enracinementest donnée par la formule générale (formule 4.3.2, page 125). Elle est égale aucoût réel de l’enracinement (qui est constant, nous considérons qu’il vaut 1) plusle potentiel de la structure finale, Φ(〈l, v, r〉), moins le potentiel de la structuresur laquelle s’applique l’enracinement (qui est aussi la structure résultant dupartitionnement), soit Φ(l) + Φ(r).

M(part(v, a)) + 1 + Φ(〈l, v, r〉)− Φ(l)− Φ(r)= Définition de Φ

M(part(v, a)) + 1 + Φ(l) + ϕ(〈l, v, r〉) + Φ(r)− Φ(l)− Φ(r)= Calcul sur R+

M(part(v, a)) + 1 + ϕ(〈l, v, r〉)< Complexité amortie de part2 + 2 · ϕ(a) + 1 + ϕ(〈l, v, r〉)

= Définition de ϕ, 〈l, v, r〉 = a+ 1, et arithmétique3 + 2 · log a+ log(a+ 1)

< Calcul sur R+ et propriété du logarithme3 + 3 · log(a+ 1)

Page 267: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 257

Ce dernier résultat nous permet de conclure que, si n représente le poids del’arbre a :

M(eAjout_ad(v, a)) ∈ O(log n)

6.8.6 Conclusion et remarques bibliographiques

Une première version des arbres déployés, présentée dans l’ouvrage [112] deR. Tarjan, est améliorée sur le plan de l’analyse de la complexité et publiéecollectivement avec D.D. Sleator, l’un de ses anciens étudiants de 3e cycle àStandford University (cf. [109]).

Les versions algorithmiques proposées dans [109] utilisent un lien explicitevers le père, ce qui fait perdre à la structure de données son statut de struc-ture « fonctionnelle ». Dans [93] C. Okasaki utilise une version fonctionnelle desarbres déployés pour mettre en œuvre une file de priorité (cf. section 9). Cettesolution est séduisante par sa simplicité et son élégance, principalement impu-tables au caractère inductif du support. C’est la raison pour laquelle nous noussommes inspirés de cette démarche dans le cadre d’une mise en œuvre d’un en-semble de clés. Dans [101] B. Schoenmakers présente une version apparentéeayant comme but d’exhiber le meilleur majorant pour la complexité amortie.Les développements réalisés vont au-delà des objectifs de cet ouvrage.

L’approche calculatoire dont nous nous faisons l’avocat est en partie remiseen cause par le modèle de construction sous-jacent aux arbres déployés. En effet,calculer les opérations d’une structure de données se fait en recherchant unesolution qui garantit le respect des contraintes imposées par le support. Or dansle cas des arbres déployés (et plus généralement dans le cas des structures au-toadaptatives), ce n’est plus cet objectif qui dirige le développement mais plutôtla recherche d’une solution peu coûteuse en terme d’analyse amortie.

Il est clair que le concepteur de structures de données autoadaptatives adopteune démarche empirique principalement fondée sur la découverte intuitive de lastructure de données, des heuristiques d’équilibrage qui l’accompagnent et d’unefonction de potentiel convenable. À terme cette approche n’est pas raisonnablecar peu constructive et laissant trop de place à l’empirisme. On note actuelle-ment une tendance à dériver la fonction de potentiel plutôt que de la deviner(cf. [69, 101, 62]). Cette orientation va selon nous dans le bon sens, mais elle estscientifiquement exigeante et nous sommes encore loin d’une véritable méthodo-logie.

Exercices

Exercice 6.8.1 Calculer une représentation des opérations eApp_ad, eSupp_ad. Effectuerune analyse amortie de chaque opération.

Exercice 6.8.2 Dans l’article [109], les auteurs proposent une version semi-adaptative dudéploiement. Celui-ci s’effectue comme décrit ci-dessus (cf. section 6.8.2) sauf dans le cas zig-zag (et dans le cas symétrique zag-zig) où le déploiement s’effectue comme le montre le schémaci-dessous :

Page 268: Structures de données et méthodes formelles ||

258 Structures de données et méthodes formelles

z

y

x

A B

C

D

y

x

A B

z

C D

et se poursuit sur y.1. Montrer que la profondeur des nœuds rencontrés sur le chemin de la recherche diminue

au moins de moitié à chaque déploiement.2. Mettre en œuvre cette solution en calculant l’opération eAjout_ad.3. Quel est le coût amorti d’un déploiement ?

Exercice 6.8.3 Dans les articles [8, 16], les auteurs proposent deux heuristiques pourconstruire des arbres binaires de recherche autoadaptatifs. La première consiste à effectuerune seule rotation simple sur le père d’un nœud auquel on a accédé (pour le consulter, l’insérerou supprimer l’un des fils). La seconde consiste à amener le nœud en question à la racine pardes rotations simples réalisées sur le chemin de la recherche.

1. Comparer l’anatomie de l’insertion des valeurs successives 40, 23, 56, 36, 10, 7, 34, 62,16, 24, 55, 19, 29 et 32 pour les deux heuristiques.

2. Effectuer une analyse amortie la plus ajustée possible. Conclusion ?

6.9 Méthodes aléatoires : les treaps randomisésCette section est consacrée à une méthode de représentation d’ensembles de

scalaires qui s’avère simple, bien que relativement récente puisqu’elle a vu lejour au début de la quatrième période de l’histoire des structures de données,celle des structures aléatoires. Nous débutons par une définition de la notionde treap, indépendamment de l’aspect aléatoire qui est traité ensuite. Le termetreap est un mot valise issu de tree (arbre) et heap (tas). Un treap randomiséest fondamentalement un abr. Cependant, comme les abr ont une « tendancenaturelle » à perdre leur (éventuel) caractère aléatoire au fil des mises à jour,l’idée qui prévaut ici est d’ajouter artificiellement une composante aléatoire àl’abr afin de garantir, avec une très forte probabilité, de bonnes performancespour toutes les opérations du type abstrait.

Plus précisément le principe des treaps est le suivant. On définit une fonctioninjective prio (pour priorite) sur le domaine des clés et à valeur dans N. Untreap est alors un abr sur la clé et un minimier sur la valeur de la fonction prio.Ainsi, par exemple, avec les 16 clés du tableau 6.1, page ci-contre, et les prioritésassociées nous obtenons le treap de la figure 6.21, page ci-contre.

6.9.1 Définition du support concretLe support des treaps, eTrp, possède les mêmes caractéristiques que le sup-

port des abr, auxquelles s’ajoute le fait que l’arbre est un minimier sur la fonctionprio. Cette dernière fonction n’est pas précisée pour l’instant, elle s’ébauche par :

function prio(v) ∈ N� N = . . .

et soit la fonction Prio(a), telle que :

Page 269: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 259

Tableau 6.1 – Clés avec leurs priorités.Le tableau représente 16 clés et leurs priorités. Celles-ci sont toutesdifférentes.

num. clé prio. num. clé. prio.1 4 18 9 18 132 7 15 10 20 203 9 29 11 22 74 10 21 12 24 245 12 10 13 27 126 13 28 14 30 227 14 17 15 34 88 16 27 16 39 19

227

1210

715

418 1021

929

1813

1417

1328 1627

2020

348

2712

2424 3022

3919

Figure 6.21 – Treap de 16 nœuds.Ce treap correspond aux clés du tableau 6.1. Les priorités sont placéesen indice des clés. L’arbre est un abr selon la clé et un minimier selonla priorité.

function Prio(a) ∈ eTrp→ N = . . .

qui délivre la priorité de la racine de a (ou ∞ si l’arbre est vide).

1) 〈〉 ∈ eTrp2) n ∈ N ∧ g ∈ eTrp ∧ d ∈ eTrp ∧

max(A(g)) < n ∧min(A(d)) > n ∧ prio(n) < min({Prio(g), P rio(d)})⇒

〈g, n, d〉 ∈ eTrp

Dans cette définition, A(a) représente la fonction qui délivre l’ensemble des clésde l’arbre a. C’est aussi la fonction d’abstraction du support eTrp.

6.9.2 Définition de la fonction d’abstraction

La fonction d’abstraction A est identique à la fonction d’abstraction des abr :

Page 270: Structures de données et méthodes formelles ||

260 Structures de données et méthodes formelles

function A(a) ∈ eTrp� ensAbst(N) =if a = 〈〉 →∅

| a = 〈g, n, d〉 →A(g) ∪ {n} ∪ A(d)

fi

6.9.3 Spécification des opérations concrètes

La figure 6.22 ci-dessous synthétise la spécification concrète du type etrp.Cette spécification est similaire à celle des abr. Elle inclut en particulier la spé-cification concrète des deux opérations de mise à jour.

concreteType etrp = (eTrp, (eV ide_tp, eAjout_tp, eSupp_tp),(eApp_tp, eEstV ide_tp))

uses bool,Nrefines ensabst(N)support

1) 〈〉 ∈ eTrp2) n ∈ N ∧ g ∈ eTrp ∧ d ∈ eTrp ∧max(A(g)) < n ∧min(A(d)) > n

prio(n) < min({Prio(g), P rio(d)})⇒

〈g, n, d〉 ∈ eTrpabstractionFunction

function A(a) ∈ eTrp� ensAbst(N) = . . .operationSpecifications

...function eAjout_tp(v, a) ∈ N× eTrp→ eTrp =b : (b ∈ eTrp ∧ A(b) = eAjout(v,A(a)))

;function eSupp_tp(v, a) ∈ N× eTrp→ eTrp =b : (b ∈ eTrp ∧ A(b) = eSupp(v,A(a)))

...end

Figure 6.22 – Spécification du type concret etrp.Il s’agit d’un spécification concrète du type ensabst de la figure 6.1,page 149. Le support concret est un treap de naturels. La fonction d’abs-traction est détaillée ci-dessus.

6.9.4 Calcul de la représentation des opérations concrètes

Nous ne développons que les deux opérations de mise à jour eAjout_tp eteSupp_tp. Les autres opérations sont identiques à celles obtenues pour les abr.Parmi tous les abr possibles pour un ensemble donné de clés, il faut retenir leseul qui soit aussi un minimier sur la priorité de chaque clé.

Page 271: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 261

Calcul d’une représentation de l’opération eAjout_tp

Partant de la formule A(eAjout_tp(v, a)), nous obtenons pour le cas de baseoù a = 〈〉 la même équation gardée que dans le cas des abr :

a = 〈〉 →eAjout_tp(v, a) = 〈〈〉, v, 〈〉〉

Pour le cas inductif (a = 〈g, n, d〉), si v = n (cas d’une fausse insertion), lerésultat obtenu est trivial :

a = 〈g, n, d〉 →v = n →

eAjout_tp(v, a) = a

Si v < n, le début du calcul est identique au calcul réalisé pour les abr jusqu’àla formule :

A(eAjout_tp(v, g)) ∪ {n} ∪ A(d) (6.9.1)

Cependant, compte tenu de la nature du support qui impose à l’arbre d’être unminimier sur la priorité, il est impossible d’appliquer systématiquement la défi-nition de la fonction d’abstraction à cette expression. Il nous faut procéder à uneanalyse par cas selon la situation relative des valeurs Prio(eAjout_tp(v, g)) etprio(n). Si Prio(eAjout_tp(v, g)) > prio(n), la définition de la fonction d’abs-traction s’applique et nous avons :

A(eAjout_tp(v, g) ∪ {n} ∪ A(d))= Définition de A

A(〈eAjout_tp(v, g), n, d〉)

Nous avons alors calculé l’équation gardée suivante :

a = 〈g, n, d〉 →v < n →

let 〈l, u, r〉 := eAjout_tp(v, g) inprio(u) > prio(n) →

eAjout_tp(v, a) = 〈〈l, u, r〉, n, d〉end

Par contre, si Prio(eAjout_tp(v, g)) < prio(n) 18, nous devons transformer l’ex-pression de façon à être en mesure d’appliquer la fonction d’abstraction. Pourcela, posons 〈l, u, r〉 = eAjout_tp(v, g). En repartant de la formule 6.9.1 nousavons :

A(eAjout_tp(v, g)) ∪ {n} ∪ A(d)= Hypothèse

A(〈l, u, r〉) ∪ {n} ∪ A(d)

18. Le cas Prio(eAjout_tp(v, g)) = prio(n) est impossible compte tenu du caractère injectifde la fonction prio.

Page 272: Structures de données et méthodes formelles ||

262 Structures de données et méthodes formelles

= Définition de A(A(l) ∪ {u} ∪ A(r)) ∪ {n} ∪ A(d)

= Propriété A.8A(l) ∪ {u} ∪ (A(r) ∪ {n} ∪ A(d))

= Définition de AA(〈l, u, 〈r, n, d〉〉)

Ce faisant, nous avons réalisé une rotation droite 19. D’où l’équation gardée :

a = 〈g, n, d〉 →v < n →

let 〈l, u, r〉 := eAjout_tp(v, g) inprio(u) < prio(n) →

eAjout_tp(v, a) = 〈l, u, 〈r, n, d〉〉end

Le cas v > n se traite de manière identique. Au total, nous avons calculé lareprésentation suivante de l’opération eAjout_tp :

function eAjout_tp(v, a) ∈ N× eTrp→ eTrp =if a = 〈〉 → /*insertion aux feuilles*/

〈〈〉, v, 〈〉〉| a = 〈g, n, d〉 →

if v = n → /*fausse insertion*/a

| v < n → /*insertion à gauche*/let 〈l, u, r〉 := eAjout_tp(v, g) in

if prio(u) < prio(n) → /*rotation droite*/〈l, u, 〈r, n, d〉〉

| prio(u) > prio(n) →〈〈l, u, r〉, n, d〉

fiend

| v > n → /*insertion à droite*/...

fifi

Cette fonction s’interprète de la manière suivante : pour insérer une clé v dansun treap, nous commençons par effectuer une insertion aux feuilles. En générall’arbre n’est alors pas encore un treap. Il faut remonter la valeur le long duchemin de la racine jusqu’à obtention d’un treap. Cette remontée se fonde surla position relative des priorités de la clé et du nœud père pour éventuellementréaliser une rotation. C’est ce que montre la figure 6.23, page 267, lue de manièreascendante : la valeur 12 étant supposée insérée aux feuilles (partie (6)) sa priorité

19. Nous savons, depuis la section 6.3.4, que les rotations préservent à la fois les valeurs dansleur ensemble et le caractère abr de l’arbre.

Page 273: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 263

est comparée à celle de son père 9. Il apparaît que l’arbre n’est pas un treap,nous réalisons donc une rotation gauche et obtenons l’arbre (5). Le processus estréitéré jusqu’à obtention d’un treap (partie (1)).

Nous reviendrons sur la question de la complexité mais pour l’instant il estfacile de se convaincre que si l’arbre était aléatoire le coût de l’insertion seraitcelui de l’insertion dans un abr auquel s’ajouterait le coût de la remontée partiellede la clé. La complexité serait en O(log n) pour un arbre de poids n.

Calcul d’une représentation de l’opération eSupp_tp

À la section 6.3.4, nous avons affirmé que la suppression dans les abr détruitl’éventuel caractère aléatoire de l’abr considéré. Si, comme c’est le cas ici, notreobjectif est de préserver cette propriété, nous devons être vigilants dans le calculde cette opération. Ainsi que nous le verrons, l’existence de la priorité nouspermet d’arriver à notre fin. Le principe que nous appliquons est le suivant : soita un treap, soit a′ le treap résultat de l’insertion de v dans a. Après suppressionde v dans a′, nous devons retrouver l’arbre initial a intact. Le cas de base oùa = 〈〉 (fausse suppression) est trivial. Il conduit à l’équation gardée :

a = 〈〉 →eSupp_tp(v, a) = a

Pour l’étape inductive, le début du calcul est similaire au cas des abr. Posonsa = 〈g, n, d〉 :

A(eSupp_tp(v, a))= Propriété caractéristique de eSupp_tp

A(〈g, n, d〉)− {v} (6.9.2)= Définition de A(A(g) ∪ {n} ∪ A(d))− {v} (6.9.3)

Procédons à une analyse par cas en distinguant les deux cas g = 〈〉 ∧ d = 〈〉 etg = 〈〉 ∨ d = 〈〉. Débutons par le premier cas :

(A(g) ∪ {n} ∪ A(d))− {v}= Hypothèse et définition de A(∅ ∪ {n} ∪ ∅)− {v}

= Propriété A.9{n} − {v} (6.9.4)

Deux cas sont à considérer : v = n (vraie suppression) et v = n (fausse suppres-sion). Débutons par le cas v = n :

{n} − {v}= Hypothèse et propriété A.18∅

= Définition de AA(〈〉)

D’où la seconde équation gardée :

Page 274: Structures de données et méthodes formelles ||

264 Structures de données et méthodes formelles

a = 〈g, n, d〉 →g = 〈〉 ∧ d = 〈〉 →

v = n →eSupp_tp(v, a) = 〈〉

Quant au cas v = n, il se développe à partir de la formule 6.9.4 :

{n} − {v}= Hypothèse et propriété A.16

n= Propriété A.9(∅ ∪ {n} ∪ ∅)− {v}

= Définition de AA(〈〈〉, n, 〈〉〉)

D’où l’équation gardée suivante :

a = 〈g, n, d〉 →g = 〈〉 ∧ d = 〈〉 →

v = n →eSupp_tp(v, a) = 〈〈〉, n, 〈〉〉

Le cas g = 〈〉 ∨ d = 〈〉 se développe en effectuant une analyse par cas incidentesur la position relative de v et de n. Débutons par le cas v = n. Ce cas exige dedistinguer la situation où v < n de celle où v > n. Le développement est alorssimilaire à celui réalisé pour les abr. Nous obtenons (pour v < n par exemple)l’équation gardée suivante :

a = 〈g, n, d〉 →g = 〈〉 ∨ d = 〈〉 →

v = n →v < n →

eSupp_tp(v, a) = 〈eSupp_tp(v, g), n, d〉

Considérons à présent le cas v = n. Trois sous-cas sont à étudier : g = 〈〉, d = 〈〉,et g = 〈〉 ∧ d = 〈〉. Pour le cas g = 〈〉, nous pouvons poser d = 〈ld, ud, rd〉puisque d n’est pas vide. En repartant de la formule 6.9.2 nous avons alors :

A(〈g, n, d〉)− {v}= Hypothèse (v = n)

A(〈〈〉, v, 〈ld, ud, rd〉〉)− {v}= Rotation (non détaillée)

A(〈〈〈〉, v, ld〉, ud, rd〉)− {v}= Définition de A et v /∈ ({ud} ∪ A(rd))(A(〈〈〉, v, ld〉)− {v}) ∪ {ud} ∪ A(rd)

= Propriété caractéristique de eSupp_tpA(eSupp_tp(v, 〈〈〉, v, ld〉)) ∪ {ud} ∪ A(rd)

= Définition de AA(〈eSupp_tp(v, 〈〈〉, v, ld〉), ud, rd〉)

Page 275: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 265

D’où l’équation gardée :

a = 〈g, n, d〉 →g = 〈〉 ∨ d = 〈〉 →

v = n →g = 〈〉 →

let 〈ld, ud, rd〉 := d ineSupp_tp(v, a) = 〈eSupp_tp(v, 〈〈〉, v, ld〉), ud, rd〉

end

Le cas d = 〈〉 se traite de manière analogue. Reste à considérer le cas g =〈〉 ∧ d = 〈〉. Nous pouvons poser g = 〈lg, ug, rg〉 et d = 〈ld, ud, rd〉. En repartantde la formule 6.9.2 nous avons :

A(〈g, n, d〉)− {v}= Hypothèse (v = n)

A(〈〈lg, ug, rg〉, v, 〈ld, ud, rd〉〉)− {v} (6.9.5)

De façon à préserver le caractère de minimier à l’arbre (exception faite du nœudv qui est destiné à disparaître) nous devons distinguer deux cas : prio(ug) >prio(ud) et prio(ug) < prio(ud). Dans le premier cas, nous effectuons une rota-tion gauche à la racine :

A(〈〈lg, ug, rg〉, v, 〈ld, ud, rd〉〉)− {v}= Hypothèse

A(〈g, v, 〈ld, ud, rd〉〉)− {v}= Rotation

A(〈〈g, v, ld〉, ud, rd〉)− {v}= Définition de A(A(〈g, v, ld〉)− {v}) ∪ {ud} ∪ A(rd)

= Propriété caractéristique de eSupp_tpA(eSupp_tp(v, 〈g, v, ld〉) ∪ {ud} ∪ A(rd)

= Définition de AA(〈eSupp_tp(v, 〈g, v, ld〉), ud, rd〉)

D’où l’équation gardée :

a = 〈g, n, d〉 →g = 〈〉 ∧ d = 〈〉 →

v = n →let 〈lg, ug, rg〉, 〈ld, ud, rd〉 := g, d in

prio(ug) > prio(ud) →eSupp_tp(v, a) = 〈eSupp_tp(v, 〈g, v, ld〉), ud, rd〉

end

Le cas prio(ug) < prio(ud) se traite de manière similaire. Au total, nous obtenonsla version suivante de l’opération eSupp_tp :

Page 276: Structures de données et méthodes formelles ||

266 Structures de données et méthodes formelles

function eSupp_tp(v, a) ∈ N× eAbr→ eAbr =if a = 〈〉 → /*fausse suppression*/

a| a = 〈g, n, d〉 in

if g = 〈〉 ∧ d = 〈〉 →if v = n → /*vraie suppression*/

〈〉| v = n → /*fausse suppression*/

〈〈〉, n, 〈〉〉fi

| g = 〈〉 ∨ d = 〈〉 →if v = n →

if v < n → /*suppression à gauche*/〈eSupp_tp(v, g), n, d〉

| v > n → /*suppression à gauche*/〈g, n, eSupp_tp(v, d)〉

fi| v = n →

if g = 〈〉 →let 〈ld, ud, rd〉 := d in

〈eSupp_tp(v, 〈〈〉, v, ld〉), ud, rd〉end

| d = 〈〉 →let 〈lg, ug, rg〉 := g in

〈lg, ug, eSupp_tp(v, 〈rg, v, 〈〉〉)〉end

| g = 〈〉 ∧ d = 〈〉 →let 〈lg, ug, rg〉, 〈ld, ud, rd〉 := g, d in

if prio(ug) > prio(ud) →〈eSupp_tp(v, 〈g, v, ld〉), ud, rd〉

| prio(ug) < prio(ud) →〈lg, ug, eSupp_tp(v, 〈rg, v, d〉)〉

fiend

fifi

fifi

Cette fonction commence par localiser la clé à supprimer en partant de la racine.Une fois localisée, cette valeur est amenée en position de feuille par rotationssoit gauches soit droites de façon à préserver le caractère minimier de l’arbre.La figure 6.23, page ci-contre, lue de haut en bas dissèque la suppression de lavaleur 12 suite à la localisation du nœud dans l’arbre. Les rotations nécessairessont grisées. Il s’agit donc du « détricotage » de ce qui a été réalisé lors del’insertion de la valeur 12. Cette technique présente l’avantage de permettre dene raisonner que sur l’une des deux opérations pour, par exemple, déterminer

Page 277: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 267

leurs complexités. Ainsi, si sous certaines conditions l’insertion est en O(log n),la suppression l’est également.

227

1210

715

418 1021

929

1813

1417

1328 1627

2020

348

2712

2424 3022

3919227

1813

1210

715

418 1021

929

1417

1328 1627

2020

348

2712

2424 3022

3919

227

1813

1417

1210

715

418 1021

929

1328

1627

2020

348

2712

2424 3022

3919227

1813

1417

715

418 1210

1021

929

1328

1627

2020

348

2712

2424 3022

3919

227

1813

1417

715

418 1021

1210

929

1328

1627

2020

348

2712

2424 3022

3919227

1813

1417

715

418 1021

929

1210

1328

1627

2020

348

2712

2424 3022

3919

(1)

(2)

(3)

(4)

(5)

(6)

Figure 6.23 – Ajout/suppression de la clé 12 dans un treap.Le treap est celui correspondant aux clés du tableau 6.1. Les prioritéssont placées en indice des clés. Selon que l’on lise la figure en descen-dant, du schéma (1) jusqu’au schéma (6) ou au contraire en remontant,du schéma (6) jusqu’au schéma (1), on dissèque la suppression ou l’ad-jonction de la valeur 12. Les branches grisées représentent les rotations.

Page 278: Structures de données et méthodes formelles ||

268 Structures de données et méthodes formelles

6.9.5 Renforcer ou non le support ?

Nous disposons à présent d’un type concret pour les treaps. Ainsi que nousl’avons vu aux sections 1.10 et 2.4 portant sur le renforcement du support, lafonction prio peut soit être décomposée sur le support, soit être recalculée àchaque fois qu’elle est appliquée. Il existe un cas cependant où il est impossiblede choisir cette seconde solution, c’est celui où la fonction est non déterministe :nous devons calculer la fonction en un point une fois pour toutes et enregistrersa valeur dans la structure de données.

Dans ce cas, le renforcement du support nous conduit à ajouter un champassocié à la clé, puis à aménager les opérations.

Version aménagée de l’opération eAjout_tp

Pour l’opération eAjout_tp nous obtenons :

function eAjout_tp(v, a) ∈ N× eTrp→ eTrp =if a = 〈〉 →

〈〈〉, (v, prio(v)) , 〈〉〉| a = 〈g, (n, p) , d〉 →

if v = n →a

| v < n →let 〈l, (u, q) , r〉 := eAjout_tp(v, g) in

if q < p →〈l, (u, q) , 〈r, (n, p) , d〉〉

| q > p →〈〈l, (u, q) , r〉, (n, p) , d〉

fiend

| v > n →...

fifi

La priorité d’une clé est introduite dès que la clé est ajoutée comme feuille dansl’arbre. Les conditions qui s’exprimaient précédemment à partir de la fonctionprio s’expriment maintenant directement à partir du nouveau champ.

Nous sommes à présent prêt à introduire l’aspect aléatoire et à en étudier lesconséquences.

6.9.6 Treaps randomisés

Pour l’instant nous n’avons fait aucune hypothèse sur la nature de la fonc-tion prio autre que son caractère injectif. Si prio délivre des valeurs qui sont

Page 279: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 269

des variables aléatoires continues indépendantes et identiquement distribuées, letreap est qualifié de randomisé. Dans [105], puis dans [106], C. Aragon et R. Sei-del montrent que la forme des arbres obtenus présente la même distribution deprobabilité que celle des abr aléatoires (cf. section 6.3.4). Le caractère aléatoirede prio est en quelque sorte transmis par osmose à l’arbre tout entier.

Si, pour un arbre de poids n, la fonction prio résulte d’une permutationaléatoire uniforme des valeurs de l’intervalle 1 .. n, l’arbre est appelé arbre car-tésien (d’après [115]). Là aussi les arbres obtenus se comportent comme des abraléatoires. Concrètement, cela signifie que la hauteur d’un treap randomisé depoids n comme celle d’un arbre cartésien de même poids se comporte asympto-tiquement comme le logarithme de n, avec une très forte probabilité. Mettre enœuvre des treaps randomisés exige cependant de surmonter quelques difficultés.La première tient tout d’abord à l’aspect continu de la fonction prio, qui nepeut être réalisé que de manière très approximative dans le contexte discret del’informatique 20. Mais l’exigence de continuité n’est présente que pour garantirl’absence absolue de doublon lors du tirage de la priorité. C. Aragon et R. Seidelmontrent que les résultats obtenus restent valables si la probabilité d’obtenir desdoublons est faible. Cela signifie qu’il est possible d’effectuer un tirage aléatoireuniforme sur un intervalle d’entiers tel que 0 .. 232 − 1.

Par ailleurs, par son caractère non déterministe, le procédé utilisé pour créerdes treaps randomisés oblige à avoir recours à la technique du renforcementdu support appliquée ci-dessus (puisque deux tirages différents pour une mêmeclé vont fournir avec une quasi-certitude deux valeurs différentes). Ce qui dupoint de vue de la complexité spatiale est une solution pénalisante. C. Aragon etR. Seidel montrent qu’il est possible de réduire la taille de ce nouveau champ eneffectuant des calculs modulo. Une méthode astucieuse a été suggérée aux auteurspar D. Sleator afin d’éliminer purement et simplement le champ supplémentaire.Il s’agit d’utiliser comme fonction prio une fonction de hachage h ayant commeargument la clé c. Cette valeur de hachage n’exige en effet pas d’être mémoriséepuisqu’elle peut être recalculée quand nécessaire. Certes, on a alors échangé de laplace contre du temps puisque h(c) sera calculée fréquemment, mais le problèmeprincipal est alors de disposer d’une fonction h suffisamment bonne pour simulerl’aléatoire 21.

Pour ce qui concerne l’utilisation des arbres cartésiens, l’obstacle principalest qu’a priori la taille de l’arbre à construire n’est en général pas connue. Sicette contrainte est sans objet, il est facile, à partir d’un générateur de nombresaléatoires quelconque 22, de simuler une permutation aléatoire de l’intervalle 1..n.Voir par exemple [116], section 2.3, page 11, pour un algorithme très performant.

20. Si l’on écarte l’exploitation de phénomènes physiques extérieurs comme la radioactivité.21. La fonction suggérée à la section 6.4.6 ne présente pas de ce point de vue de garanties

suffisantes. Cf. [75] pour un développement sur ce sujet.22. On dispose aujourd’hui de puces spécialisées dans la génération de nombres aléatoires

(cf. [100] par exemple) permettant de s’affranchir du caractère pseudo-aléatoire des générateurslogiciels.

Page 280: Structures de données et méthodes formelles ||

270 Structures de données et méthodes formelles

6.9.7 Conclusion et remarques bibliographiques

La notion d’algorithme aléatoire (ou probabiliste) est ancienne. Outre le do-maine de la simulation où l’aléatoire est omniprésent, de nombreux algorithmestrès efficaces sont fondés sur une démarche probabiliste : c’est le cas de la mé-thode de Monte-Carlo (pour le calcul d’intégrales en particulier), de certainstests de primalité, de la recherche de patrons dans les chaînes, etc. (cf. [17] parexemple pour plus de détails). L’un des spécialistes du domaine, M.O. Rabin, aobtenu (avec D. Scott) la distinction Turing Award en 1976. Il n’est donc passurprenant que l’idée d’appliquer une démarche probabiliste aux structures dedonnées ait émergé.

L’avantage de la technique étudiée ci-dessus est qu’elle permet de s’affranchirde l’hypothèse de l’équiprobabilité des n! tirages d’entrée tout en évitant lesarbres dégénérés avec une forte probabilité.

Les arbres cartésiens ont été découverts par J. Vuillemin en 1980 [115]. Unevariante, dans laquelle la priorité est remplacée par le poids de l’arbre – faisantd’eux des minimiers (ou tournois) de position – a été étudiée dans le mêmearticle (ainsi que dans [116]) afin de mettre en œuvre des tableaux fortementflexibles (cf. section 10). Les treaps randomisés ont été découverts et étudiéspar C. Aragon et R. Seidel en 1989. D. Knuth a mené des expérimentationsafin de comparer le comportement des treaps randomisés et des arbres déployés(cf. section 6.8). Il montre que les premiers ont de meilleures performances queles seconds (cf. [75], page 478).

Les treaps autorisent une mise en œuvre efficace des opérations duales departitionnement et de fusion. Partitionner un treap par rapport à une valeur v(et obtenir ainsi deux treaps) se fait en ajoutant v dans le treap avec la prio-rité la plus faible possible (la priorité −1 permet d’éviter des conflits) puis ensupprimant la racine (c’est le couple (v,−1)) du treap résultat. Le caractère abrdu treap assure que l’on obtient bien une partition par rapport à v et l’aspectminimier assure que toutes les valeurs sont prises en considération. L’opérationde fusion a comme précondition le fait que les deux treaps à fusionner pourraientrésulter du partitionnement d’un treap. Il suffit alors d’enraciner les deux treapssur une valeur quelconque v (avec une priorité quelconque) et d’effectuer unesuppression de cette valeur. Le processus de suppression descend la valeur surune feuille où elle est facile à éliminer. Le résultat est le couple de treaps attendu.L’exercice 6.9.1 propose d’étudier ces deux opérations.

Il existe d’autres méthodes aléatoires pour la mise en œuvre d’ensembles descalaires, comme par exemple les listes de sauts (skip lists). Cependant, cettestructure de données n’est pas de nature fonctionnelle, elle n’est donc pas étu-diée ici. L’une des structures de données (aléatoires) les plus intéressantes parson rapport performances/concision de l’algorithme est celle dénommée abr ran-domisé. Découverte en 1998, elle est due à C. Martinez et S. Roura (cf. [81]).Nous avons vu à la section 6.3 qu’il est possible d’effectuer une insertion soit auxfeuilles soit à la racine. Ceci suggère qu’il est possible d’effectuer l’insertion surtoute position du chemin de la recherche entre la racine et la feuille. Il suffit pourcela de décider, au moment de l’insertion, si l’on effectue l’insertion à la racinecourante (selon la méthode du partitionnement, cf. section 6.3.4) ou si l’on pour-suit la descente dans l’arbre. C’est le principe qui est exploité en décidant, pour

Page 281: Structures de données et méthodes formelles ||

6. Ensembles de clés scalaires 271

un arbre de poids n, de placer la nouvelle valeur à la racine avec une probabilitéde 1

n+1 . C. Martinez et S. Roura montrent que l’arbre construit en appliquantcette stratégie est un abr aléatoire. La suppression débute par une phase de lo-calisation de la valeur à supprimer puis par une fusion des deux sous-arbres get d restants. Cette fusion se fait en prenant comme racine du résultat la racinedu sous-arbre gauche (resp. droite) avec une probabilité de w(g)

w(g)+w(d) (resp. dew(d)

w(g)+w(d) ). Là aussi, on montre qu’une telle suppression, réalisée à partir d’unarbre aléatoire, produit un arbre aléatoire. Une phase ultime de décompositiondu poids sur la structure de données est nécessaire afin de préserver les bonnesperformances temporelles. L’exercice 6.9.2 propose une mise en œuvre de cettesolution.

Les treaps randomisés et les abr randomisés se comportent tous deux commedes abr aléatoires. Ils ont donc les mêmes performances 23. L’un des critères dechoix éventuel entre les deux solutions est que lors d’une insertion, les treapsrandomisés ne font appel qu’une seule fois au générateur de nombres aléatoires,les abr randomisés réclament un appel à chaque position d’insertion. Tous deuxexigent de renforcer le support, le premier par la priorité (qui a comme uniquerôle de randomiser l’arbre) l’autre par le poids (ce renforcement peut être néces-saire pour d’autres raisons). Concernant les treaps randomisés, la solution parhachage évite ces écueils mais le choix de la fonction de hachage est critique.

Exercices

Exercice 6.9.1 Introduire les opérations de partitionnement et de fusion dans la spécificationdu type abstrait ensabst. Ajouter à la spécification du type concret etrp la spécificationconcrète de ces opérations et calculer une représentation sur la base des descriptions informellesde la section 6.9.7. En déduire le coût de ces opérations.

Exercice 6.9.2 Calculer les opérations de mise à jour dans un abr randomisé. Effectuer ladécomposition du poids sur la structure de données. Mettre en œuvre en utilisant un générateurde nombres aléatoires.

23. Bien que les arbres construits par l’un et l’autre à partir d’une même séquence de cléssoient en général différents.

Page 282: Structures de données et méthodes formelles ||

Chapitre 7

Ensembles de clés structurées

Le chapitre 6 nous a permis d’étudier quelques représentations intéres-santes pour les ensembles de clés scalaires. Il est cependant fréquent que la clé soitcomposite. En nous limitant toujours au cas des ensembles définis en extension, ils’agit ici d’étudier la composition de deux structures de données : d’une part lesensembles de chaînes (ou de listes) et d’autre part les ensembles de couples. Lessolutions étudiées précédemment (abr, Avl, etc.) peuvent bien sûr s’appliquer.Il est cependant possible de tirer parti du caractère composite de la clé soit pourenrichir le jeu d’opérations soit pour améliorer l’efficacité temporelle ou spatialedes algorithmes. Pour les ensembles de chaînes, nous nous proposons d’étudierles mises en œuvre à base de tries 1, dont l’une des retombées est le hachagedynamique. Concernant les ensembles de couples, nous explorons la solution parkd-arbres.

7.1 Ensembles de chaînes, représentation par tries

7.1.1 IntroductionNous allons ici considérer le cas d’ensembles de chaînes (typiquement, et

pour fixer les idées, de caractères) de longueurs positives. Avec les méthodes« scalaires » comme celles étudiées au chapitre 6, le préfixe commun (commechaîne dans chaînes et chaînette) est mémorisé – et souvent consulté – plusieursfois. L’idée qui prévaut ici est de factoriser tous les plus longs préfixes communs(plpc), de façon à améliorer l’efficacité des opérations ensemblistes 2.

1. Le terme « trie » vient de « retrieval » et se prononce « traïe ».2. Les méthodes algorithmiques qui se fondent sur une prise en compte par morceaux des

valeurs à traiter sont qualifiées de méthodes radix. Ainsi la méthode de tri qui prend successi-vement en compte les chiffres d’une clé pour ventiler chaque clé dans l’un des dix réceptacles(à la manière des trieuses de cartes perforées mécaniques du début de la mécanographie) estappelée tri radix. La technique des tries est également une méthode radix.

Page 283: Structures de données et méthodes formelles ||

274 Structures de données et méthodes formelles

Exemple. Considérons l’ensemble de mots suivant :

– le – les – lapider – lapin– mai – maia – main – mare– mas – me – misera – moi

Nous constatons par exemple que main partage un plpc avec mas (c’est ma),mais qu’il a aussi un plpc avec mais (c’est mai). Une façon de factoriser ces plpcconsiste à organiser les caractères des différentes chaînes sous forme de forêt-trie.Une forêt-trie est un ensemble d’arbres-tries, un arbre-trie est une forme d’arbrenon ordonné (cf. section 3.3, page 85) particulier. C’est ce que montre la forêtci-dessous pour l’exemple introductif.

{ l

e

s

a

p

i

d

e

r

n

m

a

i

a n

r

e

s

e i

s

e

r

a

o

i

},

Pourtant, si l’on ne prend pas de précautions particulières pour la représenta-tion, il est impossible de remarquer que la chaîne mis (par exemple) n’appartientpas à l’ensemble, alors que la chaîne mai (par exemple) lui appartient. La solu-tion consiste à accompagner chaque nœud de la forêt-trie d’une information quimentionne ou non l’appartenance à l’ensemble du mot s’achevant en ce nœud.C’est le sens qu’il faut attribuer aux nœuds encerclés dans le schéma ci-dessus.Si la forêt-trie ne contient pas d’information inutile, c’est bien entendu le cas detoutes les feuilles.

Remarque. Nous avons affirmé ci-dessus vouloir ne nous intéresser qu’auxchaînes de longueur positive, excluant ainsi la chaîne vide [ ]. Qu’est-ce quijustifie une telle restriction ? Si l’on considère une forêt-trie, les racines de tousles arbres de la forêt constituent l’ensemble des premiers caractères de toutes leschaînes représentées. Or la chaîne vide est, par définition, dépourvue de premiercaractère, elle ne peut donc être représentée dans la forêt-trie. Dans certainesreprésentations, on contourne la difficulté en convenant que tous les arbres dela forêt sont enracinés sur un nœud dépourvu d’étiquette. La chaîne vide peutalors être représentée en encerclant cette racine. Cette solution entraîne uneperte d’homogénéité de la structure.

7.1.2 Définition des supports concretsNotations, rappel. Les clés considérées ici sont des listes (de caractères).Celles-ci sont introduites à la section 3.1 sous une double notation : la notation

Page 284: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 275

récursive et la notation linéaire. Ainsi la liste [c | [ ]] peut également être notée[c], la liste [c | [d | [ ]]] s’écrit également [c, d].

Le type concret que nous décrivons, ft, est un raffinement du type ensabstparamétré par des chaînes de caractères non vides. Par souci de concision, cetype est appelé chaine, son support est noté chaine dans la suite de cettesection. La définition formelle du support concret des forêts-tries ft se fait demanière croisée avec la définition des arbres-tries at. Débutons par la définitiondu support at.

c ∈ char ∧ b ∈ bool ∧ f ∈ ft ∧(b = true ∨ f = ∅)

⇔〈c, b, f〉 ∈ at

Un arbre-trie est donc un triplet dont le premier composant est un caractère c,le second composant est un booléen qui mentionne si c est (cas true) ou non(cas false) un caractère qui achève l’une des chaînes représentées. Le troisièmecomposant est la forêt-trie f associée à la racine. Le conjoint (b = true∨f = ∅)permet de garantir que si un nœud est une feuille, le booléen b a la valeur true(les feuilles terminent bien une chaîne).

Revenons au support des forêts-tries. Ainsi que nous l’avons dit ci-dessus,un arbre-trie est un arbre non ordonné. Les fils d’un nœud constituent un en-semble. Cette contrainte se transpose aux forêts-tries de la manière suivante : lesracines des différents arbres d’une forêt-trie constituent un ensemble. L’intégra-tion de cette contrainte à la spécification du support se fait par l’intermédiairede l’opération ensRac, opération auxiliaire du type ft qui délivre l’ensemble desracines d’une forêt. La définition du support ft du type ft s’effectue de manièreinductive :

1) ∅ ∈ ft2) 〈c, b, f〉 ∈ at ∧ g ∈ ft ∧ c /∈ ensRac(g) ⇒ {〈c, b, f〉} ∪ g ∈ ft

La première clause affirme que l’ensemble vide est une forêt-trie. La secondeclause précise que si 〈c, b, f〉 est un arbre-trie et g une forêt-trie, et que si cn’appartient pas à l’ensemble des racines de g alors {〈c, b, f〉} ∪ g est une forêt-trie. Il va de soi qu’un tel arbre est un arbre non ordonné.

La fonction d’abstraction se définit à partir de l’opération prefixer(c, e).Celle-ci délivre toutes les chaînes de l’ensemble e préfixées par le caractère e.Ainsi par exemple si e = {[a], [d, d, j]}, prefixer(c, e) délivre {[c, a], [c, d, d, j]}.prefixer(c,∅) délivre ∅ pour tout caractère c. Conceptuellement, l’opérationprefixer fait partie du type abstrait « ensemble de chaînes ». N’étant pas utiliséeen dehors du calcul, cette opération n’a pas à être implantée. Une définitioninductive possible de cette opération est la suivante :

Page 285: Structures de données et méthodes formelles ||

276 Structures de données et méthodes formelles

function prefixer(c, e) ∈ char× ensAbst(chaine)→ ensAbst(chaine) =if e = ∅→∅

| e = ∅→any i where

i ∈ ethen

{[c | i]} ∪ prefixer(c, e− {i})end

fi

Le tableau 7.1 représente quelques propriétés de cette opération. En particu-lier la propriété 7.1.1 affirme que si une chaîne constituée de plusieurs caractèresappartient à l’ensemble prefixer(c, e) alors la chaîne débute par le caractère c etla chaîne qui suit c appartient à l’ensemble e. La démonstration de ces propriétésest laissée en exercice.

Tableau 7.1 – Propriétés de l’opération prefixer.Ce tableau répertorie quelques-unes des propriétés de l’opérationprefixer(c, e). Cette opération délivre l’ensemble constitué de toutesles chaînes de e précédées du caractère c.

Propriété Condition Ident.[a | q] ∈ prefixer(c, e)

⇔a = c ∧ q ∈ e

a ∈ char ∧ c ∈ char∧e ⊆ ensAbst(chaine)∧q ∈ ensAbst(chaine)

(7.1.1)

prefixer(c, e) ∪ {[c | q]}=

prefixer(c, e ∪ {q})

c ∈ char∧e ⊆ ensAbst(chaine)∧q ∈ ensAbst(chaine)

(7.1.2)

prefixer(c, e)− {[c | q]}=

prefixer(c, e− {q})

c ∈ char∧e ⊆ ensAbst(chaine)∧q ∈ ensAbst(chaine)

(7.1.3)

prefixer(d, e)− {[c | q]}=

prefixer(d, e)

c ∈ char ∧ d ∈ char∧c = d∧e ⊆ ensAbst(chaine)∧q ∈ ensAbst(chaine)

(7.1.4)

[c] /∈ prefixer(c, e)c ∈ char∧e ⊆ ensAbst(chaine)

(7.1.5)

7.1.3 Définition des fonctions d’abstractionIl s’agit de définir les fonctions d’abstraction A′ et A (des types concrets

respectifs at et ft). La première, A′, délivre l’ensemble des chaînes qui sontreprésentées dans un arbre-trie. Elle se définit par :

Page 286: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 277

function A′(〈c, b, f〉) ∈ at→ ensAbst(chaine) =

prefixer(c,A(f)) ∪

⎛⎜⎜⎜⎜⎝if b = true→

{[c]}| b = false→∅

fi

⎞⎟⎟⎟⎟⎠Nous notons que A′ se définit à la fois à partir de la fonction d’abstraction Adu type ft et de l’opération prefixer.

La fonction d’abstraction A délivre l’ensemble des chaînes représentées parune forêt-trie. Une représentation inductive possible est :

function A(f) ∈ ft→ ensAbst(chaine) =if f = ∅→∅

| f = ∅→any i where i ∈ f then A′(i) ∪ A(f − {i}) end

fi

7.1.4 Spécification des opérations concrètesLa description du type at est proposée à la figure 7.1. La figure 7.2, page

suivante, reprend toutes les informations concernant le type concret ft et spé-cifie concrètement les deux opérations de mise à jour. Elle est complétée par lafigure 7.3, page 279.

concreteType at = (at, (), ())uses char, ft, chaine, boolrefines ensabst(chaine)

supportc ∈ char ∧ b ∈ bool ∧ f ∈ ft ∧(b = true ∨ f = ∅)

⇔〈c, b, f〉 ∈ at

abstractionFunctionfunction A′(〈c, b, f〉) ∈ at→ ensAbst(chaine) = . . .

end

Figure 7.1 – Spécification du type at.Ce type concret raffine le type abstrait ensabst. Cependant il s’agitd’un type auxiliaire utilisé par le type concret ft (cf. figure 7.2). Enconséquence, seuls le support et la fonction d’abstraction sont décrits.

7.1.5 Calcul de la représentation des opérations concrètesNous limitons notre étude au calcul de l’opération eAjout_ft et à la pré-

sentation de l’opération eSupp_ft. Le calcul des autres opérations est proposéà l’exercice 7.1.2, page 292.

Page 287: Structures de données et méthodes formelles ||

278 Structures de données et méthodes formelles

concreteType ft = (ft, (eV ide_ft, eAjout_ft, eSupp_ft),(eApp_ft, eEstV ide_ft))

uses bool, at, char, chainerefines ensabst(chaine)

support1) ∅ ∈ ft2) 〈c, b, f〉 ∈ at ∧ g ∈ ft ∧ c /∈ ensRac(g) ⇒ {〈c, b, f〉} ∪ g ∈ ft

abstractionFunctionfunction A(f) ∈ ft→ ensAbst(chaine) = . . .

operationSpecifications...

function eAjout_ft(l, f) ∈ chaine× ft→ ft =g : (g ∈ ft ∧ A(g) = eAjout(l,A(f)))

;function eSupp_ft(l, f) ∈ chaine× ft→ ft =g : (g ∈ ft ∧ A(g) = eSupp(l,A(f)))

...auxiliaryOperationRepresentations

function ensRac(f) ∈ ft� F(char) = · · ·end

Figure 7.2 – Spécification du type concret ft – partie 1.Le type concret ft (forêt-trie) raffine le type abstrait ens-

abst(chaine). Il est défini de manière croisée avec le type at (arbre-trie, cf. figure 7.1). Il permet de représenter des ensembles de chaînessans duplication des préfixes communs.

Tableau 7.2 – Propriétés de l’opération ensRac.Ce tableau répertorie deux des propriétés de l’opération ensRac(f).Cette opération délivre l’ensemble constitué de toutes les racines desarbres-tries présents dans f. La propriété 7.1.6 précise qu’il existe auplus dans f un arbre-trie ayant c comme racine. La propriété 7.1.7 ex-prime que si le caractère c n’est pas dans l’ensemble des racines de laforêt-trie f , alors il n’y a pas dans A(f) de chaîne débutant par c.

Propriété Condition Ident.c /∈ ensRac(f − {〈c, b, g〉}) f ∈ ft ∧ 〈c, b, g〉 ∈ at (7.1.6)

c /∈ ensRac(f)⇒ [c | q] /∈ A(f) f ∈ ft ∧ c ∈ char∧(q ∈ chaine ∨ q = [ ])

(7.1.7)

Page 288: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 279

concreteType ft = · · ·...

auxiliaryOperationRepresentationsfunction ensRac(f) ∈ ft� F(char) =if f = ∅→∅

| f = ∅→any c, b, g where

〈c, b, g〉 ∈ fthen

{c} ∪ ensRac(f − {〈c, b, g〉})end

fiend

Figure 7.3 – Spécification du type concret ft – partie 2.La rubrique auxiliaryOperationRepresentations fournit la repré-sentation de l’opération auxiliaire ensRac, qui délivre l’ensemble desracines de la forêt f .

Calcul d’une représentation de l’opération eAjout_ft

Compte tenu du typage du paramètre l de l’opération eAjout_ft(l, f) (l =[ ]), nous pouvons poser l = [c | q].

A(eAjout_ft(l, f))= Propriété caractéristique

{l} ∪ A(f)= Hypothèse

{[c | q]} ∪ A(f) (7.1.8)

Procédons à une induction sur f en débutant par le cas f = ∅.

{[c | q]} ∪ A(f)= Hypothèse

{[c | q]} ∪ A(∅)= Définition de A

{[c | q]} ∪ ∅= Définition de prefixer{[c | q]} ∪ prefixer(c,A(∅)) (7.1.9)

Procédons à une analyse par cas sur q, selon que q = [ ] ou non. Débutons parq = [ ].

{[c | q]} ∪ prefixer(c,A(∅))= Hypothèse

Page 289: Structures de données et méthodes formelles ||

280 Structures de données et méthodes formelles

{[c]} ∪ prefixer(c,A(∅))= Définition de A′, cas b = true

A′(〈c,true,∅〉)= A(∅) = ∅, propriété A.9

A′(〈c,true,∅〉) ∪ A(∅)= Définition de A

A({〈c,true,∅〉} ∪ ∅)= Propriété A.9

A({〈c,true,∅〉})

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée :

f = ∅ →let [c | q] := l in

q = [ ] →eAjout_ft(l, f) = {〈c,true,∅〉}

end

Considérons à présent le cas q = [ ] en partant de la formule 7.1.9 ci-dessus.

{[c | q]} ∪ prefixer(c,A(∅))= Propriété 7.1.2, page 276

prefixer(c, {q} ∪ A(∅))= Propriété caractéristique de eAjout_ft

prefixer(c,A(eAjout_ft(q,∅)))= Définition de A′ dans le cas b = false

A′(〈c, false, eAjout_ft(q,∅)〉)= Propriété A.9 et définition de A

A′(〈c, false, eAjout_ft(q,∅)〉) ∪ A(∅)= Définition de A

A({〈c, false, eAjout_ft(q,∅)〉} ∪ ∅)= Propriété A.9

A({〈c, false, eAjout_ft(q,∅)〉})

D’où, d’après la propriété de l’équation à membres identiques (page 67), la se-conde équation gardée :

f = ∅→let [c | q] := l in

q = [ ] →eAjout_ft(l, f) = {〈c, false, eAjout_ft(q,∅)〉}

end

Le cas f = ∅ étant complètement analysé, abordons le cas f = ∅. Soit iet h tels que i ∈ f et h = f − {i}. Posons i = 〈d, b, g〉. Nous repartons de laformule 7.1.8.

Page 290: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 281

{[c | q]} ∪ A(f)= Hypothèse

{[c | q]} ∪ A({〈d, b, g〉} ∪ h)= Définition de A

{[c | q]} ∪ A′(〈d, b, g〉) ∪ A(h) (7.1.10)

Procédons à nouveau à une analyse par cas selon que c = d ou que c = d.Débutons par c = d.

{[c | q]} ∪ A′(〈d, b, g〉) ∪ A(h)= Hypothèse

{[c | q]} ∪ A′(〈c, b, g〉) ∪ A(h) (7.1.11)

Pour développer l’expression A′(〈c, b, g〉) nous devons distinguer les deux casb = true et b = false, conformément à la définition de la fonction A′. Débutonspar le cas b = true.

{[c | q]} ∪ A′(〈c, b, g〉) ∪ A(h)= Définition de A′{[c | q]} ∪ {[c]} ∪ prefixer(c,A(g)) ∪ A(h) (7.1.12)

Nous devons effectuer une analyse par cas selon que q = [ ] ou que q = [ ].Débutons par le cas q = [ ] :

{[c | q]} ∪ {[c]} ∪ prefixer(c,A(g)) ∪ A(h)= Hypothèse

{[c]} ∪ {[c]} ∪ prefixer(c,A(g)) ∪ A(h)= Propriété A.9

{[c]} ∪ prefixer(c,A(g)) ∪ A(h)= Définition de A′A′(〈c, b, g〉) ∪ A(h)

= Définition de AA({〈c, b, g〉} ∪ h)

D’où l’équation gardée suivante :

f = ∅→let [c | q] := l in

any i, h wherei ∈ f ∧ h = f − {i}

thenlet 〈d, b, g〉 := i in

c = d →b = true →

q = [ ] →eAjout_ft(l, f) = {〈c, b, g〉} ∪ h

endend

end

Page 291: Structures de données et méthodes formelles ||

282 Structures de données et méthodes formelles

Pour le cas q = [ ], nous repartons de la formule 7.1.12 :

{[c | q]} ∪ {[c]} ∪ prefixer(c,A(g)) ∪ A(h)= Propriété 7.1.2, page 276

{[c]} ∪ prefixer(c, {q} ∪ A(g)) ∪ A(h)= Propriété caractéristique de eAjout_ft

{[c]} ∪ prefixer(c,A(eAjout_ft(q, g))) ∪ A(h)= Définition de A′, cas b = true

A′(〈c,true, eAjout_ft(q, g)〉) ∪ A(h)= Définition de A

A({〈c,true, eAjout_ft(q, g)〉} ∪ h)

D’où l’équation gardée :

f = ∅→let [c | q] := l in

any i, h wherei ∈ f ∧ h = f − {i}

thenlet 〈d, b, g〉 := i in

c = d →b = true →

q = [ ] →eAjout_ft(l, f) = {〈c,true, eAjout_ft(q, g)〉} ∪ h

endend

end

Nous abordons à présent le cas b = false. Nous repartons de la formule 7.1.11 :

{[c | q]} ∪ A′(〈c, b, g〉) ∪ A(h)= Hypothèse

{[c | q]} ∪ A′(〈c, false, g〉) ∪ A(h)= Définition de A′

{[c | q]} ∪ prefixer(c,A(g)) ∪ A(h) (7.1.13)

Nous devons à nouveau réaliser une analyse par cas, en distinguant le cas q = [ ]de sa négation. Débutons par q = [ ] :

{[c | q]} ∪ prefixer(c,A(g)) ∪ A(h)= Hypothèse

{[c]} ∪ prefixer(c,A(g)) ∪ A(h)= Définition de A′A′(〈c,true, g〉) ∪ A(h)

= Définition de AA({〈c,true, g〉} ∪ h)

D’où l’équation gardée :

Page 292: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 283

f = ∅→let [c | q] := l in

any i, h wherei ∈ f ∧ h = f − {i}

thenlet 〈d, b, g〉 := i in

c = d →b = false →

q = [ ] →eAjout_ft(l, f) = {〈c,true, g〉} ∪ h

endend

end

Le cas q = [ ] se traite comme suit, en repartant de la formule 7.1.13 :

{[c | q]} ∪ prefixer(c,A(g)) ∪ A(h)= Propriété 7.1.2, page 276

prefixer(c, {q} ∪ A(g)) ∪ A(h)= Propriété caractéristique de eAjout_ft

prefixer(c, eAjout_ft(q, g)) ∪ A(h)= Définition de A′

A′(〈c, false, eAjout_ft(q, g)〉) ∪ A(h)= Définition de A

A({〈c, false, eAjout_ft(q, g)〉} ∪ h)

L’équation gardée suivante s’en déduit :

f = ∅→let [c | q] := l in

any i, h wherei ∈ f ∧ h = f − {i}

thenlet 〈d, b, g〉 := i in

c = d →b = false →

q = [ ] →eAjout_ft(l, f) = {〈c, false, eAjout_ft(q, g)〉} ∪ h

endend

end

Reste à traiter le cas c = d. Nous repartons de la formule 7.1.10 :

{[c | q]} ∪ A′(〈d, b, g〉) ∪ A(h)= Propriété A.7

A′(〈d, b, g〉) ∪ {[c | q]} ∪ A(h)= Propriété caractéristique de l’opération eAjout_ft

A′(〈d, b, g〉) ∪ A(eAjout_ft([c | q], h))

Page 293: Structures de données et méthodes formelles ||

284 Structures de données et méthodes formelles

= Définition de A, de [c | q] et de 〈d, b, g〉A({i} ∪ eAjout_ft(l, h))

D’où l’équation gardée :

f = ∅→let [c | q] := l in

any i, h wherei ∈ f ∧ h = f − {i}

thenlet 〈d, b, g〉 := i in

c = d →eAjout_ft(l, f) = {i} ∪ eAjout_ft(l, h)

endend

end

Au total, nous avons calculé la représentation suivante de l’opérationeAjout_ft :

function eAjout_ft(l, f) ∈ chaine× ft→ ft =let [c | q] := l in

if f = ∅ → /*vraie insertion*/if q = [ ] →

{〈c,true,∅〉}| q = [ ] →

{〈c, false, eAjout_ft(q,∅)〉}fi

| f = ∅ →any i, h where

i ∈ f ∧ h = f − {i}then

let 〈d, b, g〉 := i inif c = d →

if b = true →if q = [ ] → /*fausse insertion*/

{〈c,true, g〉} ∪ h| q = [ ] →

{〈c,true, eAjout_ft(q, g)〉} ∪ hfi

| b = false →if q = [ ] → /*vraie insertion*/

{〈c,true, g〉} ∪ h| q = [ ] →

{〈c, false, eAjout_ft(q, g)〉} ∪ hfi

Page 294: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 285

fi| c = d →

{i} ∪ eAjout_ft(l, h)fi

endend

fiend

Nous constatons qu’il s’agit d’une version qui utilise une expression non dé-terministe (any). En outre elle s’exprime à partir de l’opérateur ensembliste ∪.Ceci est imputable au fait que nous n’avons pour l’instant pas pris de décisionconcernant la représentation des forêts-tries en tant qu’ensembles. Il sera doncnécessaire de poursuivre le développement en réalisant un choix pour la mise enœuvre de l’ensemble f .

La complexité au pire de cet algorithme dépend a priori de deux paramètres :la longueur #(l) de la chaîne et la taille n du vocabulaire utilisé. Cependant,pour une application donnée, le vocabulaire est figé, n est donc constant. Le trai-tement réalisé pour chaque caractère de la chaîne conduit au pire à descendre#(l) branches dans la forêt-trie. À chaque niveau, des comparaisons sont néces-saires, leur nombre dépend à la fois de n et du choix de mise en œuvre réalisépour raffiner les forêts-tries. La complexité de l’algorithme eAjout_ft est doncen O(f(n) ·#(l)). Ainsi, par exemple, pour une représentation des forêts-triespar listes f(n) = n, pour des Avl f(n) = log n et pour des tables d’indexa-tion alphabétique (c’est-à-dire des tableaux à n entrées, chacune désignant ledescendant éventuel), f(n) = 1. En tout état de cause, quel que soit le choixréalisé, f(n) est en O(n) et, comme n est constant, eAjout_ft est en O(#(l)).Une remarque mérite cependant d’être formulée à propos du facteur multipli-catif. Les codes de caractères utilisés aujourd’hui (Unicode, UTF-32, UTF-8)peuvent comporter plusieurs dizaines de milliers de caractères, nombre qui dansle pire des cas constitue la constante multiplicative f(n) ci-dessus. Dans ce typede situation, le choix de la stratégie de développement et de la mise en œuvredes forêts-tries n’est pas indifférent.

Représentation de l’opération eSupp_ft

Le calcul de cette opération ne présente pas de difficultés par rapport aucalcul précédent. Une représentation possible est la suivante :

function eSupp_ft(l, f) ∈ chaine× ft→ ft =if f = ∅ → /*fausse suppression*/∅

| f = ∅ →any i, h where

i ∈ f ∧ h = f − {i}then

Page 295: Structures de données et méthodes formelles ||

286 Structures de données et méthodes formelles

let 〈d, b, g〉, [c | q] := i, l inif c = d →

if b = true →if q = [ ] → /*vraie suppression*/

if g = ∅ →h

| g = ∅ →{〈c, false, g〉} ∪ h

fi| q = [ ] →

{〈c,true, eSupp_ft(q, g)〉} ∪ hfi

| b = false →if q = [ ] → /*fausse suppression*/

{〈c, false, g〉} ∪ h| q = [ ] →

{〈c, false, eSupp_ft(q, g)〉} ∪ hfi

fi| c = d →

{i} ∪ eSupp_ft(l, h)fi

endend

fi

Ici encore un raffinement ultérieur s’impose après avoir décidé d’une repré-sentation pour les forêts-tries.

Pour ce qui concerne la complexité, les remarques formulées lors de l’étudede l’opération eAjout_ft s’appliquent ; la complexité de la suppression d’unechaîne de #(l) caractères est en O(#(l)). Dans [75], D. Knuth propose une ana-lyse approfondie des complexités spatiales et temporelles des tries (cf. pages 500-507).

7.1.6 Variantes des triesNous allons étudier, sans les développer complètement, deux variantes à la

méthode présentée ci-dessus. La première, les Patricia tries, vise à limiter lenombre de pointeurs en fusionnant certains nœuds sur un chemin entre la racineet les feuilles. La seconde est dénommée « hachage dynamique ». Elle est, pourles supports externes, une bonne alternative aux B-arbres et aux B+-arbresprésentés au chapitre 6.

Patricia tries

L’idée de base des Patricia tries part du constat que lorsqu’il existe uneséquence de nœuds consécutifs suivis par un nœud terminal ou non et qu’aucundes nœuds ne donne lieu à une bifurcation, il est possible de fusionner ces nœuds

Page 296: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 287

en un seul. Le statut (terminal ou non) du nœud résultant de la fusion est héritéde celui du dernier nœud. Dans un Patricia trie, les nœuds représentent donc engénéral des chaînes et non plus de simples caractères. Ainsi le trie de la page 274conduit au Patricia trie suivant :

{ l

e

s

ap

i

n der

m

a

i

a n

re s

e isera oi

},

Le gain en terme de complexité spatiale se paye par une complexité accrue desalgorithmes (cf. exercice 7.1.8).

Hachage dynamique

Le hachage dynamique est une technique, fondée sur les tries, adaptée à lareprésentation d’ensembles sur supports secondaires à accès direct (typiquementdes disques magnétiques ou des ssd en 2010) pour lesquels on cherche à limiterle nombre d’accès – que ce soit en lecture ou en écriture – au détriment éventueldu coût des opérations en mémoire centrale. Un ensemble géré par hachagedynamique se présente selon deux niveaux de mémoire :

– l’index, situé en mémoire centrale et structuré en forêt-trie, qui permetl’accès au niveau inférieur, le niveau page ;

– les « pages », de taille fixe n, qui contiennent les clés de l’ensemble. Afin depermettre une évolution de la structure (ajout et suppression d’éléments),un système d’allocation/récupération dynamique de pages est supposé dis-ponible.

forêt-trie

niveau page

niveau index

· · ·

Pour simplifier notre représentation, dans la suite nous considérons que lesclés sont des chaînes de caractères de taille fixe (quatre ci-dessous). Le principeest le suivant. Tout chemin de la racine à une feuille d’un arbre-trie de l’indexdonne accès à une page. Par ailleurs tout chemin représente une chaîne. Toutesles clés d’une page ont comme préfixe commun la chaîne qui donne accès à lapage. Dans l’exemple ci-dessous, le chemin mis désigne la page qui contient lesdeux éléments mise et miss, de préfixe commun mis.

Page 297: Structures de données et méthodes formelles ||

288 Structures de données et méthodes formelles

{ m

e

mena

i

e

mien

m

mime

s

misemiss

n

a

nainnais

i

niesniasnina

},

Lors de l’ajout d’une clé c, le trie est utilisé conjointement avec c pour iden-tifier la page dans laquelle c devra venir s’insérer. Si la page est pleine, toutesses clés sont ventilées sur autant de pages que nécessaire, selon la valeur de lanouvelle position dans les clés. La nouvelle clé est insérée dans la structure ainsimodifiée. Les suppressions se traitent de manière duale : dès que l’ensemble despages filles d’un nœud passe de n+ 1 clés à n clés, les pages sont fusionnées enune seule et le trie est mis à jour.

Exemple. Dans l’exemple traité ci-dessous, nous considérons des pages dequatre emplacements. Le tableau 7.3 est un synoptique de la mise à jour. Chaqueélément est une clé de longueur fixe de quatre caractères. Onze clés sont toutd’abord insérées puis trois d’entre elles sont supprimées.

Tableau 7.3 – Séquence de mises à jour par hachage dynamique.Le tableau représente une séquence de onze ajouts consécutifs suivis detrois suppressions dans un ensemble de clés à quatre caractères. Cetensemble est géré par hachage dynamique. Son évolution est développéedans le texte.

type clé type clé1 A mise 8 A nain2 A nies 9 A nais3 A miss 10 A mima4 A nias 11 A mena5 A mime 12 S nain6 A nina 13 S mena7 A mien 14 S mime

A : ajoutS : suppression

1. Ajout de la clé mise. Le trie est créé, une page est allouée, elle va contenirla clé mise.

Page 298: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 289

{ m

mise

}

2. Ajout de la clé nies, qui conduit à la création d’un nouveau nœud et d’unnouvel arbre-trie ainsi qu’à l’allocation d’une page. Les six ajouts suivants(jusqu’à nain compris) se font sans modification de la structure.

{ m

misemissmimemien

n

niesniasninanain

},

On note que les deux pages sont maintenant pleines.3. Ajout de la clé nais. L’ensemble des clés existant dans la page de préfixe n

({nies, nias, nina, nain}) est partitionné selon le second caractère. Le trieest mis à jour et la clé nais est insérée dans la nouvelle structure, dans lapage de préfixe na.

{ m

misemissmimemien

n

a

nainnais

i

niesniasnina

},

4. Ajout de la clé mima. Cette fois encore on atteint une page déjà pleine.L’ensemble {mise, miss, mime, mien} est pris en compte et partitionnéselon le second caractère. i n’étant pas discriminant on obtient :

{ m

i

misemissmimemien

n

a

nainnais

i

niesniasnina

},

Page 299: Structures de données et méthodes formelles ||

290 Structures de données et méthodes formelles

Cette situation ne permet toujours pas d’insérer la clé mima. On procèdeà un nouveau partitionnement, cette fois selon le troisième caractère. Laclé mima peut alors être insérée.

{ m

i

e

mien

m

mimemima

s

misemiss

n

a

nainnais

i

niesniasnina

},

5. Ajout de la clé mena. Une nouvelle branche de préfixe me est créée. Onobtient :

{ m

e

mena

i

e

mien

m

mimemima

s

misemiss

n

a

nainnais

i

niesniasnina

},

qui n’est autre que la configuration présentée en introduction, section 7.1.1.

6. Suppression de la clé nain. Le nombre de clés dépendant du nœud n passede cinq à quatre, permettant l’utilisation d’une seule page : on fusionne lesdeux pages, le trie est mis à jour, une page est désallouée.

{ m

e

mena

i

e

mien

m

mimemima

s

misemiss

n

naisniesniasnina

},

7. Suppression de la clé mena : le chemin me est supprimé et la page corres-pondant désallouée.

Page 300: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 291

{ m

i

e

mien

m

mimemima

s

misemiss

n

naisniesniasnina

},

8. Suppression de la clé mime. Le nombre de clés dépendant de la chaîne midevient égal à quatre. On fusionne les trois pages et on met à jour le trie.Dans une première phase, le préfixe mi est conservé puis, le i se révélantinutile, seul le m est conservé, conduisant à :

{ m

mienmimamisemiss

n

naisniesniasnina

},

7.1.7 Conclusion et remarques bibliographiques

Les tries sont souvent introduits comme une solution pour implanter deschaînes de bits. Dans ce cas, étant donné un nœud, celui-ci possède au plus deuxfils (l’un pour le 0 et l’autre pour le 1). Nous avons d’emblée généralisé à deschaînes quelconques.

Nous n’avons représenté qu’un nombre limité d’opérations. L’une des opé-rations les plus utiles sur les chaînes est largement facilitée par l’utilisation destries. C’est l’opération de complétion. Étant donné un ensemble de chaînes eet une chaîne particulière c, il s’agit de rechercher le sous-ensemble de e qui acomme préfixe la chaîne s. Cette opération peut être utilisée pour l’amorçage demots dans un éditeur de textes, pour la complétion de requêtes dans un naviga-teur Web ou la complétion de commandes lignes dans une application interactive(comme par exemple un système d’exploitation). L’exercice 7.1.5 propose d’étu-dier cette opération.

L’un des aspects de la mise en œuvre a été simplement évoqué dans ce quiprécède. C’est celui de la représentation d’une forêt-trie. Puisqu’une forêt-trieest un ensemble, il faut à un moment ou un autre prendre une décision quant àla représentation de cet ensemble. Le plus souvent c’est la méthode du vecteurcaractéristique (cf. section 6.1) qui est utilisée ou décrite dans la littérature.Dans le cas des tries binaires, cette solution s’impose : elle ne présente quedes avantages. Dans le cas des tries « multivoies » comme ceux que nous avonsutilisés, la solution du vecteur caractéristique (cf. section 6.1) – au demeurant

Page 301: Structures de données et méthodes formelles ||

292 Structures de données et méthodes formelles

excellente sur le plan de la complexité temporelle pour les opérations calculéesci-dessus – est coûteuse en espace puisqu’à chaque nœud sera associé un tableaude n emplacements (avec n = 256 pour un codage Ascii des caractères) quel quesoit le nombre de fils. Parmi les n emplacements, le plus souvent, peu d’entre euxsont réellement utilisés, le tableau est en général très creux. Les autres solutionsconnues pour représenter des ensembles de scalaires (liste, abr, Avl, etc.) sontalors des alternatives envisageables à celle du vecteur caractéristique (cf. sec-tion 6.1). Des solutions mixtes peuvent également être prises en considération.

Selon D.E. Knuth [75], les tries ont été initialement proposés par le mathé-maticien norvégien A. Thue en 1912 (voir la préface cependant pour une traceplus ancienne). La première référence informatique est à rechercher auprès deR. de la Briandais qui, en 1959, propose de raffiner les ensembles de forêts-triespar des listes. Peu de temps après, en 1960, E. Fredkin forge le terme trie [38].Les Patricia tries sont dus à D. Morrison en 1968 [86]. Le terme est un acronymepour « Practical Algorithm to Retrieve Information Coded in Alphanumeric ».Le hachage dynamique est décrit initialement en 1978 par P.-Å. Larson dans[78] et détaillé dans [34]. De nombreuses autres variantes ont été proposées.C’est par exemple le cas des burst tries [52] qui, à l’instar des structures à ha-chage dynamique, sont des structures à deux niveaux. Le premier niveau est untrie classique et le second est une structure ensembliste quelconque (comme desabr par exemple) ne contenant que les suffixes. Dans [54], R. Hinze propose unegénéralisation à des composants quelconques.

Exercices

Exercice 7.1.1 La technique des tries telle qu’elle est utilisée à la section 7.1 ne permet pasde représenter des ensembles de chaînes contenant la chaîne vide. Proposer des solutions pourcontourner cette limitation.

Exercice 7.1.2 Calculer la représentation des opérations eV ide_ft, eApp_ft, eSupp_ft eteEstV ide_ft dans le cas des tries.

Exercice 7.1.3 Après avoir décidé d’une implantation ensembliste, compléter les calculs d’opé-rations réalisés dans cette section pour les tries standard en raffinant les opérateurs ensemblistesqui subsistent dans la représentation des opérations.

Exercice 7.1.4 L’opération eAjout_ft(l, f) a été calculée en réalisant une induction surl’ensemble f . Une autre solution consiste à rechercher dans l’ensemble A(f) les chaînes quidébutent par le même caractère que l. Développer cette solution. Discuter par rapport à lasolution présentée à la section 7.1.

Exercice 7.1.5 Enrichir la spécification abstraite des tries de façon à introduire l’opérationde complétion comp(p, e) qui délivre le sous-ensemble des chaînes de e qui ont comme préfixecommun la chaîne p. Proposer une spécification concrète sous forme de tries. Calculer unereprésentation de cette opération.

Exercice 7.1.6 Le cas des ensembles de chaînes de longueur variable permet d’envisager uneopération qui, dans le cas des ensembles de scalaires, serait dépourvue de sens. Il s’agit del’opération d’appariement. Étant donné une chaîne de caractères c d’une part et un ensemblee de chaînes d’autre part, il s’agit de découvrir (si elle existe) la plus longue chaîne de e quis’identifie à un préfixe de la chaîne c. Spécifier et calculer cette opération. À votre avis, quelstypes d’application peuvent être demandeurs d’une telle fonctionnalité ?

Page 302: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 293

Exercice 7.1.7 Spécifier, pour les tries, les opérations concrètes complémentaires décritesdans l’exercice 6.2.2, page 149. Calculer une représentation de ces opérations.

Exercice 7.1.8 Spécifier le type concret Patricia trie. Calculer les cinq opérations correspon-dant aux opérations abstraites de la figure 6.1, page 149.

Exercice 7.1.9 Montrer, sur l’exemple suivant, comment évolue une structure de hachagedynamique dans laquelle les pages ont une taille de quatre emplacements :

type clé type clé1 A rien 8 A sale2 A rive 9 A rein3 A role 10 A rode4 A rois 11 A rude5 A sien 12 A sous6 A soin 13 S sien7 A sain 14 A soit

A : ajoutS : suppression

Exercice 7.1.10 Spécifier un type concret pour un hachage dynamique avec des chaînesde longueur fixe n et des pages de p emplacements. Calculer les cinq opérations concrètescorrespondant aux opérations abstraites de la figure 6.1, page 149.

Exercice 7.1.11 On considère le hachage dynamique dans le cas de clés de longueurs quel-conques positives. Développer l’évolution d’une telle structure sur l’exemple de la page 274.Quels sont les problèmes nouveaux qui se posent ? Proposer des solutions.

Exercice 7.1.12 Spécifier pour le hachage dynamique les opérations abstraites complémen-taires décrites dans l’exercice 6.2.2, page 149. Calculer une représentation de ces opérations.

Exercice 7.1.13 On souhaite créer un dictionnaire partitionnant l’ensemble des mots dufrançais de sorte que chaque entrée répertorie les mots constitués du même sac de lettres. Ainsil’entrée contenant le mot varie contiendra également le mot ravie. Les opérations suivantessont visées :

– entree qui, à partir d’un mot, délivre tous les mots de la même entrée,– ajout, qui introduit un nouveau mot dans le dictionnaire,– supp, qui supprime un mot existant du dictionnaire.

Proposer une spécification abstraite de la structure de données ainsi définie. Rechercher unemise en œuvre qui soit efficace pour toutes les opérations visées.

7.2 Ensembles de couples, représentation par kd-arbres

7.2.1 Ensembles de couples, spécification abstraiteLe problème de la représentation de clés scalaires étudié tout au long du

chapitre 6 se généralise au cas de la représentation de clés composées de plusieursconstituants (c’est-à-dire de sous-ensembles de produits cartésiens, soit encore derelations). On ne perd pas en généralité en ne considérant uniquement que desproduits cartésiens de deux ensembles (pour lesquels les éléments en questionsont appelés paires ordonnées, 2-uplets ou couples). Par contre, nous limitonsnotre étude au cas d’ensembles dotés d’une structure d’ordre totale et de sous-ensembles finis définis en extension. Les domaines d’application couverts sont

Page 303: Structures de données et méthodes formelles ||

294 Structures de données et méthodes formelles

vastes, allant des bases de données à l’informatique géométrique ou géographique,en passant par la robotique, l’astronomie, la physique des particules, etc. En guised’illustration (cf. tableau 7.4) nous considérons un exemple pris dans un systèmed’informations hypothétique dans lequel il existe un ensemble de demandeursd’emploi (chacun d’eux identifié par une clé entière) D, un ensemble d’offresd’emploi (également identifiées par une clé entière) O et un sous-ensemble duproduit cartésien D × O constitué de couples d’entiers (d, o) tels que chacund’eux représente l’intérêt potentiel du demandeur d’emploi d pour l’offre o. Ainsi(couples n◦ 2 et 3) le demandeur inscrit sous le numéro 7 exprime son intérêtpour les offres d’emploi 5 et 11, tandis que (couples no 2 et 5) l’offre d’emploi 5est convoitée par les demandeurs 7 et 12 .

Tableau 7.4 – Relation entre demandeurs et offres d’emploi.Ce tableau représente 10 couples d’entiers. Le premier élément ducouple (dem.) identifie un demandeur d’emploi tandis que le second(off.) symbolise une offre d’emploi. Chaque couple (d, o) représente l’in-térêt potentiel du demandeur d envers une offre o. Ces 10 couples re-présentent un sous-ensemble de N × N, soit encore une relation surN× N.

num. dem. off. num. dem. off.1 3 10 6 15 32 7 5 7 15 133 7 11 8 17 154 9 14 9 20 115 12 5 10 21 8

Pourquoi alors traiter le cas des relations différemment du cas des sous-ensembles de scalaires ? Les opérations définies dans le type abstrait ensabst(cf. figure 6.1, page 149) ne suffisent-elles pas ? Rechercher si un demandeurd’emploi est intéressé par une offre, introduire un demandeur donné pour uneoffre particulière ou encore supprimer un couple parce qu’un demandeur se dé-siste par rapport à une offre particulière peuvent se faire via les versions concrètesdes opérations eApp, eAjout et eSupp en considérant chaque couple comme unscalaire. Cependant il faut en général dépasser ces fonctionnalités élémentaires.On doit par exemple pouvoir retrouver toutes les offres visées par un demandeurou, de manière duale, tous les demandeurs d’emploi intéressés par une offre don-née. Des opérations complémentaires sont alors nécessaires. Elles font partie dela spécification abstraite du nouveau type.

La notion de relation est très riche. Ses applications s’étendent bien au-delà des systèmes d’information. Ainsi, si chaque couple s’interprète comme lescoordonnées cartésiennes d’un plan, il peut être intéressant de rechercher le pointle plus proche d’un point donné ou encore l’ensemble des points situés à l’intérieurd’une figure géométrique du plan. La relation du tableau 7.4 s’interprète de lamanière suivante sur un plan :

Page 304: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 295

×

×

×

×

××

××

×

×

dem.

off.

2 4 6 8 10 12 14 16 18 20 22

2

4

6

8

10

12

14

16

Si l’on ne considère que des relations évolutives, la représentation efficace dece type de données reste à ce jour un défi. Les représentations naïves (tableau decouples ou listes) sont bien entendu simples à mettre en œuvre mais leur efficacitélaisse à désirer. Elles ne doivent cependant pas être négligées comme nous leverrons plus tard. Les représentations arborescentes butent sur le problème del’équilibre, qu’il s’agisse de l’équilibre en poids ou en hauteur. S’il est assez facilede construire un arbre équilibré à partir d’une représentation naïve, maintenircet équilibre lors d’opérations de mise à jour est problématique. La raison est quel’on ne connaît pas d’opération de rééquilibrage (comme le sont les rotations dansle cadre scalaire) préservant les propriétés exprimées par le support. En outre,plus que d’autres, il s’agit d’un type abstrait de données ouvert : il est souventnécessaire d’enrichir le type de base par des opérations propres à l’applicationsous-jacente.

Notre choix de représentation se porte vers les kd-arbres (aussi appelés arbresmultidirectionnels ou multidimensionnels). En outre, nous ajoutons aux opéra-tions classiques sur les ensembles, l’opération de coupure qui, à partir d’une abs-cisse x (resp. d’une ordonnée y), délivre l’ensemble des ordonnées y (resp. desabscisses x) tel que (x, y) est un couple appartenant à la relation. Ainsi, pourl’exemple ci-dessus, la coupure selon l’abscisse 7 délivre l’ensemble {5, 11}. Laspécification abstraite ecabst (ensemble de couples abstrait) est présentée àla figure 7.4. Posé en ces termes, le problème que nous cherchons à résoudre s’ap-parente au problème de la recherche de solutions efficaces pour les « tableauxcreux » (c’est-à-dire les tableaux ne contenant qu’une faible proportion d’élé-ments significatifs ou comportant une forte proportion d’éléments identiques).

7.2.2 Ensembles de couples, introduction aux kd-arbres

Dans kd-arbres, kd signifie k d imensions. Compte tenu de notre hypothèsede ne travailler que sur des relations binaires entre scalaires, k = 2. Notre repré-sentation se dénomme donc précisément 2d-arbres (ou arbres binaires bidirec-tionnels). Le type concret correspondant est ec2da. Notre spécification concrètese fait de manière croisée entre deux spécifications outils, l’une pour le niveau x

Page 305: Structures de données et méthodes formelles ||

296 Structures de données et méthodes formelles

abstractType ecabst = (ecAbst, (ecV ide, ecAjout, ecSupp),(ecCoupeX, ecCoupeY, ecApp, ecEstV ide))

usesbool,N

supportc ∈ N× N ⇔ c ∈ ecAbst

operations...

function ecAjout((x, y), e) ∈ (N× N)× ecAbst→ ecAbst =e ∪ {(x, y)}

;function ecSupp((x, y), e) ∈ (N× N)× ecAbst� ecAbst =e− {(x, y)}

;function ecCoupeX(x, e) ∈ N× ecAbst→ ensAbst(N) =e[{x}]

;function ecCoupeY (y, e) ∈ N× ecAbst→ ensAbst(N) =e−1[{y}]

...end

Figure 7.4 – Spécification du type abstrait ecabst.Le type abstrait ecabst formalise la représentation de relations surN×N. Outre les opérations ecV ide, ecAjout, ecSupp, ecApp, ecEstV ide,homologues des opérations eV ide, eAjout, eSupp, eApp, eEstV ide pourles ensembles de scalaires, deux opérations spécifiques, ecCoupeX etecCoupeY sont spécifiées. ecCoupeX(x, e) (resp. ecCoupeY (y, e)) dé-livre l’image par e (resp. e−1) de l’ensemble {x} (resp. {y}).

(x2da) et l’autre pour le niveau y (y2da) 3. Les niveaux x et y alternent depuisla racine jusqu’aux feuilles. Par convention, la racine d’un arbre du type ec2daest à un niveau x.

7.2.3 Définition du support concret

Un 2d-arbre non vide est un arbre binaire dont chaque nœud est un coupled’entiers (x, y). C’est un x2d-arbre et ses deux sous-arbres sont des y2d-arbres(dont les éventuels sous-arbres sont eux-mêmes des x2d-arbres). À cela vient sesuperposer le fait qu’il s’agit d’arbres de recherche 4. Plus précisément :1. Un arbre vide est un x2d-arbre (resp. un y2d-arbre).

3. Dans la suite nous utilisons parfois le préfixe x- (resp. y-) pour désigner une entité duniveau x (resp. y).

4. Un 1d-arbre est donc un abr.

Page 306: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 297

2. Un arbre binaire de couples, dont la racine représente le couple (x, y) estun x2d-arbre (resp. un y2d-arbre) si et seulement si :– les couples représentés dans le sous-arbre gauche sont des points diffé-rents de la racine d’abscisses (resp. d’ordonnées) inférieures ou égales àx (resp. y) ;

– les couples représentés dans le sous-arbre droit sont des points d’abscisses(resp. d’ordonnées) supérieures à x (resp. y) ;

– les deux sous-arbres sont des y2d-arbres (resp. x2d-arbres).Nous pouvons fournir une interprétation « planaire » d’un 2d-arbre : la racine

d’un x2d-arbre (resp. d’un y2d-arbre) divise sa portion du plan (ou le plancomplet pour la racine initiale) en deux sous-espaces selon une droite parallèleà l’axe des y (resp. des x). C’est ce que montre la figure 7.5 pour la relation dutableau 7.4, page 294, en fournissant deux interprétations possibles ainsi que les2d-arbres correspondants.

×

×

×

×

××

××

×

×

x

y

2 4 6 8 10 12 14 16 18 20 22

246810121416

(12, 5)

(3, 10)

(7, 5) (9, 14)

(7, 11)

(20, 11)

(15, 3)

(21, 8)

(17, 15)

(15, 13)

×

×

×

×

××

××

×

×

x

y

2 4 6 8 10 12 14 16 18 20 22

246810121416

(15, 3)

(7, 11)

(3, 10)

(7, 5)

(12, 5)

(9, 14)

(15, 13)

(20, 11)

(21, 8) (17, 15)

Figure 7.5 – 2d-arbres et interprétation planaire.Cette figure montre deux 2d-arbres possibles pour la relation du ta-bleau 7.4, page 294, ainsi que l’interprétation planaire associée.

Dans la suite nous définissons deux types concrets auxiliaires, x2da pour leniveau x et y2da pour niveau y. Le type ec2da s’identifie à x2da. Le supportdu type concret x2da se définit formellement par :

Page 307: Structures de données et méthodes formelles ||

298 Structures de données et méthodes formelles

1) 〈〉 ∈ x2da2) g ∈ y2da ∧ d ∈ y2da ∧ (x, y) ∈ N× N ∧ (x, y) /∈ Ay(g) ∧

max(dom(Ay(g))) ≤ x ∧min(dom(Ay(d))) > x⇒

〈g, (x, y), d〉 ∈ x2da

où y2da est le support concret dual de x2da (cf. figure 7.7, page 300, pour unedescription plus complète de ce type) et Ay la fonction d’abstraction correspon-dante, qui délivre la relation abstraite à partir de sa représentation sous la formed’un arbre y2da.

Compte tenu de cette définition, le support ec2da du type concret ec2da estun simple renommage du support x2da :

a ∈ x2da⇔ a ∈ ec2da

Théorème 15 (des kd-arbres). Soit a = 〈g, (x′, y′), d〉 un kd-arbre et (x, y) ∈N× N.

1. x > x′⇒ (x, y) /∈ Ay(g),2. x ≤ x′⇒ (x, y) /∈ Ay(d).

La démonstration de ce théorème est laissée en exercice.

7.2.4 Définition de la fonction d’abstraction

La fonction d’abstraction Ax du type auxiliaire x2da se définit également demanière croisée avec la fonction d’abstraction Ay du type auxiliaire y2da :

function Ax(a) ∈ x2da� ecAbst =if a = 〈〉 →∅

| a = 〈g, (x, y), d〉 →Ay(g) ∪ {(x, y)} ∪ Ay(d)

fi

Tandis que la fonction d’abstraction A du type concret ec2da s’identifie à Ax :

function A(a) ∈ ec2da� ecAbst = Ax(a)

7.2.5 Spécification des opérations concrètes

Les figures 7.6, 7.7 et 7.8 (resp. page ci-contre, 300, 301) spécifient les typesconcrets ec2da, x2da et y2da. ec2da est le type principal qui se définit àpartir du type outil x2da. Les types x2da et y2da se définissent de manièrecroisée. Ainsi que nous l’avons dit, le type ec2da est un simple renommage dutype x2da.

Page 308: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 299

concreteType ec2da = (ec2da, (ecV ide_2d, ecAjout_2d, ecSupp_2d),(ecCoupeX_2d, ecCoupeY_2d, ecApp_2d, ecEstV ide_2d))

usesbool,x2da,N

refinesecabst

supporta ∈ x2da ⇔ a ∈ ec2da

abstractionFunctionfunction A(a) ∈ ec2da� ecAbst = Ax(a)

operationSpecifications...

function ecAjout_2d((x, y), a) ∈ (N× N)× ec2da→ ec2da =ecAjout_x((x, y), a)

;function ecSupp_2d((x, y), a) ∈ (N× N)× ec2da� ec2da =ecSupp_x((x, y), a)

;function ecCoupeX_2d(x, a) ∈ N× ec2da� ensAbst(N) =ecCoupeX_x(x, a)

;function ecCoupeY_2d(y, a) ∈ N× ec2da� ensAbst(N) =ecCoupeY_x(y, a)

...end

Figure 7.6 – Spécification du type concret ec2da.Le type concret ec2ad raffine le type abstrait ecabst. Il met en œuvredes ensembles de couples par la méthode des 2d-arbres. Ce type s’iden-tifie au type auxiliaire x2ad tant pour le support et la fonction d’abs-traction que pour les opérations. La fonction d’abstraction est présentéepage ci-contre.

7.2.6 Calcul d’une représentation des opérations concrètes

Le calcul des opérations du type principal ec2da se base sur celui des opé-rations du type x2da. Pour cette raison, nous nous intéressons tout d’abordà ce dernier type : nous développons complètement le calcul des opérationsecAjout_x, ecCoupeX_x (et par conséquent ecCoupeX_y) et nous présen-tons l’opération ecSupp_x. Le calcul des opérations ecV ide_x, ecApp_x etecEstvide_x est laissé en exercice. Celui des opérations ecCoupeY_x etecCoupeY_y est similaire aux calculs de ecCoupeX_x et de ecCoupeX_y. Lareprésentation des autres opérations peut être déduite de leurs homologues parsymétrie.

Page 309: Structures de données et méthodes formelles ||

300 Structures de données et méthodes formelles

concreteType x2da = (x2da, (ecV ide_x, ecAjout_x, ecSupp_x),(ecCoupeX_x, ecCoupeY_x, ecApp_x, ecEstV ide_x))

usesbool,y2da,N

refines ecabst

support1) 〈〉 ∈ x2da2) g ∈ y2da ∧ d ∈ y2da ∧ (x, y) ∈ N× N ∧ (x, y) /∈ Ay(g) ∧max(dom(Ay(g))) ≤ x ∧min(dom(Ay(d))) > x

⇒〈g, (x, y), d〉 ∈ x2da

abstractionFunctionfunction Ax(a) ∈ x2da� ecAbst = . . .

operationSpecifications...

function ecAjout_x((x, y), a) ∈ (N× N)× x2da→ x2da =b : (b ∈ x2da ∧ Ax(b) = ecAjout((x, y),Ax(a)))

;function ecSupp_x((x, y), a) ∈ (N× N)× x2da� x2da =b : (b ∈ x2da ∧ Ax(b) = ecSupp((x, y),Ax(a)))

;function ecCoupeX_x(x, a) ∈ N× x2da� ensAbst(N) =ecCoupeX(x,Ax(a)))

;function ecCoupeY_x(y, a) ∈ N× x2da� ensAbst(N) =ecCoupeY (y,Ax(a))

...end

Figure 7.7 – Spécification du type concret x2da.Le type concret x2ad raffine le type abstrait ecabst. Il représente lesniveaux x.

Calcul d’une représentation des opérations ecAjout_x et ecAjout_2d

L’opération ecAjout_x((x, y), a) ajoute le couple (x, y) à l’ensemble repré-senté par le 2d-arbre a. Le calcul est comparable à celui de l’insertion aux feuillesdans un abr (cf. section 6.3.4), la principale différence portant sur l’existenced’une alternance entre deux niveaux consécutifs : niveau x, puis niveau y, etc.

Ax(ecAjout_x((x, y), a))= Propriété caractéristique de ecAjout_x

Ax(a) ∪ {(x, y)} (7.2.1)

Nous réalisons une induction sur la structure de l’arbre a en débutant para = 〈〉 :

Page 310: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 301

concreteType y2da = (y2da, (ecV ide_y, ecAjout_y, ecSupp_y),(ecCoupeX_y, ecCoupeY_y, ecApp_y, ecEstV ide_y))

usesbool,x2da, ecabst,N

support1) 〈〉 ∈ y2da2) g ∈ x2da ∧ d ∈ x2da ∧ (x, y) ∈ N× N ∧ (x, y) /∈ Ax(g) ∧max(ran(Ax(g))) ≤ y ∧min(ran(Ax(d))) > y

⇒〈g, (x, y), d〉 ∈ y2da

abstractionFunctionfunction Ay(a) ∈ y2da� ecAbst = . . .

operationSpecifications...

function ecAjout_y((x, y), a) ∈ (N× N)× y2da→ y2da =b : (b ∈ y2da ∧ Ay(b) = ecAjout((x, y),Ay(a)))

;function ecSupp_y((x, y), a) ∈ (N× N)× y2da� y2da =b : (b ∈ y2da ∧ Ay(b) = ecSupp((x, y),Ay(a)))

;function ecCoupeX_y(x, a) ∈ N× y2da� ensAbst(N) =ecCoupeX(x,Ay(a))) ;

;function ecCoupeY_y(y, a) ∈ N× y2da� ensAbst(N) =ecCoupeY (y,Ay(a)) ;

...end

Figure 7.8 – Spécification du type concret y2da.Le type concret y2da est un type auxiliaire pour la définition du typex2da. Il représente les niveaux y.

Ax(a) ∪ {(x, y)}= Hypothèse

Ax(〈〉) ∪ {(x, y)}= Définition de Ax

∅ ∪ {(x, y)}= Définition de Ay

Ay(〈〉) ∪ {(x, y)}= Propriété A.9

Ay(〈〉) ∪ {(x, y)} ∪ ∅= Définition de Ay

Ay(〈〉) ∪ {(x, y)} ∪ Ay(〈〉)= Définition de Ax

Page 311: Structures de données et méthodes formelles ||

302 Structures de données et méthodes formelles

Ax(〈〈〉, (x, y), 〈〉〉)

D’où, d’après la propriété de l’équation à membres identiques (page 67), la pre-mière équation gardée :

a = 〈〉 →ecAjout_x((x, y), a) = 〈〈〉, (x, y), 〈〉〉

Concernant la partie inductive, nous pouvons poser a = 〈g, (x′, y′), d〉. Lessous-arbres g et d se situent sur un niveau y. Ce sont des y2da. En repartant dela formule 7.2.1, nous avons immédiatement :

Ax(a) ∪ {(x, y)}= Hypothèse

Ax(〈g, (x′, y′), d〉) ∪ {(x, y)}= Définition de Ax

Ay(g) ∪ {(x′, y′)} ∪ Ay(d) ∪ {(x, y)} (7.2.2)

Il nous faut alors procéder à une analyse par cas selon que (x, y) = (x′, y′) ounon. Dans le premier cas, nous avons :

Ay(g) ∪ {(x′, y′)} ∪ Ay(d) ∪ {(x, y)}= Propriété A.18

Ay(g) ∪ {(x′, y′)} ∪ Ay(d)= Définition de Ax

Ax(〈g, (x′, y′), d〉)= Hypothèse

Ax(a)

D’où nous obtenons l’équation gardée :

a = 〈g, (x′, y′), d〉 →(x, y) = (x′, y′) →

ecAjout_x((x, y), a) = a

Si au contraire (x, y) = (x′, y′), nous procédons à une analyse par cas selonque x ≤ x′ ou que x > x′. Développons le premier cas en repartant de laformule 7.2.2 :

Ay(g) ∪ {(x′, y′)} ∪ Ay(d) ∪ {(x, y)}= Propriété A.7

Ay(g) ∪ {(x, y)} ∪ {(x′, y′)} ∪ Ay(d)= Propriété caractéristique de ecAjout_y

Ay(ecAjout_y((x, y), g)) ∪ {(x′, y′)} ∪ Ay(d)= Définition de Ax

Ax(〈ecAjout_y((x, y), g), (x′, y′), d〉)

Cette dernière formule nous donne, d’après la propriété de l’équation à membresidentiques (page 67), l’équation gardée suivante :

Page 312: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 303

a = 〈g, (x′, y′), d〉 →(x, y) = (x′, y′) →

x ≤ x′ →ecAjout_x((x, y), a) = 〈ecAjout_y((x, y), g), (x′, y′), d〉

Le cas x > x′ se traite de manière analogue. Au total, nous avons calculé lareprésentation suivante de l’opération ecAjout_x :

function ecAjout_x((x, y), a) ∈ (N× N)× x2da→ x2da =if a = 〈〉 → /*vraie insertion*/

〈〈〉, (x, y), 〈〉〉| a = 〈g, (x′, y′), d〉 →

if (x, y) = (x′, y′) → /*fausse insertion*/a

| (x, y) = (x′, y′) →if x ≤ x′ → /*insertion à gauche*/

〈ecAjout_y((x, y), g), (x′, y′), d〉| x > x′ → /*insertion à droite*/

〈g, (x′, y′), ecAjout_y((x, y), d)〉fi

fifi

Il est alors facile d’en déduire une représentation de l’opération de baseecAjout_2d :

ecAjout_2d((x, y), a)= Spécification de ecAjout_2d

ecAjout_x((x, y), a)

D’où la représentation de l’opération ecAjout_2d :

function ecAjout_2d((x, y), a) ∈ (N× N)× ec2da→ ec2da =ecAjout_x((x, y), a)

Concernant la complexité de l’insertion dans un kd-arbre aléatoire, J. Bentley(cf. [13], page 511) montre une identité de comportement avec celui de l’insertionaux feuilles dans un abr aléatoire. Pour y parvenir, il ramène le calcul sur les kd-arbres à celui sur les abr (cf. section 6.3.4). Il en conclut que le coût de l’insertiondans un kd-arbre de poids n est en O(log n). Il en est de même pour le coût del’opération de recherche ecApp_2d. Cependant, dans le cas de 2d-arbres qui nesont pas aléatoires, la complexité au pire est en O(n).

Calcul d’une représentation des opérations ecCoupeX_x et ecCoupeX_y

Rappelons que l’opération ecCoupeX_x(x, a) s’applique à un x2d-arbre etdélivre l’ensemble des valeurs y telles que (x, y) est un couple de l’ensemblereprésenté par l’arbre a. Nous verrons que sur un x-niveau il est possible de

Page 313: Structures de données et méthodes formelles ||

304 Structures de données et méthodes formelles

sélectionner le sous-arbre vers lequel poursuivre la recherche, mais que sur uny-niveau il est nécessaire d’explorer le sous-arbre gauche et le droit. Insistons parailleurs sur le fait que la spécification de l’opération ecCoupeX_x(x, a) ne prendpas position sur la représentation de l’ensemble constituant le résultat. Celui-ciest exprimé par le type abstrait ensabst(N). Un raffinement ultime est doncnécessaire afin de préciser la représentation choisie pour ensabst(N). Celle-cidevra permettre d’exprimer l’union de deux ensembles.

ecCoupeX_x(x, a)= Spécification de ecCoupeX_x

Ax(a)[{x}] (7.2.3)

Procédons à une induction sur la structure de a, en débutant par le cas debase a = 〈〉.

Ax(a)[{x}]= Hypothèse

Ax(〈〉)[{x}]= Définition de Ax

∅[{x}]= Propriété B.62∅

D’où l’équation gardée :

a = 〈〉 →ecCoupeX_x(x, a) = ∅

La partie inductive considère que a = 〈g, (x′, y′), d〉. Nous repartons de laformule 7.2.3 :

Ax(a)[{x}]= Hypothèse

Ax(〈g, (x′, y′), d〉)[{x}]= Définition de Ax

(Ay(g) ∪ {(x′, y′)} ∪ Ay(d))[{x}]= Propriété B.57

Ay(g)[{x}] ∪ {(x′, y′)}[{x}] ∪ Ay(d)[{x}]

Dans l’hypothèse où x ≤ x′, nous pouvons en conclure que par transitivitémin(dom(Ay(d))) > x et donc la propriété B.62 s’applique. Elle permet d’élimi-ner le troisième terme :

Ay(g)[{x}] ∪ {(x′, y′)}[{x}] ∪ Ay(d)[{x}]= Remarque ci-dessus et propriété B.62

Ay(g)[{x}] ∪ {(x′, y′)}[{x}] ∪ ∅= Propriété A.9

Ay(g)[{x}] ∪ {(x′, y′)}[{x}]

Page 314: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 305

Nous pouvons alors développer séparément chacun des deux termes. Débutonspar Ay(g)[{x}] :

Ay(g)[{x}]= Propriété caractéristique de ecCoupeX_y

ecCoupeX_y(x, g)

Le terme {(x′, y′)}[{x}] exige une analyse par cas selon que x = x′ ou non. Six = x′ nous avons :

{(x′, y′)}[{x}]= Propriété B.60

{y′}

Sinon nous avons :

{(x′, y′)}[{x}]= Propriété B.62∅

En regroupant le résultat des calculs, nous obtenons l’équation gardée suivante :

a = 〈g, (x′, y′), d〉 →ecCoupeX_x(x, a) =

ecCoupeX_y(x, g) ∪ if x = x′ → {y′} | x = x′ → ∅ fi

Le cas x > x′ se traite de manière analogue, mais se limite à effectuer la x-recherche sur la droite. Au total, nous obtenons la représentation suivante del’opération ecCoupeX_x :

function ecCoupeX_x(x, a) ∈ N× x2da� ensAbst =if a = 〈〉 →∅

| a = 〈g, (x′, y′), d〉 →if x ≤ x′ →

ecCoupeX_y(x, g) ∪ if x = x′ → {y′} | x = x′ → ∅ fi| x > x′ →

ecCoupeX_y(x, d)fi

fi

Reste à calculer la représentation de l’opération ecCoupeX_y. Celle-ci ne sedéduit pas de celle de ecCoupeX_x par symétrie. En effet, ecCoupeX_y coupeun y2d-arbre selon la première coordonnée. Or un tel arbre n’est pas un arbrede recherche en x. Il nous faut donc reprendre le calcul :

ecCoupeX_y(x, a)= Spécification de ecCoupeX_y

Ay(a)[{x}] (7.2.4)

Page 315: Structures de données et méthodes formelles ||

306 Structures de données et méthodes formelles

La suite du calcul se fait par induction sur la structure de a. Pour le cas de base,nous sommes dans la même situation que pour l’opération ecCoupeX_x. Nousavons donc l’équation gardée :

a = 〈〉 →ecCoupeX_y(x, a) = ∅

Par contre, pour ce qui concerne la partie inductive, puisque a est un y2d-arbre, la racine ne partitionne pas les points selon l’abscisse. Il est donc nécessairede poursuivre la recherche systématiquement dans les deux sous-arbres, gaucheet droit. En repartant de la formule 7.2.4 et après avoir posé a = 〈g, (x′, y′), d〉,nous avons :

Ay(a)[{x}]= Hypothèse

Ay(〈g, (x′, y′), d〉)[{x}]= Définition de Ax

(Ax(g) ∪ {(x′, y′)} ∪ Ax(d))[{x}]= Propriété B.57

Ax(g)[{x}] ∪ {(x′, y′)}[{x}] ∪ Ax(d)[{x}]

Le second terme, {(x′, y′)}[{x}], se traite comme ci-dessus mais l’analogie s’arrêtelà puisqu’il faut conserver les deux autres termes (le premier et le dernier). Nousobtenons la seconde et dernière équation gardée :

a = 〈g, (x′, y′), d〉 →ecCoupeX_y(x, a) =

ecCoupeX_x(x, g) ∪ ecCoupeX_x(x, d) ∪if x = x′ → {y′} | x = x′ → ∅ fi

Au total, nous avons calculé la version suivante de l’opération ecCoupeX_y :

function ecCoupeX_y(x, a) ∈ N× x2da� ensAbst =if a = 〈〉 →∅

| a = 〈g, (x′, y′), d〉 →

ecCoupeX_x(x, g) ∪ ecCoupeX_x(x, d) ∪

⎛⎜⎜⎜⎜⎝if x = x′ →

{y′}| x = x′ →∅

fi

⎞⎟⎟⎟⎟⎠fi

La représentation des opérations ecCoupeX_2d et ecCoupeY_2d s’en déduitfacilement.

Qu’en est-il de la complexité de l’opération de coupure (évaluée en nombred’appels aux fonctions ecCoupeX_x et ecCoupeX_y et en faisant abstractiondes opérations sur les ensembles) ? Pour un arbre de n nœuds, le cas le pire est

Page 316: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 307

clairement en O(n). Par contre, dans le cas d’un arbre plein 5 (cf. section 3.5)pour lequel n = 2m− 1, les complexités Cx(n) et Cy(n) s’expriment par les équa-tions récurrentes ci-dessous. Celles-ci sont obtenues à partir de la représentationdes deux opérations :{

Cx(0) = 1Cx(2m − 1) = Cy(2m−1 − 1) pour m > 0

(7.2.5){Cy(0) = 1Cy(2m − 1) = 2 · Cx(2m−1 − 1) pour m > 0

On montre alors que Cx(n) = (n + 1)12 et donc que Cx(n) est en n

12 (cf. exer-

cice 7.2.1).

Représentation de l’opération ecSupp_x

Le calcul des opérations auxiliaires ecSupp_x et ecSupp_y ne présente pasde difficulté par rapport aux calculs déjà effectués. Ils sont proposés à l’exer-cice 7.2.3. Une représentation possible pour ecSupp_x est la suivante :

function ecSupp_x((x, y), a) ∈ (N× N)× x2da� x2da =if a = 〈〉 → /*fausse suppression*/

a| a = 〈g, (x′, y′), d〉 →

if (x, y) = (x′, y′) →if x ≤ x′ → /*suppression à gauche*/

〈ecSupp_y((x, y), g), (x′, y′), d〉| x > x′ → /*suppression à droite*/

〈g, (x′, y′), ecSupp_y((x, y), d)〉fi

| (x, y) = (x′, y′) →if g = 〈〉 ∧ d = 〈〉 → /*suppression sur une feuille*/

〈〉| g = 〈〉 → /*remplacement par le max. gauche*/

let (xg, yg) := maxX_x(g) in〈ecSupp_y((xg, yg), g), (xg, yg), d〉

end| d = 〈〉 → /*remplacement par le min. droit*/

let (xd, yd) := minX_x(d) in〈g, (xd, yd), ecSupp_y((xd, yd), d)〉

endfi

fifi

5. Un arbre plein est un arbre particulièrement bien équilibré en hauteur. Le résultat ci-dessous s’étend aux arbres p-équilibrés quelconques.

Page 317: Structures de données et méthodes formelles ||

308 Structures de données et méthodes formelles

maxX_x(a) (resp. minX_x(a)) est la fonction qui délivre l’un des couples x-maximum (resp. x-minimum) dans l’arbre non vide a. L’opération ecSupp_y,qui supprime un couple d’un arbre de niveau y, s’obtient par symétrie. Ellen’est pas représentée ici. Outre l’existence d’une alternance de niveaux, la prin-cipale différence avec la suppression dans les abr porte sur le fait qu’ici nousne savons pas fusionner la recherche d’un extremum avec la suppression. Noussommes à présent face au problème de la représentation des fonctions maxX_xetminX_x (et des fonctionsmaxX_y etminX_y pour l’opération ecSupp_y).Nous avons vu (cf. sections 1.10 et 2.4) que deux types de réaction sont alorspossibles : soit nous évaluons quand nécessaire les opérations en question (avecle risque d’être confronté à une complexité temporelle excessive), soit nous ren-forçons le support en décomposant ces fonctions sur la structure de données. Lerisque étant cette fois d’accroître la complexité spatiale. Cette dernière solutionn’est cependant viable que si la fonction est O(1)-décomposable (cf. encadrépage 188). La première solution est proposée en exercice (cf. exercice 7.2.2). Laseconde solution nous conduit à enrichir le support par des champs contenantla valeur de chacune des fonctions. Ainsi, sur un x-nœud, nous aurons à notredisposition le couple x-maximum à gauche et le couple x-minimum à droite.Trouver le couple qui viendra remplacer la racine lors d’une suppression se faiten consultant les nouvelles informations situées sur le nœud considéré (inutile dedescendre dans l’arbre). Il suffit ensuite de supprimer ce couple dans le sous-arbrecorrespondant. Ces fonctions sont bien O(1)-décomposables (la vérification estimmédiate). Appliquée à un arbre équilibré de poids n, ecSupp_x (de même queecSupp_y) est en O(log n). Ce raffinement est proposé à l’exercice 7.2.3. Notonsque ces modifications, par les conséquences qu’elles entraînent sur le support,ont un impact sur toutes les opérations de mise à jour. La représentation del’opération de base ecSupp_2d s’en déduit facilement :

function ecSupp_2d((x, y), a) ∈ (N× N)× ec2da �� ec2da =ecSupp_x((x, y), a)

Il est clair que la suppression telle que nous l’avons présentée ci-dessus atendance à déséquilibrer l’arbre considéré. L’évaluation de complexité réaliséeci-dessus perd de son intérêt. D’autres solutions, plus radicales mais plus simplesà mettre en œuvre sont parfois utilisées pour effectuer une suppression. L’uned’elles consiste, dès que l’on a identifié le nœud à supprimer, à collecter tous lesnœuds des deux sous-arbres puis à reconstruire un 2d-arbre équilibré (cf. exer-cice 7.2.4). Dans son principe ce type de solution revient à une conversion entresupports. Un support « naïf » comme un tableau peut alors convenir commesupport intermédiaire. Une autre solution consiste à marquer les nœuds suppri-més (cf. [84, 123]), puis lorsque l’on décide de reconstruire le 2d-arbre, à ignorerles nœuds marqués. La décision de reconstruire l’arbre peut par exemple êtreprise sur un critère de rapport entre le nombre de nœuds « morts » et le nombretotal de nœuds. Là aussi il est possible d’obtenir un arbre équilibré après lareconstruction. Ce type de technique se prête a priori bien à une analyse amor-tie. Cependant, en considérant que la reconstruction se fasse dès qu’il y a (aumoins) la moitié de nœuds morts, une analyse amortie, avec comme fonction depotentiel le nombre de nœuds morts, fournit un résultat en O(n · log n).

Page 318: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 309

7.2.7 Conclusion et remarques bibliographiques

La notion de kd-arbre est due à J. Bentley dans un article initial de 1975 [13].La bibliographie rassemblée ici (outre la référence précédente, [84, 120, 88, 18, 39,22, 123]) sous-évalue les énormes développements auxquels les kd-arbres et plusgénéralement les « structures spatiales » ont donné naissance. Malgré ces efforts,le défi de l’efficacité reste d’actualité. Nous avons vu que l’on sait traiter efficace-ment la plupart des opérations classiques mais uniquement dans le cas d’arbreséquilibrés. Toutefois, on ne sait pas maintenir cet équilibre autrement que parune reconstruction – coûteuse – de la structure. De plus on ne connaît pas destructures autoadaptatives satisfaisantes. Le problème de la complexité spatialene doit pas non plus être négligé. La solution consistant à renforcer le supporten décomposant les fonctions de recherche d’extremum conduit grossièrement àdoubler la taille des nœuds. Compte tenu des applications concernées, commel’astronomie, les limites de la mémoire risquent d’être rapidement atteintes. Ilest alors intéressant de se tourner vers des structures partiellement sur mémoiressecondaires. La technique des arbres externes, qui permet de séparer l’index desdonnées, est alors avantageuse (cf. l’article de C. Yu [120]).

D’autres mises en œuvres concrètes peuvent être envisagées sur la base desvecteurs caractéristiques (cf. section 6.1) ou de ce qui a été réalisé pour les en-sembles de scalaires : arbres, table de hachage. La méthode du vecteur caracté-ristique se transpose en matrice (ou tableau à deux dimensions) caractéristique.La représentation planaire de la page 295 fournit une bonne idée d’une tellereprésentation. Les qualités et défauts de cette méthode se retrouvent ici : limi-tation des bornes et complexité spatiale du côté des inconvénients. Efficacité desopérations pour les avantages.

Les techniques de hachage s’adaptent sans difficulté (mais pas sans inconvé-nients) à la gestion d’ensembles de couples (cf. exercice 7.2.9). Le problème dela gestion des collisions subsiste mais l’inconvénient le plus pénalisant concernela mise en œuvre d’opérations exigeant de prendre en compte la distance entredeux points. Ce qui se manifestait dans le cas d’ensembles de scalaires par laquasi-impossibilité d’un traitement séquentiel se traduit ici par la difficulté àretrouver le point le plus proche d’un point donné. Compte tenu de l’impor-tance de ce type d’opération, le hachage est une solution qui n’est que rarementadoptée.

Concernant les représentations arborescentes, il faut citer les treaps (cf. sec-tion 6.9) qui, sous la dénomination d’arbres de recherche à priorité, sont utiliséspar E. McCreight [82] mais en imposant des limites sur les bornes d’une desdimensions. Ils sont également utilisés par J. Vuillemin dès 1978 sous la déno-mination d’arbres cartésiens [115].

Mais parmi les solutions arborescentes les plus utilisées en pratique, outre leskd-arbres, on trouve les quad trees (ou arbres quaternaires). Il s’agit de précur-seurs aux kd-arbres, proposés par R.A. Finkel et J. Bentley en 1974 (cf. [35]).Le support est un arbre 4-aire dont la racine représente un couple de coordon-nées (x, y) tandis que chacun des quatre sous-arbres représente un quadrant duplan (ou de la portion du plan) considéré. Là aussi, étant donné un ensemble decouples, il existe en général plusieurs représentations possibles. Ainsi la relationdu tableau 7.4, page 294, pourrait par exemple se représenter comme le montre

Page 319: Structures de données et méthodes formelles ||

310 Structures de données et méthodes formelles

la figure 7.9 ci-dessous. Dans les quad trees, la suppression est une opérationdélicate. L’article original [35] propose de réintroduire tous les descendants dunœud supprimé l’un après l’autre. Cette méthode est bien entendu très coûteuse.Dans [99], H. Samet étudie une optimisation qui consiste à prendre comme nou-velle racine le nœud qui minimise le nombre de réintroductions. Les quad treespeuvent être utilisés pour représenter non plus des points mais des régions d’unplan (on parle alors de « quad trees zone »). Lorsque l’on représente des pointsd’un espace à trois dimensions, on utilise des « octrees » qui découpent l’espaceen 8 octants. 2d-arbres et quad trees ont des performances assez semblables(cf. [18] pour une évaluation expérimentale). Par contre, la suppression est plussimple dans les 2d-arbres.

×

×

×

×

××

××

×

×

x

y

2 4 6 8 10 12 14 16 18 20 22

246810121416

(12, 5)

(7, 11)

(9, 14) (3, 10)

(7, 5)

(15, 3) (15, 13)

(20, 11)

(21, 7)

(17, 15)

Figure 7.9 – Quad tree et interprétation planaire.Cette figure montre un quad tree possible pour la relation du tableau 7.4,page 294, ainsi que l’interprétation planaire associée. Dans l’arbre ci-dessus, les quadrants sont représentés dans l’ordre nord-ouest, sud-est,nord-est, sud-ouest.

Concluons par une citation de D. Knuth dans [75], page 579, (section consa-crée à la recherche sur clés secondaires) : en conséquence il n’est pas improbablequ’une approche complètement nouvelle de la conception de machines soit dé-couverte, qui résoudrait une fois pour toutes le problème de la recherche sur cléssecondaires, rendant obsolète la totalité de cette section.

Exercices

Exercice 7.2.1 Montrer que pour m pair et n = 2m − 1 la solution au système d’équationsrécurrentes 7.2.5, page 307, est Cx(n) = (n+ 1)

12 .

Exercice 7.2.2 Calculer les fonctions auxiliaires maxX_x, minX_x, maxX_y et minX_y.Évaluer la complexité la meilleure et la pire.

Exercice 7.2.3 Calculer l’opération ecSupp_x puis raffiner les opérations calculées en décom-posant les opérations maxX_x, minX_x, maxX_y et minX_y sur la structure de données.

Page 320: Structures de données et méthodes formelles ||

7. Ensembles de clés structurées 311

Toutes les opérations de mise à jour doivent être revues afin que les propriétés du supportdemeurent invariantes.

Exercice 7.2.4 (Construction d’un 2d-arbre) On dispose d’un ensemble de couplesd’entiers dans un tableau t. Étudier le problème de la construction d’un 2d-arbre équilibré àpartir de t. Évaluer la complexité.

Exercice 7.2.5 La démarche utilisée ci-dessus consistant à construire une fonction (d’ajout,de suppression, etc.) par dimension n’est pas tenable lorsque le nombre de dimensions est élevé.Il est alors nécessaire de fusionner les fonctions similaires mais travaillant sur des « niveaux »différents en une seule fonction véhiculant le niveau considéré comme paramètre. Effectuerl’analyse, la formalisation et le calcul de façon à prendre en compte ce type de généralisation.

Exercice 7.2.6 Refaire l’analyse, la formalisation et le calcul des opérations en utilisant unsupport du type arbre externe.

Exercice 7.2.7 Enrichir le type abstrait ecabst par les opérations suivantes :– recherche du plus proche voisin d’un point donné pour une distance euclidienne,– recherche des points à l’intérieur d’un cercle, d’un rectangle.

Calculer une représentation avec une mise en œuvre sur un support du type kd-arbre. Évaluerla complexité la meilleure et la pire.

Exercice 7.2.8 Fournir la spécification concrète de la mise en œuvre d’ensembles de couplespar quad trees (support, fonction de raffinement et opérations du type abstrait à l’exceptionde la suppression). Calculer une représentation pour chacune des opérations.

Exercice 7.2.9 (Ensemble de couples par table de hachage) Étant donné un coupled’entiers (x, y), il est possible de calculer une valeur de hachage pour chaque composant ducouple. (x, y) peut donc être utilisé pour accéder directement à une cellule d’un tableau à deuxdimensions. Le problème des collisions (cf. section 6.4.1) interdit de réserver cette cellule àce seul élément puisque plusieurs couples peuvent entrer en compétition pour l’occupation del’emplacement. Une cellule représente donc un sous-ensemble de l’ensemble initial. Pour lescouples du tableau 7.4, page 294, pour un tableau de hachage défini sur 0 .. 2× 0 .. 2 et pourune fonction de hachage délivrant le composant (x ou y) de la clé modulo 3, nous obtenons letableau ci-dessous (x verticalement, y horizontalement) :

0 1 20 {(15,3)} {(3,10),(15,13)} {(9,14),(12,5),(21,8)}1 {(7,5),(7,11)}2 {(17,5)} {(20,11)}

Ainsi, par exemple, le couple (3, 10) donne (0, 1) par un calcul modulo 3. (0, 1) constitue lescoordonnées de la cellule destinée à recevoir le couple (3, 10). Cette représentation convientbien pour toutes les opérations du type abstrait de la figure 7.4. Fournir une spécificationconcrète pour cette mise en œuvre. Calculer les différentes opérations. Cette solution exigecependant d’être raffinée puisque chaque entrée du tableau est un ensemble ecAbst. Raffinercette solution en utilisant un 2d-arbre afin d’obtenir une solution implantable.

Page 321: Structures de données et méthodes formelles ||

Chapitre 8

Files simples

Dans ce chapitre nous étudions les files simples. Nous avons décidé departir d’une spécification abstraite fondée sur une liste. Par contre nous avonsécarté la mise en œuvre classique sous forme de tableau. Sa nature peu fonction-nelle complexifie les calculs. Nous avons retenu la solution par « double liste » (oudouble pile si l’on préfère) qui, dans notre contexte, présente plusieurs avantages.C’est une structure fonctionnelle qui illustre de manière simple et convaincantela notion de complexité amortie ; en outre, le résultat se caractérise à la foispar son originalité et son élégance. Nous supposons le lecteur familiarisé avecla notion de pile ainsi qu’avec ses deux principales mises en œuvre (contiguë etchaînée). Ci-dessous une liste est considérée comme une représentation concrètecorrecte d’une pile.

8.1 Présentation informelle des files simples

Dans cette section nous considérons les files 1 Fifo (First In First Out :premier entré/premier sorti). Les éléments sont pris dans un ensemble T (dont lesupport est t) qui constitue le paramètre du type fileabst. Les éléments placésdans une file sont considérés comme des identifiants ; pour une file donnée, ilssont donc tous différents.

– fV ide(), opération qui délivre une file vide ;– fAjout(v, f), opération qui « insère » l’élément v en queue de la file f ;– fSupp(f), opération qui « supprime » l’élément en tête de la file f, selonla stratégie Fifo. Cette opération est préconditionnée par le fait que la filef n’est pas vide ;

– fPremier(f), opération qui délivre (sans le supprimer) l’élément en têtede la file f, déterminé par la stratégie Fifo. Cette opération est précondi-tionnée par le fait que la file n’est pas vide ;

– fEstV ide(f), opération qui délivre true si et seulement si la file f estvide.

1. Nous ne nous intéressons pas ici à la théorie des files d’attente qui a elle comme objectifde quantifier le temps d’attente en fonction de la loi d’arrivée des entrants.

Page 322: Structures de données et méthodes formelles ||

314 Structures de données et méthodes formelles

Spécifier une file d’attente en utilisant la théorie des ensembles peut se fairede plusieurs façons. L’une d’elle consiste à considérer qu’une file est une fonc-tion totale d’un intervalle quelconque de Z dans T. L’intervalle constituantle domaine de définition ne joue alors aucun rôle particulier (seule sa lon-gueur est significative) et, si nous supposons que T = N, l’ensemble suivant :{−2 �→ 3,−1 �→ 12, 0 �→ 17, 1 �→ 1} représente la même file que l’ensemble{153 �→ 3, 154 �→ 12, 155 �→ 17, 156 �→ 1}.

Cette solution est séduisante dans la mesure où elle ne conduit pas à sur-spécifier le concept de file en imposant un intervalle particulier. Par contre, parrapport à notre approche, elle introduit un inconvénient quasi rédhibitoire quiest que lors du raffinement, l’association entre le support concret et le supportabstrait est de nature relationnelle et non pas fonctionnelle, puisqu’à chaque fileconcrète correspond une infinité de files abstraites.

Pour contourner cette difficulté (imputable à notre modèle de raffinement),il est possible d’envisager une solution où le domaine de définition de la fileabstraite débute en une position fixe, par exemple 1.

Si l’on considère la file suivante :

1 �→ 32 �→ 123 �→ 174 �→ 1

représentée en notation ensembliste par la fonction {1 �→ 3, 2 �→ 12, 3 �→ 17, 4 �→1}, l’adjonction de la valeur v à la file se fait par l’adjonction à la fonction ducouple (5, v), tandis que la suppression de la file se fait en supprimant le coupleayant 1 comme première composante, puis en décalant les autres valeurs « versles indices bas », de façon à préserver la propriété qui veut que le domaine dedéfinition débute en 1.

1 �→ 3 1 �→ 31 �→ 12 suppression 2 �→ 12 ajout de 4 2 �→ 122 �→ 17 ←− 3 �→ 17 −→ 3 �→ 173 �→ 1 4 �→ 1 4 �→ 1

5 �→ 4

Une autre solution consiste à spécifier les files simples à partir des listes tellesque définies à la section 3.1, page 78. C’est cette solution que nous développonsici.

8.2 Spécification du type abstrait fileabst

Le type abstrait fileabst se définit à partir du type liste de la section 3.1.Il hérite des opérations et , qui deviennent des opérations auxiliaires, et dusupport, qui cependant s’enrichit du fait qu’ici il n’existe pas de doublon, puisqueles éléments d’une file sont des identifiants. Spécifier cette caractéristique exige despécifier et d’utiliser la fonction ens qui délivre l’ensemble des éléments présentsdans la file. Nous avons donc la définition suivante pour le support de fileabst :

Page 323: Structures de données et méthodes formelles ||

8. Files simples 315

1) [ ] ∈ fileAbst(T )2) v ∈ t ∧ l ∈ fileAbst(T ) ∧ v /∈ ens(l) ⇒ [v | l] ∈ fileAbst(T )

La figure 8.1, page suivante, (complétée par la figure 8.2) représente la spéci-fication du type abstrait fileabst. L’opération fAjout(v, f) exige une précon-dition. Celle-ci stipule que l’élément ajouté n’est pas déjà présent dans la file.Pour spécifier cette précondition, nous utilisons la fonction auxiliaire, ens, déjàintroduite ci-dessus. Cette fonction n’a pas besoin d’être implantée 2 puisqu’ellen’est utilisée que dans la partie précondition. L’ajout se fait « en queue », cecis’obtient en affirmant que la file résultante est l’inverse de la file obtenue eninsérant la valeur v dans l’inverse de la file f initiale.

Remarquons que si nous disposions de tableaux fortement flexibles (cf. cha-pitre 10), nous pourrions utiliser directement ce type de structure de donnéespour mettre en œuvre les files simples.

8.3 Mise en œuvre « chaînée »

Dans la spécification de la figure 8.1, page suivante, l’élément en tête de listese superpose à l’élément en tête de file, tandis que l’élément de queue de la fileest le « dernier » élément de la liste. Une implantation fidèle à la spécificationprésenterait l’inconvénient d’exiger que l’insertion parcoure toute la liste à larecherche de son extrémité finale avant de procéder à l’insertion proprementdite. La complexité temporelle qui en résulterait pour l’opération d’adjonctionserait rédhibitoire. Il est nécessaire de rechercher une solution plus efficace.

Un autre type de solution « chaînée » existe, décrit dans la plupart des ou-vrages dédiés aux structures de données. Il se caractérise par le fait que l’élémentde queue (s’il existe) est identifié et accessible (« pointé ») directement. Son ef-ficacité est remarquable (toutes les opérations sont en O(1)) mais son caractère« peu fonctionnel » le rend difficile à calculer à partir de la spécification.

Une troisième solution constitue un bon compromis entre facilité de dériva-tion et efficacité. C’est la solution qui consiste à représenter la file par un couplede listes 3 similaires à celles utilisées pour la spécification du type fileabst. Lapremière liste, la « liste de tête », représente le début de la file, la seconde, la« liste de queue », la fin. Cependant cette seconde liste est inversée de façon àeffectuer l’insertion en queue de file par une insertion en tête de liste. La sup-pression comme l’insertion se font donc toujours en tête d’une liste, c’est a prioriun gage d’efficacité. Lors d’une suppression, quand la « liste de tête » est vide,elle est remplacée par l’inverse de la « liste de queue », celle-ci devenant elle-même vide. Nous verrons que, bien que la complexité la pire de l’opération desuppression (fSupp_dl) soit importante, la complexité amortie (cf. page 123)est excellente. L’exemple ci-dessous montre l’évolution d’une file à la fois dans sareprésentation concrète par une double liste et dans sa représentation abstraite.

2. Son implantation pourrait cependant se révéler nécessaire dans l’utilisation du typeconsidéré.

3. Qui, compte tenu de leur usage, se comportent en piles.

Page 324: Structures de données et méthodes formelles ||

316 Structures de données et méthodes formelles

abstractType fileabst(T ) = (fileAbst, (fV ide, fAjout, fSupp),(fPremier, fEstV ide))

uses boolsupport

1) [ ] ∈ fileAbst(T )2) v ∈ t ∧ l ∈ fileAbst(T ) ∧ v /∈ ens(l) ⇒ [v | l] ∈ fileAbst(T )

operationsfunction fV ide() ∈ fileAbst(T ) = [ ]

;function fAjout(v, f) ∈ t× fileAbst(T ) �→ fileAbst(T ) =pre

v /∈ ens(f)then[v | f ]˜

end;

function fSupp(f) ∈ fileAbst(T ) �� fileAbst(T ) =pre

f = [ ]then

let [t | q] := f in q endend

;function fPremier(f) ∈ fileAbst(T ) �→ T =pre

f = [ ]then

let [h | q] := f in h endend

;function fEstV ide(f) ∈ fileAbst(T )� bool = bool(f = [ ])

auxiliaryOperationRepresentationsfunction ens(f) ∈ fileAbst(T )� F(T ) = · · ·

;function l1 l2 ∈ fileAbst(T )× fileAbst(T )� fileAbst(T ) = · · ·

;function l˜∈ fileAbst(T )�� fileAbst(T ) = · · ·

end

Figure 8.1 – Spécification du type abstrait fileabst – partie 1.La file abstraite est définie par une liste simple. Cette solution doit êtreraffinée car les ajouts ont un coût rédhibitoire : ils exigent le parcourscomplet de la liste.

Page 325: Structures de données et méthodes formelles ||

8. Files simples 317

abstractType fileabst(T ) = · · ·...

auxiliaryOperationRepresentationsfunction ens(f) ∈ fileAbst(T )� F(T )if f = [ ]→∅

| f = [h | q] →ens(q) ∪ {h}

fi;

function l1 l2 ∈ fileAbst(T )× fileAbst(T )� fileAbst(T )pre

ens(l1) ∩ ens(l2) = ∅then

if l1 = [ ] →l2

| l1 = [h | q] →[h | q l2]

fiend

;function l˜∈ fileAbst(T )�� fileAbst(T )if l = [ ]→[ ]

| l = [h | q] ⇀q˜[h | [ ]]

fiend

Figure 8.2 – Spécification du type abstrait fileabst – partie 2.Représentation des opérations auxiliaires. L’opération ens(f) délivrel’ensemble des valeurs présentes dans la file abstraite f . L’opérationinfixée délivre la concaténation de deux listes et l’opération postfixée ˜inverse la liste en argument.

Opérations Représentation concrète File abstraite([4,8],[7,3]) → [4,8,3,7]

Insertion de 2([4,8],[2,7,3]) → [4,8,3,7,2]

Suppression([8],[2,7,3]) → [8,3,7,2]

Suppression([ ],[2,7,3]) → [3,7,2]

Suppression([3,7,2],[ ])

([7,2],[ ]) → [7,2]

Page 326: Structures de données et méthodes formelles ||

318 Structures de données et méthodes formelles

Nous notons en particulier, dans la cas de la dernière suppression, que cetteopération est réalisée en deux phases, la première consistant à inverser la listede queue dans la liste de tête et la seconde à effectuer la suppression proprementdite.

8.3.1 Définition du support concretLe support concret est constitué d’un couple de listes. Nous allons pour cela

utiliser le type fileabst spécifié à la figure 8.1, page 316, en tant que typeauxiliaire nécessaire à la définition du type filedl (file double liste) et de sonsupport fileDL 4. Nous obtenons :

a ∈ fileAbst(T ) ∧ b ∈ fileAbst(T ) ∧ ens(a) ∩ ens(b) = ∅⇔

(a, b) ∈ fileDL(T )

Notons que cette définition exige que les éléments présents dans une telle fileconcrète soient tous différents : c’est déjà le cas pour chaque file a et b, ça l’estégalement pour ces deux files prises dans leur ensemble en raison de la propriétéens(a) ∩ ens(b) = ∅ qui est requise par la définition du support.

8.3.2 Définition de la fonction d’abstractionLa fonction d’abstraction A capte le fait que la file fileDL qui correspond

à la double liste est la concaténation de la liste de tête et de l’inverse de la listede queue, soit :

function A((a, b)) ∈ fileDL(T )� fileAbst(T ) = a b˜8.3.3 Spécification formelle des opérations

Le nom des opérations concrètes dérive du nom des opérations abstraitesen le suffixant par _dl. La figure 8.3, page 320, récapitule les informations quiconstituent le type filedl. Nous remarquons que le nom du type abstrait, fi-leabst, apparaît à la fois comme type raffiné (rubrique refines) et comme typeoutil (rubrique uses). Ceci matérialise la remarque formulée lors de la définitiondu support concret.

8.3.4 Calcul de la représentation des opérations concrètesNous restreignons notre développement au calcul des trois opérations

fV ide_dl, fAjout_dl et fSupp_dl. Le cas de l’opération fPremier_dl esttrès proche de celui de l’opération fSupp_dl, tandis que celui de l’opérationfEstV ide_dl se résout facilement. La dérivation de ces deux dernières opéra-tions est laissée en exercice.

4. Le fait que le type abstrait soit utilisé comme type auxiliaire dans la spécification de lamise en œuvre constitue un cas très particulier qui ne doit pas entraîner de confusions.

Page 327: Structures de données et méthodes formelles ||

8. Files simples 319

Calcul d’une représentation de l’opération fV ide_dl

A(fV ide_dl())= Propriété caractéristique de l’opération fV ide_dl()[ ]

= [ ] est élément neutre de la concaténation[ ] [ ]

= Propriété de l’opération ˜[ ] [ ]˜

= Définition de AA(([ ], [ ]))

D’où, d’après la propriété de l’équation à membres identiques (page 67), la re-présentation suivante de l’opération fV ide_dl() :

function fV ide_dl() ∈ fileDL(T ) = ([ ], [ ])

Calcul d’une représentation de l’opération fAjout_dl

La traduction de la précondition est triviale, elle fournit le prédicat v /∈ens(a) ∧ v /∈ ens(b). Le calcul de la représentation proprement dite se présentede la manière suivante :

A(fAjout_dl(v, (a, b)))= Propriété caractéristique de l’opération fAjout_dl[v | (a b ) ]˜

= Propriété 3.1.4, page 81[v | b ˜ a ]˜

= Propriété 3.1.8, page 81 (involution de )[v | b a ]˜

= Définition de la concaténation (cf. figure 8.2, page 317)([v | b] a )˜

= Propriété 3.1.4, page 81a˜˜[v | b]˜

= Propriété 3.1.8, page 81 (involution de )a [v | b]˜

= Définition de AA((a, [v | b]))

D’où, d’après la propriété de l’équation à membres identiques (page 67), lareprésentation suivante de l’opération fAjout_dl :

function fAjout_dl(v, (a, b)) ∈ T × fileDL(T ) �→ fileDL(T ) =pre

v /∈ ens(a) ∧ v /∈ ens(b)then

(a, [v | b])end

L’ajout se fait donc toujours en tête de la liste de queue.

Page 328: Structures de données et méthodes formelles ||

320 Structures de données et méthodes formelles

concreteTypefiledl(T ) = (fileDL, (fV ide_dl, fAjout_dl, fSupp_dl),(fPremier_dl, fEstV ide_dl))

uses fileabst(T ),boolrefines fileabst(T )support

a ∈ fileAbst(T ) ∧ b ∈ fileAbst(T ) ∧ ens(a) ∩ ens(b) = ∅⇔

(a, b) ∈ fileDL(T )abstractionFunction

function A((a, b)) ∈ fileDL(T )� fileAbst(T ) = a b˜operationSpecifications

function fV ide_dl() ∈ fileDL(T ) =q : (q ∈ fileDL(T ) ∧ A(q) = fV ide())

;function fAjout_dl(v, (a, b)) ∈ t× fileDL(T ) �→ fileDL(T ) =pre

v /∈ ens(A((a, b)))then

q : (q ∈ fileDL(T ) ∧ A(q) = fAjout(v,A((a, b))))end

;function fSupp_dl((a, b)) ∈ fileDL(T ) �� fileDL(T ) = . . .pre

A((a, b)) = [ ]then

q : (q ∈ fileDL(T ) ∧ A(q) = fSupp(A((a, b))))end

;function fPremier_dl((a, b)) ∈ fileDL(T ) �→ T = . . .

;function fEstV ide_dl((a, b)) ∈ fileDL(T )� bool = . . .

end

Figure 8.3 – Spécification du type concret filedl.Une file concrète est définie par une double liste, la première sert pourles suppressions et la seconde pour les ajouts. Quand la file de suppres-sion est vide, on y inverse la file des ajouts.

Calcul d’une représentation de l’opération fSupp_dl

La précondition doit être transformée :

A((a, b)) = [ ]= Définition de A

a b˜ = [ ]

Page 329: Structures de données et méthodes formelles ||

8. Files simples 321

= Propriété 3.1.1, page 81 et spécification de l’opération ˜a = [ ] ∨ b = [ ]

Le calcul de la représentation proprement dite se présente comme suit :

A(fSupp_dl((a, b)))= Propriété caractéristique de l’opération fSupp_dl

fSupp(a b ) (8.3.1)

D’après la précondition a = [ ] ∨ b = [ ], soit a = [ ] et b = [ ] soit a = [ ].Effectuons une analyse par cas en débutant par a = [ ]. Posons a = [h | q].

fSupp(a b )= Hypothèse (a = [t | q])

fSupp([h | q] b )= Définition de la concaténation (cf. figure 8.2, page 317)

fSupp([h | q b ])= Définition de l’opération fSupp

q b˜= Définition de A

A((q, b))

D’où, d’après la propriété de l’équation à membres identiques (page 67), l’équa-tion gardée suivante :

a = [h | q] →fSupp_dl((a, b)) = (q, b)

Intéressons-nous maintenant au second cas, a = [ ] et b = [ ]. Nous repartonsde la formule 8.3.1 ci-dessus :

fSupp(a b )= Hypothèse (a = [ ])

fSupp([ ] b )= [ ] est élément neutre à gauche, et propriété 3.1.1, page 81

fSupp(b˜[ ])= Définition de ˜

fSupp(b˜[ ] )= Définition de A

fSupp(A((b , [ ])))= Propriété caractéristique de l’opération fSupp_dl

A(fSupp_dl((b , [ ])))

D’où, d’après la propriété de l’équation à membres identiques (page 67), la se-conde équation gardée :

a = [ ] →fSupp_dl((a, b)) = fSupp_dl((b , [ ]))

Page 330: Structures de données et méthodes formelles ||

322 Structures de données et méthodes formelles

Cette équation gardée s’interprète en disant que pour supprimer un élémentdans une file dont le premier composant est une liste vide, il suffit de supprimerun élément dans une file dont le premier composant est l’inverse du secondcomposant et le second élément est une liste vide.

Au total, nous obtenons la représentation suivante pour la fonctionfSupp_dl :

function fSupp_dl((a, b)) ∈ fileDL(T ) �→ fileDL(T ) =pre

¬(a = [ ] ∧ b = [ ])then

if a = [h | q] →(q, b)

| a = [ ] →fSupp_dl((b , [ ]))

fiend

8.3.5 Complexité de la mise en œuvre chaînéeLa mise en œuvre par double liste de la structure de données abstraite « file

simple » se prête particulièrement bien à l’analyse amortie de sa complexité, tantsur le plan de l’intérêt de la démarche que de son principe (cf. page 123). Il esten effet facile de comprendre que l’inversion de la liste de queue par l’opérationfSupp_dl n’est pas systématique mais, quand elle est réalisée, constitue uninvestissement vis-à-vis des appels à venir de fSupp_dl.

Nous proposons de choisir comme fonction de potentiel la fonction Φ deprofil :

Φ ∈ fileDL → R+

et telle que :

Φ((a, b)) = #(b)

Φ((a, b)) représente donc le nombre d’éléments présents dans la seconde liste.Cette fonction satisfait les conditions requises et en particulier Φ(([ ], [ ])) = 0.

Sachant qu’une insertion dans la file se limite à une insertion en têtede la première liste, il est possible de considérer que le coût réel de cetteopération est de 1 : T (fAjout_dli(v, (a, b))) = 1. La complexité amortieM(fAjout_dli(v, (a, b))) de l’opération fAjout_dli((a, b)) par rapport à Φ estalors :

M(fAjout_dli(v, (a, b)))= Définition de la complexité amortie (page 123)

T (fAjout_dli(v, (a, b))) + Φ(fAjout_dli(v, (a, b)))− Φ((a, b))= Représentation de fAjout_dl

T (fAjout_dli((a, b))) + Φ((a, [v | b]))− Φ((a, b))= Coût réel d’une insertion et définition de Φ

Page 331: Structures de données et méthodes formelles ||

8. Files simples 323

1 + #(b) + 1−#(b)= Arithmétique2

DoncM(fAjout_dli(v, (a, b))) est en O(1) pour la fonction de potentiel Φ consi-dérée.

Pour l’analyse amortie de la complexité de l’opération fSupp_dl((a, b)), ilest nécessaire de considérer les deux situations types, conformément à ce quenous apprend l’algorithme : a = [ ] et a = [ ]. Prenons tout d’abord en comptele cas a = [ ] et posons a = [h | q]. Dans ce cas, la suppression dans la file selimite à une suppression en tête de la première liste. Nous pouvons considérerque T (fSupp_dli((a, b)) = 1.

M(fSupp_dli((a, b)))= Définition du coût amorti pour l’hypothèse considérée

T (fSupp_dli((a, b))) + Φ(fSupp_dli((a, b)))− Φ(([h | q], b))= Représentation de fSupp_dl

T (fSupp_dli((a, b))) + Φ((q, b))− Φ(([h | q], b))= Définition de la fonction de potentiel Φ et coût réel1 + #(b)−#(b)

= Arithmétique1

Dans ce cas M(fSupp_dli((a, b)) est en O(1). Si a = [ ], nous savons, d’aprèsl’algorithme, que fSupp_dl(([ ], b)) = fSupp_dl((b , [ ])). Posons b˜ = [h | q] :

M(fSupp_dli((a, b)))= Définition du coût amorti pour l’hypothèse considérée

T (fSupp_dli((a, b))) + Φ(fSupp_dli((a, b)))− Φ(([ ], b))= Représentation de fSupp_dl

T (fSupp_dli((a, b))) + Φ((q, [ ]))− Φ(([ ], b))

Le coût réel de l’opération est celui d’une inversion (#(b)) plus celui de la sup-pression proprement dite (soit 1).

T (fSupp_dli((a, b))) + Φ((q, [ ]))− Φ(([ ], b))= D’après la remarque ci-dessus#(b) + 1 + Φ((q, [ ]))− Φ(([ ], b))

= Définition de la fonction de potentiel Φ#(b) + 1 +#([ ]))−#(b)

= Arithmétique#(b) + 1 + 0−#((b)

= Arithmétique1

Nous tombons à nouveau sur une complexité amortie en O(1) par rapport à lafonction Φ choisie. Le coût amorti des deux opérations étudiées est en O(1). Onatteindrait le même résultat pour les autres opérations non développées ici.

Page 332: Structures de données et méthodes formelles ||

324 Structures de données et méthodes formelles

Persistance et analyse amortie : les frères ennemisL’utilisation effective de la persistance conduit en général à invalider les

résultats acquis par une analyse amortie. Pour le comprendre considéronsl’exemple de la file simple mise en œuvre par double liste. Soit b une listede n éléments et soit l’opération fSupp_dl(([ ], b)), dont la complexitéamortie est en O(1). Supposons que nous réalisions n appels consécutifsà cette opération. En interprétant le code de l’opération fSupp_dl, il estfacile de constater que nous allons réaliser n fois la même inversion de laliste b, ce qui au total nous coûtera n2 opérations élémentaires (et non ncomme le laisse penser l’analyse amortie).

Où est l’erreur ? Elle se trouve dans le fait que nous avons considéréque la structure ([ ], b) est persistante et donc disponible à volonté. Le pa-radigme fonctionnel pur interdit un tel usage. L’argument d’un appel doitêtre le résultat d’un autre appel. Au contraire, une expression telle quefSupp_dl(. . . fSupp_dl(([ ], b)) . . .), qui évite d’exploiter la persistance,fournit un résultat compatible avec la complexité amortie. L’ouvrage deC. Okasaki [93] développe plus largement ce point. Moralité : la persis-tance est à proscrire dans un contexte d’analyse amortie.

8.3.6 Conclusion et remarques bibliographiquesLa solution par double liste est une excellente représentation. Son inconvé-

nient principal est que le coût des opérations est très variable selon les appels.Une utilisation dans un contexte de temps réel est donc à éviter.

Cette solution a probablement été découverte à l’Université Cornell parR. Hood et R. Melville [59] en 1980, publiée en 1981, puis reprise par D. Griesdans le célèbre ouvrage [45], page 250 (cf. également [93], page 16). Une solutionlégèrement différente est proposée par F.W. Burton [20] en 1982.

Exercices

Exercice 8.3.1 Dans la représentation par double liste d’une file d’attente, calculer la repré-sentation de l’opération fPremier_dl. Quel est son coût amorti vis-à-vis de la fonction depotentiel Φ utilisée à la section 8.3.5 ?

Exercice 8.3.2 (Tourniquet) Spécifier une « file à temps de service » telle que chaqueclient qui s’introduit dans la file le fait en possession de n (n > 0) jetons. Lorsqu’un client seprésente devant le « guichet » il consomme l’un des jetons et est réintroduit dans la file si sonquota de jetons est encore positif, sinon il quitte la file. Proposer un raffinement par doubleliste.

Exercice 8.3.3 (File amicale) Une file amicale est une file d’attente Fifo dans laquelle,lorsqu’un client se présente, il transmet sa « liste d’achats » au client qui le précède dans lafile à condition que ce dernier soit un « ami ». Le client disparaît alors de la file, son « ami »effectuera ses achats à sa place. Deux clients sont « amis » s’ils sont représentés par le mêmeidentificateur, la « liste d’achats » est représentée par un entier naturel positif, la transmission

Page 333: Structures de données et méthodes formelles ||

8. Files simples 325

d’une « liste d’achats » se traduit par une addition d’entiers. Spécifier les files amicales. Raffinerpar une méthode de votre choix.

Exercice 8.3.4 fileabst, le type abstrait défini ci-dessus pour les files d’attente Fifo, imposel’absence de doublon dans une file. S’assurer que l’opération fAjout n’est invoquée que si saprécondition est satisfaite peut exiger d’enrichir le type abstrait d’une opération fExiste(v, f)qui délivre true si et seulement si v apparaît dans la file f . Spécifier cette opération. Calculersa représentation dans le cas d’un raffinement par double liste.

Page 334: Structures de données et méthodes formelles ||

Chapitre 9

Files de priorité

9.1 Présentation informelle

Une file de priorité est une structure de données qui gère les adjonctionset les suppressions selon la discipline suivante : lors d’une arrivée, le client seprésente avec une valeur représentant une priorité (définie sur un ensemble dotéd’une relation d’ordre total tel que les entiers naturels comme c’est le cas ici) ;lors d’une suppression, l’élément qui a la plus forte priorité est supprimé de lafile. Par convention ici, plus l’élément est petit plus la priorité est grande. Encas de conflit lors d’une suppression (cas où plusieurs candidats ont la mêmeplus forte priorité), le choix de l’élu n’est pas précisé par la spécification. Lesopérations suivantes sont définies :

– fpV ide(), opération qui délivre une file de priorité vide ;– fpAjout(v, f), opération d’adjonction de la priorité v qui délivre une filede priorité résultant de l’ajout de la priorité v dans la file f ;

– fpPrio(f), opération qui délivre (sans la supprimer de la file f) la valeurprioritaire. Cette opération est préconditionnée par le fait que f ne soitpas vide ;

– fpSupp(f), opération qui délivre une file de priorité identique à la file f àl’exception d’une occurrence de la valeur prioritaire de f qui est supprimée.Cette opération est préconditionnée par le fait que f ne soit pas vide ;

– fpEstV ide(f), opération qui délivre la valeur true si et seulement si lafile f ne contient aucun élément.

Lorsque l’opération suivante est définie, nous qualifions la structure de donnéesde file de priorité fusionnable :

– fpFus(f, f ′), opération qui, à partir des deux files de priorité f et f ′,délivre une file représentant l’addition multiensembliste (�) des élémentsde f et de f ′.

Les files de priorité sont utilisées dans des applications telles que :– la gestion de processus dans un système d’exploitation ;– la gestion de mémoire dans un système d’exploitation (afin de permettrede sélectionner l’emplacement libre le plus adapté à la taille requise) ;

Page 335: Structures de données et méthodes formelles ||

328 Structures de données et méthodes formelles

– la simulation ;– la compression de fichiers (par exemple par codage de Huffman, cf. encadrépage 359) ;

– la recherche dans les graphes (l’algorithme de Prim pour la recherched’arbres recouvrants ou l’algorithme de Dijkstra pour la recherche de pluscourts chemins) ;

– le tri (pour trier un sac de valeurs il suffit d’itérer l’opération fpAjout pourintroduire les valeurs dans la file puis d’itérer la séquence fpPrio; fpSupppour obtenir toutes les valeurs de la file dans l’ordre croissant) ;

– la gestion de messages dans les réseaux ;– le filtrage bayésien de spams ;– la géométrie algorithmique (la recherche d’intersections) ;– etc.Les représentations naïves des files de priorité de n éléments ont, quelle que

soit la technique employée, au moins une opération de base (différente de la fu-sion) qui est en O(n). Nous allons chercher à améliorer cette situation. Plusieurstechniques s’offrent à nous parmi lesquelles les trois suivantes.

– Les minimiers parfaits binaires (tas), solution qui est bonne pour les opé-rations de base mais pas pour la fusion. Pour permettre une fusion efficace,il faut disposer d’une structure de données moins contrainte, au risque deperdre en efficacité sur une ou plusieurs opérations.

– Les minimiers binomiaux (la structure de données concrète est une file bi-nomiale, triée sur les rayons décroissants). Cette représentation a un boncomportement pour toutes les opérations, y compris la fusion. Cependant,les opérations fpPrio (recherche de la valeur de l’élément prioritaire) etfpSupp (suppression de l’élément prioritaire) sont légèrement moins effi-caces que dans la solution par tas.

– Les minimiers obliques (skew heaps). Cette solution est simple à mettre enœuvre et possède un bon comportement amorti.

Dans le cas où les opérations de fusion sont exceptionnelles ou réalisées surdes files de petites tailles, une solution par tas est suffisante.

9.2 Spécification du type abstrait fpabst

Fondamentalement, une file de priorité est un sac (un multiensemble) d’en-tiers naturels doté de deux opérations particulières par rapport aux sacs : lasuppression d’une occurrence du plus petit élément du sac (suppression d’unélément prioritaire de la file) et la recherche d’une occurrence du plus petit élé-ment (recherche d’un élément prioritaire de la file). Le support abstrait est doncsac(N), ensemble des sacs finis de N. Le type fpabst est décrit à la figure 9.1.Les notations �. . .�, ��, �, − et bMin représentent respectivement la définitionen extension d’un sac, un sac vide, l’addition multiensembliste, la différence mul-tiensembliste et la fonction qui délivre le plus petit élément d’un sac de relatifs.Ces notations et toutes celles concernant les sacs sont introduites au chapitre 3,section 3.7.

Page 336: Structures de données et méthodes formelles ||

9. Files de priorité 329

abstractType fpabst = (fpAbst, (fpV ide, fpAjout, fpSupp, fpFus),(fpPrio, fpEstV ide))

usesbool,N

supportf ∈ sac(N) ⇔ f ∈ fpAbst

operationsfunction fpV ide() ∈ fpAbst = ��

;function fpAjout(v, f) ∈ N× fpAbst → fpAbst = �v�� f

;function fpSupp(f) ∈ fpAbst �� fpAbst =pre

f = ��then

f − �bMin(f)�end

;function fpFus(f, f ′) ∈ fpAbst× fpAbst� fpAbst = f � f ′

;function fpPrio(f) ∈ fpAbst �� N =pre

f = ��thenbMin(f)

end;

function fpEstV ide(f) ∈ fpAbst� bool = bool(f = ��)end

Figure 9.1 – Spécification du type abstrait file de priorité.Ce type, dénommé fpabst, comprend six opérations : 1) fpV ide quidélivre une file vide, 2) fpAjout qui ajoute un élément dans une file,3) fpSupp qui supprime l’élément prioritaire d’une file, 4) fpFus quifusionne deux files en une seule, 5) fpPrio qui délivre l’élément prio-ritaire sans altérer la file et 6) fpEstV ide qui délivre true si la fileest vide.

9.3 Méthodes équilibrées : les tas

9.3.1 Principe

Un minimier binaire (cf. section 3.5.2, page 89) est un arbre binaire étiquetépar des valeurs prises dans un ensemble doté d’une structure d’ordre total et telque, pour tout nœud, son étiquette est inférieure ou égale aux valeurs situéesdans les sous-arbres gauche et droit. L’arbre suivant est un minimier sur N :

Page 337: Structures de données et méthodes formelles ||

330 Structures de données et méthodes formelles

2

3 2

5

18 8

12

15

Rappelons par ailleurs qu’un arbre binaire parfait à gauche (cf. chapitre 3,section 3.5) est un arbre tel que toutes les feuilles sont situées sur le dernierniveau ou sur les deux derniers niveaux de l’arbre et que les feuilles du dernierniveau sont toutes situées sur la gauche de l’arbre. Les deux arbres ci-dessoussont des arbres binaires parfaits à gauche :

• •

• •

• •

• •

• •

• •

Le mariage entre minimier binaire et arbre binaire parfait à gauche s’appelleun tas 1 (à gauche). La figure 9.2 présente trois exemples de tas (à gauche).

5

6

7 6

8

10 9

2

4

5

8 10

5

7

9 8

3

10

12

14 21

11

12 14

6

8

9

9

(1) (2) (3)

Figure 9.2 – Trois tas à gauche.Dans le tas (1), toutes les feuilles sont situées au dernier niveau. Parcontre, dans les tas (2) et (3), les feuilles sont situées sur les deuxderniers niveaux. On peut remarquer que les feuilles du dernier niveausont calées sur la gauche. Le tas (3) possède un point simple (étiquetépar la valeur 8), les tas (1) et (2) n’en ont pas.

Une telle structure se prête bien à la représentation des files de priorité (nonfusionnables). En effet :

– la recherche de l’élément prioritaire (opération abstraite fpPrio) est tri-viale, cet élément est à la racine :

– la suppression de l’élément prioritaire (opération abstraite fpSupp) con-siste à supprimer la racine puis à rétablir la structure de tas ;

1. Le terme tas est très surchargé dans le vocabulaire informatique. Selon les auteurs, ilpeut désigner aussi bien un minimier, un maximier que la zone de mémoire où sont alloués lesstructures dynamiques ou les objets. Pour ce qui nous concerne, nous réservons ce terme auxminimiers parfaits binaires.

Page 338: Structures de données et méthodes formelles ||

9. Files de priorité 331

– l’adjonction d’un élément (opération abstraite fpAjout) consiste à insérercet élément en tant que feuille puis à le remonter vers la racine jusqu’à ceque la structure de tas soit rétablie.

Intuitivement, ces opérations exigent, pour être efficaces, d’accéder facile-ment :

– à la racine du tas ;– au père d’un nœud afin d’effectuer une insertion ascendante lors d’uneadjonction ;

– aux sous-arbres d’un nœud afin d’effectuer une insertion descendante lorsd’une suppression.

La structure ainsi caractérisée n’est pas une structure fonctionnelle : elleexige des pointeurs vers le père et les sous-arbres gauche et droit. Par contre, ilest possible de mettre en œuvre un tas par un tableau.

Pour ce qui est de l’efficacité des opérations, nous pouvons prédire un boncomportement dans la mesure où le rayon d’un tas de poids n est �log n� + 1et où les opérations d’adjonction et de suppression n’exigent rien d’autre que leparcours (partiel ou complet) du chemin joignant une feuille à la racine.

9.3.2 Conclusion et remarques bibliographiques

La structure de données tas a été proposée initialement par J.W.J. Williamsen 1964 en tant que support pour un algorithme de tri. Son utilisation en tantque support pour des files de priorité est plus récente. Cette structure de donnéesse prête particulièrement bien à un double raffinement : le premier conduisant dela structure abstraite aux minimiers parfaits et le second des minimiers parfaitsaux tableaux représentant des tas.

La représentation des minimiers par tas est une solution très efficace quandles files sont petites ou quand il s’agit de files non fusionnables. Cependant, elleprésente dans certaines situations un inconvénient qui peut être rédhibitoire : ils’agit d’une représentation implicite (les pointeurs ne sont pas matérialisés). Ilpeut être difficile, voire impossible, d’implanter cette structure de données ausein d’une structure de données préexistante. C’est par exemple le cas si l’onveut implanter une file de priorité pour gérer une mémoire : il faut distribuer lesconstituants de la file de priorité dans les différents « trous » présents dans lamémoire. Ces trous ne sont pas contigus et la solution « tas » doit être écartée.

Exercice

Exercice 9.3.1 Fournir une spécification concrète des files de priorité (non fusionnables) partas. Calculer les différentes opérations.

9.4 Méthodes équilibrées : les files binomialesNous proposons tout d’abord deux définitions alternatives, équivalentes sur

le plan de la spécification, des minimiers binomiaux et des files (de priorité)

Page 339: Structures de données et méthodes formelles ||

332 Structures de données et méthodes formelles

binomiales. La première, abstraite et intuitive, est celle que l’on rencontre com-munément dans la littérature, tandis que la seconde peut être vue comme un raf-finement opérationnel de la première. Celle-ci est utilisée dans la suite, lorsqu’ils’agit de définir formellement le support et de réaliser le calcul des opérations.

Une feuille étiquetée par un entier naturel est un minimier binomial B1 derayon 1. Si Bi et B′i sont deux minimiers binomiaux de rayon i, et si la racinede Bi est inférieure à celle de B′i, alors l’arbre représenté par

Bi

B′i︸ ︷︷ ︸Bi+1

est un minimier binomial Bi+1 de rayon i + 1. Dans les exemples de minimiersci-dessous, les rayons des arbres sont, de la gauche vers la droite, 1, 3 et 4.

4 1

41

5

4

78

12

5

66

14

Par contre, les deux arbres ci-dessous ne sont pas des minimiers binomiaux. Lepremier car ce n’est tout simplement pas un minimier, le second parce qu’il estconstruit à partir de deux minimiers binomiaux de rayons différents.

4

11

5

4

75

66

14

Une file binomiale est une liste (finie) de minimiers binomiaux triée sur lesrayons décroissants. Par définition, le rayon i d’une file binomiale est le rayonde son plus grand minimier s’il existe, 0 sinon.

Bi

Bj

Bk

Page 340: Structures de données et méthodes formelles ||

9. Files de priorité 333

Ci-dessous la structure (13) est une file binomiale de longueur 2 et de rayon 3,la structure (14) est une file de longueur 4 et de rayon 4.

1

32

4

2 3

74

5

8

98

9

2

65

9

7

5

1

(13) (14)

Afin d’harmoniser les représentations des minimiers et des files binomiales,nous décidons d’adopter la représentation suivante. Un minimier binomial seconstruit à partir d’une file binomiale complète (dans laquelle tous les rayons in-termédiaires sont présents) en enracinant la file sur une valeur inférieure ou égaleà toutes les valeurs de la file. Une conséquence de ces définitions est que les deuxsupports correspondants (les files binomiales complètes fBC(n) et les minimiersbinomiaux mB(n), cf. figure 9.5, page 338) se définissent de manière mutuelle-ment récursive comme le montre le schéma suivant dans lequel un minimier derayon i+ 1 est construit à partir d’une file complète de rayon i.

Bi

Bi−1

B2

B1

En adoptant cette représentation, la file (14) (qui est une file complète, contrai-rement à la file (13)) se présente de la manière suivante :

3 2 7 1

8 4 7 5 6 5

8 9 5 9

9

Cette représentation s’applique aussi bien aux files complètes qu’aux files incom-plètes.

9.4.1 Définition des supports concretsUne file de minimiers binomiaux est donc constituée d’une liste, triée sur les

rayons décroissants, de minimiers binomiaux. La définition formelle du support

Page 341: Structures de données et méthodes formelles ||

334 Structures de données et méthodes formelles

se fait donc, à l’instar des listes classiques (cf. section 3.1, page 78), de manièreinductive.

1) [ ] ∈ fB(0)2) i, j ∈ N1 × N ∧ m ∈ mB(i) ∧ f ∈ fB(j) ∧ i > j

⇒[m | f ] ∈ fB(i)

La clause de base spécifie que la liste vide est une file binomiale de rayon 0. Laclause inductive affirme que si m est un minimier binomial de rayon i, f une filebinomiale de rayon j tel que i > j, alors nous obtenons une file binomiale derayon i en plaçant le minimier binomial m en tête de la file.

Définir formellement le support des minimiers binomiaux exige de définirau préalable la notion de file binomiale complète (fBC). Informellement, unefile binomiale complète de rayon r est une file binomiale dans laquelle il existeun minimier de rayon j, pour tout j compris entre 1 et r. Une autre façon despécifier cette contrainte consiste à affirmer que dans une file binomiale complète,la longueur, notée #(. . .), est égale au rayon. La formalisation du support fBCse présente comme suit :

j ∈ N ∧ f ∈ fB(j) ∧ #(f) = j⇔

f ∈ fBC(j)

La définition de mB(i) s’en déduit :

i ∈ N ∧ f ∈ fBC(i) ∧ a ∈ N ∧ a ≤ bMin(A(f))⇔

〈a, f〉 ∈ mB(i+ 1)

Cette définition utilise la fonction d’abstraction A qui, à partir d’une file bi-nomiale, délivre le sac de ses valeurs. Elle permet d’établir les propriétés dutableau 9.1.

Tableau 9.1 – Files et minimiers binomiaux : propriétés.Ce tableau regroupe certaines des propriétés des poids et des longueursde files ou de minimiers binomiaux.

Propriété Condition Ident.w(f) = 2i − 1 f ∈ fBC(i) (9.4.1)w(m) = 2i m ∈ mB(i+ 1) (9.4.2)w(f) ≥ 2i−1 f ∈ fB(i) (9.4.3)#(f) = log(w(f) + 1) f ∈ fBC(i) (9.4.4)#(f) ≤ log(w(f) + 1) f ∈ fB(i) ∧ i > 0 (9.4.5)

Page 342: Structures de données et méthodes formelles ||

9. Files de priorité 335

Le qualificatif de binomial qui accompagne cette structure de données pro-vient du fait que, dans un arbre binomial de rayon r, le nombre de nœuds présents

au niveau k est donné par la formule du binôme(r − 1k

)ainsi que l’illustre le

schéma ci-dessous.

1 =

(30

)

3 =

(31

)

3 =

(32

)

1 =

(33

)

niveau

0

1

2

3

9.4.2 Définition des fonctions d’abstraction

La fonction d’abstraction A qui, à partir d’une file binomiale, délivre unefile de priorité abstraite, est une fonction totale (toute file binomiale peut setransformer en file de priorité), surjective (toute file de priorité a (au moins)une représentation sous la forme d’une file binomiale). Elle n’est pas injective :une file de priorité possède en général plusieurs représentations différentes sousla forme de files binomiales. La définition de A utilise la fonction d’abstractionA′ associée aux minimiers binomiaux qui délivre également une file de prioritéabstraite.

function A(f) ∈ fB(i)� fpAbst =if f = [ ] →��

| f = [t | q] →A′(t)�A(q)

fi

Le support fBC(i) étant inclus dans le support fB(i), la fonction d’abstrac-tion A liée à fB(i) peut, sans réserve, être appliquée au support fBC(i). Cettepropriété est exploitée dans la définition de A′ qui fait usage de la fonction A.

function A′(m) ∈ mB(i)� fpAbst =let 〈r, g〉 := m in �r��A(g) end

À l’instar de A, la fonction A′ est totale, surjective, mais pas injective. La filebinomiale obtenue à partir d’un minimier binomial est l’addition multiensem-bliste du sac ayant pour seul élément la racine du minimier et du sac obtenu àpartir de la file binomiale complète qui se trouve sous la racine du minimier.

Page 343: Structures de données et méthodes formelles ||

336 Structures de données et méthodes formelles

9.4.3 Spécification des opérations concrètesComme d’habitude, la spécification des opérations concrètes se fait par homo-

morphisme de type dans la rubrique operationSpecifications du type fb(n)(cf. figures 9.3 et 9.4). Il nous faut cependant rappeler les opérations auxiliairesainsi que les opérations portant sur les minimiers binaires (du type mb(n)) (cf. fi-gure 9.5).

concreteType fb(n) =(fB, (fpV ide_fb, fpAjout_fb, fpSupp_fb, fpFus_fb),(fpPrio_fb, fpEstV ide_fb))

uses bool,mb(i),Nconstraints n ∈ Nrefines fpabst

support1) [ ] ∈ fB(0)2) i, j ∈ N1 × N ∧ m ∈ mB(i) ∧ f ∈ fB(j) ∧ i > j

⇒[m | f ] ∈ fB(i)

abstractionFunctionfunction A(f) ∈ fB(i)� fpAbst = . . .

operationSpecificationsfunction fpV ide_fb() ∈ fB(0) = · · ·

; function fpAjout_fb(v, f) ∈ N× fB(i)→ fB(n) = · · ·; function fpSupp_fb(f) ∈ fB(i) �� fB(j) = · · ·; function fpFus_fb(f, f ′) ∈ fB(i)× fB(j)� fB(n) = · · ·; function fpPrio_fb(f) ∈ fB(i) �� N = · · ·; function fpEstV ide_fb(f) ∈ fB(i)� bool = · · ·auxiliaryOperationRepresentations

function #(f) ∈ fB(i)→ N = · · ·; function r(f) ∈ fB(i)→ N = · · ·end

Figure 9.3 – Spécification du type concret file binomiale – partie 1.Le support « file binomiale », co-défini avec le support « minimier bi-nomial », permet d’implanter des « files de priorité » (fpabst). Lesprincipales opérations de fpabst ainsi que les opérations auxiliairessont spécifiées ou définies à la figure 9.4.

Pour le type fb, la fonction # fournit, comme nous l’avons déjà vu, la lon-gueur de la file. L’opération r fournit le rayon du minimier binomial en tête dela file ou 0 si la file est vide.

Concernant le type mb(n), l’opération r délivre le rayon de l’arbre en ar-gument. Si l’arbre se réduit à sa racine, son rayon vaut 1, sinon c’est le rayonde la file des descendants plus 1. Bien que le type mb soit déclaré en tant queraffinement du type abstrait fpabst, seules les opérations abstraites fpPrio etfpFus sont raffinées.

Page 344: Structures de données et méthodes formelles ||

9. Files de priorité 337

concreteTypefb(n) = · · ·...

operationSpecificationsfunction fpV ide_fb() ∈ fB(0) = . . .

;function fpAjout_fb(v, f) ∈ N× fB(i)→ fB(n) =q : (q ∈ fB(n) ∧ A(q) = fpAjout(v,A(f)))

;function fpSupp_fb(f) ∈ fB(i) �� fB(j) =pre

i > 0then

q : (q ∈ fB(j) ∧ A(q) = fpSupp(A(f)))end

;function fpFus_fb(f, f ′) ∈ fB(i)× fB(j)� fB(n) =q : (q ∈ fB(n) ∧ A(q) = fpFus(A(f),A(f ′)))

;function fpPrio_fb(f) ∈ fB(i) �� N = . . .

;function fpEstV ide_fb(f) ∈ fB(i)� bool = . . .

auxiliaryOperationRepresentationsfunction #(f) ∈ fB(i)→ N =if f = [ ]→0

| f = [t | q] →1 + #(q)

fi; function r(f) ∈ fB(i)→ N =

if f = [ ]→0

| f = [t | q] →r(t)

fiend

Figure 9.4 – Spécification du type concret file binomiale – partie 2.Trois des six opérations concrètes sont spécifiées. Deux opérations auxi-liaires : # (longueur de la file) et r (rayon de la file) sont représentées.

Le tableau 9.2 propose deux propriétés des files et minimiers binomiaux quiprécisent les relations qu’entretiennent sacs, files et arbres binomiaux. La dé-monstration de ces deux propriétés fait l’objet de l’exercice 9.4.5.

Page 345: Structures de données et méthodes formelles ||

338 Structures de données et méthodes formelles

concreteType mb(n) = (mB, (fpFus_mb), (fpPrio_mb))uses

fb(i),N,N1constraints n ∈ N1

refines fpabst

auxiliarySupportsj ∈ N ∧ f ∈ fB(j) ∧ #(f) = j

⇔f ∈ fBC(j)

supporti ∈ N ∧ f ∈ fBC(i) ∧ a ∈ N ∧ a ≤ bMin(A(f))⇔

〈a, f〉 ∈ mB(i+ 1)abstractionFunction

function A′(m) ∈ mB(i)� fpAbst = . . .operationSpecifications

function fpPrio_mb(t) ∈ mB(i)→ N = bMin(A′(t));

function fpFus_mb(t, t′) ∈ mB(i− 1)×mB(i− 1)→mB(i) =m : (m ∈ mB(i) ∧ A(m) = fpFus(A′(t),A′(t′)))

auxiliaryOperationRepresentationsfunction r(〈v, g〉) ∈ mB(i)→ N1 =if g = [ ]→1

| g = [ ]→r(g) + 1

fiend

Figure 9.5 – Spécification du type concret minimier binomial.Le support « minimier binomial » (mb) est défini en conjonction avecle support « file binomiale ». Le type mb est un type auxiliaire indirec-tement utilisé pour la mise en œuvre de files de priorité : seules deuxopérations du type abstrait (fpabst), fpPrio et fpFus sont définiesici (resp. fpPrio_mb et fpFus_mb). Une opération auxiliaire est dis-ponible, il s’agit de r, qui délivre le rayon d’un minimier. Le supportfBC (file binomiale complète) est défini comme support auxiliaire.

Tableau 9.2 – Files et minimiers binomiaux : propriétés.

Propriété Condition Ident.A′(t) = A([t | [ ]]) t ∈ mB(i) (9.4.6)�v� = A′(〈v, [ ]〉) v ∈ N (9.4.7)

Page 346: Structures de données et méthodes formelles ||

9. Files de priorité 339

9.4.4 Calcul de la représentation des opérations concrètesNous nous préoccupons tout d’abord du type mb en calculant l’opéra-

tion fpFus_mb. Nous abordons ensuite quatre des opérations du type fb,fpPrio_fb, fpFus_fb, fpAjout_fb et fpSupp_fb.

Calcul d’une représentation de l’opération fpFus_mb

Nous savons que, compte tenu du domaine de définition de cette fonction, lesdeux arguments t et t′ sont des minimiers binomiaux de même rayon.

A′(fpFus_mb(t, t′))= Propriété caractéristique de fpFus_mb

A′(t)�A′(t′) (9.4.8)

Posons t = 〈v, g〉 et t′ = 〈v′, g′〉. Deux cas seront à considérer selon la positionrelative de v et de v′. Nous débutons par v ≤ v′ :

A′(t)�A′(t′)= Hypothèse

A′(〈v, g〉)�A′(t′)= Définition de A′�v��A(g)�A′(t′)

= Définition de A�v��A([t′ | g])

= Définition de A′A′(〈v, [t′ | g]〉)

D’où la première équation gardée pour l’opération fpFus_mb :

let 〈v, g〉, 〈v′, g′〉 := t, t′ inv ≤ v′ →

fpFus_mb(t, t′) = 〈v, [t′ | g]〉end

Le cas v′ ≤ v se traite de manière similaire. Au total, nous obtenons la repré-sentation suivante de l’opération fpFus_mb :

function fpFus_mb(t, t′) ∈ mB(i− 1)×mB(i− 1)→mB(i) =let 〈v, g〉, 〈v′, g′〉 := t, t′ in

if v ≤ v′ →〈v, [t′ | g]〉

| v′ ≤ v →〈v′, [t | g′]〉

fiend

Le rayon du minimier résultant est bien égal à celui des deux arguments plusun. Fusionner deux minimiers de même rayon consiste donc : 1) à construire une

Page 347: Structures de données et méthodes formelles ||

340 Structures de données et méthodes formelles

file ayant comme tête le minimier ayant la racine la plus grande et comme queuela file de l’autre minimier ; 2) à enraciner la tête avec la plus petite racine. Leschéma ci-dessous fournit un exemple d’une telle fusion pour des minimiers derayon 3.

4

74

5

+ 5

68

9

= 4

74

5

5

68

9

Cette opération est en O(1). Nous allons à présent aborder le calcul de la repré-sentation des opérations principales du type concret fb.

Calcul d’une représentation de l’opération fpPrio_fb

La précondition stipule que le rayon i de la file f est strictement positif. Cettecontrainte est équivalente au fait que f n’est pas vide. Nous pouvons donc poserf = [t | q] comme hypothèse du calcul.

fpPrio_fb(f)= Propriété caractéristiquebMin(A(f))

= HypothèsebMin(A([t | q]))

= Définition de AbMin(A′(t)�A(q)) (9.4.9)

À ce stade, nous procédons à une induction sur la structure de la file q endébutant pas le cas q = [ ].

bMin(A′(t)�A(q))= HypothèsebMin(A′(t)�A([ ]))

= Définition de AbMin(A′(t)���)

= Propriété 3.7.2, page 104bMin(A′(t))

= Application de fpPriofpPrio(A′(t))

= Propriété caractéristique de fpPrio_mbfpPrio_mb(t)

Nous avons donc obtenu l’équation gardée suivante pour fpPrio_fb :

let [t | q] := f inq = [ ] →

fpPrio_fb(f) = fpPrio_mb(t)end

Page 348: Structures de données et méthodes formelles ||

9. Files de priorité 341

Le cas inductif se caractérise par q = [ ]. Nous repartons de la formule 9.4.9 :

bMin(A′(t)�A(q))= Propriété 3.7.15, page 104min({bMin(A′(t)), bMin(A(q))})

= Propriété caractéristique de fpPrio_mb et de fpPrio_fbmin({fpPrio_mb(t), fpPrio_fb(q)})

D’où la seconde équation gardée pour fpPrio_fb :

let [t | q] := f inq = [ ] →

fpPrio_fb(f) = min({fpPrio_mb(t), fpPrio_fb(q)})end

Au total, nous avons calculé la version suivante de l’opération fpPrio_fb :

function fpPrio_fb(f) ∈ fB(i) �� N =pre

i > 0then

let [t | q] := f inif q = [ ] →

fpPrio_mb(t)| q = [ ] →min({fpPrio_mb(t), fpPrio_fb(q)})

fiend

end

La recherche de la valeur prioritaire dans une file binomiale se fait donc enprenant le plus petit élément du minimier en tête de liste (dont on sait quec’est la racine) si la liste ne comprend qu’un seul élément et, le cas échéant, enretenant le minimum entre l’élément prioritaire du minimier en tête de liste etl’élément prioritaire de la liste de queue.

Nous allons à présent calculer la complexité asymptotique au pire de l’opé-ration fpPrio_fb. Le coût de l’opération fpPrio_mb est de un (une conditionest évaluée systématiquement).

Soit f la file argument de l’opération fpPrio_fb. La précondition impose quef n’est pas vide. Soit l sa longueur et n son poids. Soit P(l) le nombre maximumde conditions évaluées lors de l’exécution de l’opération fpPrio_fb(f). P(l)satisfait l’équation de récurrence suivante :

P(1) = 1 Garde de la conditionnelleP(l) = 1+ Pour atteindre la seconde branche de la conditionnelle

1+ Évaluation du min1+ Évaluation de fpPrio_mbP(l − 1) Appel récursif

Page 349: Structures de données et méthodes formelles ||

342 Structures de données et méthodes formelles

Soit encore :{P(1) = 1P(l) = P(l − 1) + 3 si l > 1

qui est une récurrence linéaire d’ordre 1. Elle a comme solution, pour l > 0 :

P(l) = 3 · l − 2 (9.4.10)

Nous avons alors :

P(l) = 3 · l − 2⇒ Propriété 9.4.5, page 334

P(l) ≤ 3 · log(n+ 1)− 2

D’où nous déduisons (d’après le résultat démontré à l’exercice 4.1.2) que lacomplexité au pire de l’opération fpPrio_fb est en O(log(n)).

Calcul d’une représentation de l’opération fpFus_fb

L’opération fpFus_fb est une opération appartenant au type fb. C’estaussi une opération autour de laquelle s’articule la mise en œuvre de l’opéra-tion fpSupp_fb. C’est la raison pour laquelle nous dérogeons à notre habitudede présenter les développements dans l’ordre de la spécification en nous penchantdès à présent sur le calcul de cette opération.

Développer le calcul de la représentation de fpFus_fb va nous conduire àutiliser l’hypothèse d’induction suivante, qui est démontrée conjointement audéveloppement :

Hypothèse d’induction 5 (Aug(f, f ′)). f, f ′ ∈ fB(i) × fB(j) ⇒r(fpFus_fb(f, f ′))−max({r(f), r(f ′)}) ∈ {0, 1}

Cette hypothèse d’induction postule que lorsque l’on fusionne deux files bino-miales, le résultat est une file binomiale dont le rayon augmente au plus de unpar rapport au plus grand rayon des files en arguments.

A(fpFus_fb(f, f ′))= Propriété caractéristique

A(f)�A(f ′) (9.4.11)

Nous procédons à une induction sur la structure de f en débutant par le casde base, f = [ ].

A(f)�A(f ′)= Hypothèse f = [ ]

A([ ])�A(f ′)= Définition de A���A(f ′)

= Propriétés 3.7.1 et 3.7.2, page 104A(f ′)

Page 350: Structures de données et méthodes formelles ||

9. Files de priorité 343

D’où la première équation gardée :

f = [ ]→fpFus_fb(f, f ′) = f ′

Nous remarquons (i) que le résultat est bien une file binomiale, (ii) que son rayonest égal au plus grand rayon des deux arguments (puisqu’il est égal à celui def ′). L’hypothèse d’induction 5 est donc vérifiée dans ce cas.

Pour le cas inductif, f = [ ], nous procédons à une induction secondaire surf ′, en débutant par le cas de base f ′ = [ ]. Partant de A(f)�A(f ′) (calculs nondéveloppés), nous arrivons à A(f) qui nous fournit la seconde équation gardée :

f = [ ]→f ′ = [ ]→

fpFus_fb(f, f ′) = f

Le résultat est bien une file binomiale, son rayon n’augmente pas par rapport àcelui de f , l’hypothèse d’induction 5 est donc bien vérifiée.

Nous abordons à présent, pour l’induction secondaire, le cas inductif f ′ = [ ].Posons f = [t | q] et f ′ = [t′ | q′]. Nous repartons de la formule 9.4.11ci-dessus :

A(f)�A(f ′)= Hypothèse

A([t | q])�A([t′ | q′]) (9.4.12)

Nous procédons à une analyse par cas, en considérant les trois cas suivants :(i) r(t) > r(t′), (ii) r(t) = r(t′) et (iii) r(t) < r(t′). Les cas (i) et (iii) sontsymétriques, seuls les cas (i) et (ii) sont développés ci-dessous. Débutons parr(t) > r(t′).

A([t | q])�A([t′ | q′])= Définition de A

A′(t)�A(q)�A(f ′)= Propriété caractéristique de fpFus_fb

A′(t)�A(fpFus_fb(q, f ′)) (9.4.13)

Arrivé à ce stade, il serait tentant d’exploiter la partie inductive dela définition de A pour conclure que l’expression ci-dessus est égale àA([t | fpFus_fb(q, f ′)]). Cependant rien ne garantit que cette expressionest une file binomiale puisqu’il est possible (cf. l’hypothèse d’induction 5) que lerayon de la file fpFus_fb(q, f ′) et le rayon de t soient égaux. Il faut donc réaliserune analyse par cas secondaire. Posons fpFus_fb(q, f ′) = [t′′ | q′′]. D’aprèsl’hypothèse d’induction 5, les deux seuls cas à envisager sont (i) r(t) > r(t′′) et(ii) r(t) = r(t′′). Débutons par le premier cas :

A′(t)�A(fpFus_fb(q, f ′))= Hypothèse

A′(t)�A([t′′ | q′′])= Définition de A

A([t | [t′′ | q′′]])

Page 351: Structures de données et méthodes formelles ||

344 Structures de données et méthodes formelles

D’où la troisième équation gardée :

f = [t | q] →f ′ = [t′ | q′] →

r(t) > r(t′)→let [t′′ | q′′] := fpFus_fb(q, f ′) in

r(t) > r(t′′)→fpFus_fb(f, f ′) = [t | [t′′ | q′′]]

end

Il s’agit bien d’une file binomiale. Par ailleurs, son rayon n’augmente pas parrapport à celui de la plus longue file : l’hypothèse d’induction 5 est donc bienvérifiée. Traitons à présent le second cas r(t) = r(t′′). Nous repartons de laformule 9.4.13 ci-dessus.

A′(t)�A(fpFus_fb(q, f ′))= Hypothèse

A′(t)�A([t′′ | q′′])= Définition de A

A′(t)�A′(t′′)�A(q′′)= Propriété caractéristique de fpFus_mb

A′(fpFus_mb(t, t′′))�A(q′′)= Définition de A

A([fpFus_mb(t, t′′) | q′′])

D’où la quatrième équation gardée :

f = [t | q] →f ′ = [t′ | q′] →

r(t) > r(t′) →let [t′′ | q′′] := fpFus_fb(q, f ′) in

r(t) = r(t′′) →fpFus_fb(f, f ′) = [fpFus_mb(t, t′′) | q′′]

end

Le résultat est bien une file binomiale. D’après l’hypothèse d’induction 5, lafusion de q et f ′ produit une file binomiale dont le rayon atteint au pire celui def tandis que, toujours d’après l’hypothèse d’induction, la fusion de [t′ | q′] etde [t′′ | q′′] délivre une file dont le rayon dépasse au pire de un celui de [t′ | q′].L’hypothèse d’induction est donc satisfaite.

Après avoir traité le cas r(t) > r(t′), nous abordons à présent le second casr(t) = r(t′). Repartons de la formule 9.4.12 ci-dessus :

A([t | q])�A([t′ | q′])= Définition de A

A′(t)�A(q) � A′(t′)�A(q′)= Propriété 3.7.1, page 104

A′(t)�A′(t′) � A(q) �A(q′)= Propriété caractéristique de fpFus_mb et de fpFus_fb

A′(fpFus_mb(t, t′)) � A(fpFus_fb(q, q′))

Page 352: Structures de données et méthodes formelles ||

9. Files de priorité 345

Nous savons que r(fpFus_mb(t, t′)) = r(t) + 1. Par ailleurs, selon l’hypothèsed’induction 5, le rayon de fpFus_fb(q, q′) est inférieur ou égal au rayon de t(et donc à celui de t′). Nous sommes donc dans les conditions d’application dela branche inductive de la définition de la fonction d’abstraction A. Le calcul sepoursuit donc par :

A′(fpFus_mb(t, t′)) � A(fpFus_fb(q, q′))= Définition de A

A([fpFus_mb(t, t′) | fpFus_fb(q, q′)])

D’où l’équation gardée :

f = [t | q] →f ′ = [t′ | q′] →

r(t) = r(t′)→fpFus_fb(f, f ′) = [fpFus_mb(t, t′) | fpFus_fb(q, q′)]

Le résultat est bien une file binomiale, son rayon augmente de 1 par rapport aurayon des arguments, l’hypothèse d’induction 5 est donc bien vérifiée.

Le cas r(t) < r(t′) se traite comme le cas r(t) > r(t′). Nous obtenons au totalla représentation suivante de l’opération fpFus_fb :

function fpFus_fb(f, f ′) ∈ fB(j)× fB(k)→ fB(i) =if f = [ ] →

f ′

| f = [t | q] →if f ′ = [ ] →

f| f ′ = [t′ | q′] →

if r(t) > r(t′) →let [t′′ | q′′] := fpFus_fb(q, f ′) in

if r(t) > r(t′′)→[t | [t′′ | q′′]]

| r(t) = r(t′′) →[fpFus_mb(t, t′′) | q′′]

fiend

| r(t) = r(t′) →[fpFus_mb(t, t′) | fpFus_fb(q, q′)]

| r(t) < r(t′) →...

fifi

fi

Cette fonction s’interprète de la manière suivante : si l’une au moins des filesconsidérées est vide, le résultat est l’autre file, sinon par hypothèse il existe unminimier binomial en tête de chaque file. Il faut alors distinguer trois cas selon

Page 353: Structures de données et méthodes formelles ||

346 Structures de données et méthodes formelles

la position relative des rayons de ces deux minimiers. Si les rayons sont égaux,le résultat est une file dont la tête est la fusion des deux minimiers de tête et laqueue la fusion des deux files binomiales de queue. Si les rayons sont différents,nous mettons de côté le minimier le plus grand et fusionnons la queue avec l’autrefile pour obtenir la file f ′′. Si le minimier écarté est (encore) plus grand que latête de f ′′ alors le résultat est une file qui a comme tête le minimier écarté etcomme queue f ′′, sinon (les deux minimiers ont même rayon), le résultat est unefile qui a comme tête la fusion du minimier écarté et de la tête de f ′′ et commequeue la queue de f ′′.

Nous allons à présent évaluer la complexité temporelle au pire de l’opérationfpFus_fb. Un premier obstacle surgit : nous constatons que la complexité defpFus_fb dépend en principe du rayon des files considérées puisque la versioncalculée de fpFus_fb invoque à plusieurs occasions la fonction r correspon-dante. Nous proposons de faire l’hypothèse que r est en O(1). Nous verrons ci-dessous comment faire de cette hypothèse une réalité. Par ailleurs, la complexitéde l’opération fpFus_mb est de 1 puisque son exécution se limite à évaluer uneseule conditionnelle. Nous pouvons à nouveau considérer que la complexité aupire est atteinte pour des files complètes.

Soit f et f ′ les deux files objets de la fusion, de poids respectifs n et n′. Posons#(f) + #(f ′) = l et n + n′ = N . Soit F(l) le nombre maximum de conditionsévaluées pour fusionner f et f ′. F(l) satisfait l’équation de récurrence suivante :

F(0) = 2 Conditions pour s’assurer de la vacuité des deux filesF(l) = 4+ Pour atteindre le dernier appel récursif

F(l − 1)+ Appel récursif sur des files complètes1+ Pour atteindre la dernière condition1 Appel de fpFus_mb

Soit encore :{F(0) = 2F(l) = F(l − 1) + 6 si l > 0

qui est une récurrence linéaire d’ordre 1. Elle a comme solution :

F(l) = 6 · l + 2 (9.4.14)

La propriété 9.4.4, page 334, appliquée aux files f et f ′ (supposées non vides)donne #(f) ≤ log(n + 1) et #(f ′) ≤ log(n′ + 1). Soit en additionnant membreà membre :

l ≤ log(n+ 1) + log(n′ + 1)⇔ Propriété du log

l ≤ log((n+ 1)·(n′ + 1))

Or nous savons (exercice 9.4.7) que, si a = 0 et b = 0, log(a · b) < 2 · log(a+ b).Reprenons le calcul :

Page 354: Structures de données et méthodes formelles ||

9. Files de priorité 347

l ≤ log((n+ 1)·(n′ + 1))⇒ Propriété du log

l < 2 · log(n+ n′ + 2)⇔ Notation

l < 2 · log(N + 2) (9.4.15)

Reportons ce résultat dans la formule 9.4.14 :

F(l) = 6 · l + 2⇒ Inégalité (9.4.15)

F(l) < 6 ·(2 · log(N + 2)) + 2⇔ Arithmétique

F(l) < 12 · log(N + 2) + 2

Le résultat de l’exercice 4.1.2 permet de conclure que (sous l’hypothèse où lecalcul de rayon présente un coût constant et en considérant qu’aucune des filesn’est vide) l’opération fpFus_mb est en O(logN). Dans le cas où l’une au moinsdes files est vide le coût est trivialement constant.

Calcul d’une représentation de l’opération fpAjout_fb

Le calcul de cette opération nous conduit à utiliser l’opération auxiliairefaa(m, f) (fpajoutaux_fb) qui délivre une file dans laquelle le minimier m estajouté (au sens multiensembliste) à f . La spécification de cette opération vientcompléter le type concret fb de la manière suivante :

concreteTypefb(n) = · · ·...

auxiliaryOperationSpecificationsfunction faa(m, f) ∈ mB(i)× fB(j) �→ fB(k) =g : (g ∈ fB(k) ∧ A(g) = fpFus(A′(m),A(f)))

end

Une fois cette opération disponible, il suffit, pour mettre en œuvre l’opérationeAjout_fb, de convertir au préalable la valeur à insérer en un minimier m. C’estce que nous calculons ci-dessous. Développer le calcul de la représentation de faava nous conduire à utiliser l’hypothèse d’induction suivante, qui est démontréeconjointement au développement :

Hypothèse d’induction 6 (Aug(f)). m, f ∈ mB(j)×fB(i)⇒ r(faa(m, f))−max({r(m), r(f)}) ∈ {0, 1}.

Commençons par le développement de cette opération auxiliaire.

A(faa(m, f))= Propriété caractéristique

A′(m)�A(f) (9.4.16)

Page 355: Structures de données et méthodes formelles ||

348 Structures de données et méthodes formelles

Nous procédons alors à une induction sur f en débutant par le cas f = [ ] :

A′(m)�A(f)= Hypothèse

A′(m)�A([ ])= Définition de A

A′(m)���= Propriété 3.7.2, page 104

A′(m)= Propriété 9.4.6, page 338

A([m | [ ]])

D’où la première équation gardée pour l’opération faa :

f = [ ]→faa(m, f) = [m | [ ]]

L’hypothèse d’induction est bien satisfaite : la file obtenue a le même rayon quele minimier en argument. Pour le cas inductif (f = [ ]), posons f = [t | q] avantde reprendre la formule 9.4.16 :

A′(m)�A(f)= Hypothèse

A′(m)�A([t | q])= Définition de A

A′(m)�A′(t)�A(q) (9.4.17)

Si les rayons des minimiers m et t sont égaux, le développement peut se pour-suivre par :

A′(m)�A′(t)�A(q)= Propriété caractéristique de fpFus_mb

A′(fpFus_mb(m, t))�A(q)= Définition de A

A([fpFus_mb(m, t) | q])

D’où la seconde équation gardée pour l’opération faa :

f = [t | q] →r(m) = r(t) →

faa(m, f) = [fpFus_mb(m, t) | q]

Le rayon du résultat est supérieur de 1 à ceux de m et de f : l’hypothèse d’in-duction est toujours satisfaite. Le cas r(m) > r(t) se traite en repartant de laformule 9.4.17 ci-dessus :

A′(m)�A′(t)�A(q)= Définition de A

A([m | f ])

Page 356: Structures de données et méthodes formelles ||

9. Files de priorité 349

D’où la troisième équation gardée pour l’opération faa :

f = [t | q] →r(m) > r(t) →

faa(m, f) = [m | f ]

Le rayon du résultat est égal à celui de m : l’hypothèse d’induction est toujourssatisfaite. Le cas r(m) < r(t) se traite toujours en repartant de la formule 9.4.17ci-dessus :

A′(m)�A′(t)�A(q)= Propriété 3.7.1, page 104 et propriété caractéristique de faa

A′(t)�A(faa(m, q))

Le rayon de faa(m, q) peut atteindre celui de t. Il est impossible de conclureimmédiatement. À ce stade nous pouvons affirmer que la file faa(m, q) n’estpas vide (elle contient au moins les éléments de m). Posons f ′ = faa(m, q) puis[t′ | q′] = f ′ :

A′(t)�A(faa(m, q))= Première hypothèse

A′(t)�A([t′ | q′])= Définition de A

A′(t)�A′(t′)�A(q′) (9.4.18)

Selon l’hypothèse d’induction, deux cas seulement sont à envisager : r(t′) = r(t)et r(t′) < r(t) (cf. exercice 9.4.8). Débutons par le cas r(t′) = r(t) :

A′(t)�A′(t′)�A(q′)= Propriété caractéristique de fpFus_mb

A′(fpFus_mb(t′, t))�A(q′)= Définition de A

A([fpFus_mb(t′, t) | q′])

D’où la quatrième équation gardée pour l’opération faa :

f = [t | q] →r(m) < r(t) →

let [t′ | q′] := faa(m, q) inr(t′) = r(t) →

faa(m, f) = [fpFus_mb(t′, t) | q′]end

Le rayon du résultat est supérieur de un au rayon de m et de f : l’hypothèsed’induction est satisfaite. Quant au cas r(t′) < r(t), il se traite en repartant dela formule 9.4.18 :

A′(t)�A′(t′)�A(q′)= Hypothèse et définition de A

A([t | f ′])

Page 357: Structures de données et méthodes formelles ||

350 Structures de données et méthodes formelles

D’où enfin la cinquième équation gardée pour l’opération faa :

f = [t | q] →r(m) < r(t) →

let f ′ := faa(m, q) inlet [t′ | q′] := f ′ in

r(t′) < r(t) →faa(m, f) = [t | f ′]

endend

Le rayon du résultat est égal au rayon de la file : l’hypothèse d’induction esttoujours satisfaite.

Au total, nous avons calculé la représentation suivante de l’opération faa :

function faa(m, f) ∈ mB(i)× fB(j) �→ fB(k) =if f = [ ] →[m | [ ]]

| f = [t | q] →if r(m) = r(t)→[fpFus_mb(m, t) | q]

| r(m) > r(t)→[m | f ]

| r(m) < r(t)→let f ′ := faa(m, q) in

let [t′ | q′] := f ′ inif r(t′) = r(t)→[fpFus_mb(t′, t) | q′]

| r(t′) < r(t)→[t | f ′]

fiend

endfi

fi

Nous sommes maintenant prêt à calculer une représentation pour l’opérationfpAjout_fb :

A(fpAjout_fb(v, f))= Propriété caractéristique�v��A(f)

= Propriété 9.4.7, page 338A′(〈v, [ ]〉)�A(f)

= Propriété caractéristique de faaA(faa(〈v, [ ]〉, f))

D’où la représentation suivante pour l’opération fpAjout_fb(v, f) :

function fpAjout_fb(v, f) ∈ N× fB(i)→ fB(n) = faa(〈v, [ ]〉, f)

Page 358: Structures de données et méthodes formelles ||

9. Files de priorité 351

Analyse amortie de l’opération fpAjout_fb

La similitude existant entre l’ajout d’un élément dans une file binomialeet l’ajout de 1 à un compteur binaire représenté par une liste (cf. exemplede la page 129) nous incite à penser que la complexité amortie de l’opérationfpAjout_fb(v, f) puisse être en temps constant. Nous allons tenter de confirmercette intuition en appliquant la méthode du potentiel. Pour cela, commençonspar proposer une version récurrente de T , fonction qui évalue le coût réel d’unappel. Ce coût est donné par le nombre d’appels à l’opération fpFus_mb. En-suite nous choisirons une fonction de potentiel Φ. Nous serons alors à mêmed’appliquer la formule 4.3.2, page 125, afin de calculer le coût amorti M d’unappel à l’opération fpAjout_fb(v, f).

Le coût réel d’un appel à l’opération fpAjout_fb(v, f) est donné, d’après lareprésentation calculée ci-dessus, par :

T (fpAjout_fb(v, f)) = T (faa(〈v, [ ]〉, f))

Si nous considérons que le coût « réel » d’un appel à la fonction fpFus_mbest de un, la structure de la fonction faa nous permet de fournir l’équationrécurrente suivante pour le coût « réel » T d’un appel à faa(m, f) :⎧⎪⎪⎪⎪⎨⎪⎪⎪⎪⎩

T (faa(m, [ ])) = 1

T (faa(m, [t | q])) =

⎧⎪⎪⎨⎪⎪⎩2 si r(m) = r(t)1 si r(m) > r(t){T (faa(m, q)) + 1 si r(m) < r(t) ∧ r(t′) = r(t)T (faa(m, q)) si r(m) < r(t) ∧ r(t′) < r(t)

Nous choisissons comme fonction de potentiel la fonction qui délivre la lon-gueur de la file : Φ(f) = #(f). Appliquée à faa(m, f), celle-ci s’exprime sous laforme d’une équation récurrente :⎧⎪⎪⎪⎪⎨⎪⎪⎪⎪⎩

Φ(faa(m, [ ])) = 1

Φ(faa(m, [t | q])) =

⎧⎪⎪⎨⎪⎪⎩Φ(q) + 1 si r(m) = r(t)Φ([t | q]) + 1 si r(m) > r(t){Φ(faa(m, q)) si r(m) < r(t) ∧ r(t′) = r(t)Φ(faa(m, q)) + 1 si r(m) < r(t) ∧ r(t′) < r(t)

L’équation qui fournit la complexité amortie de l’opération faa est alors (cf. for-mule 4.3.2, page 125) :

M(faa(m, f)) = T (faa(m, f)) + Φ(faa(m, f))− Φ(f) (9.4.19)

Elle se résout par induction sur la structure de f et, pour la partie inductive,par une analyse par cas. Débutons par le cas de base f = [ ] :

T (faa(m, [ ])) + Φ(faa(m, [ ]))− Φ([ ])= Définition de T et de Φ1 + 1 − 0

= Arithmétique2

Page 359: Structures de données et méthodes formelles ||

352 Structures de données et méthodes formelles

Pour la partie inductive (f = [t | q]), nous distinguons les quatre cas apparais-sant dans les définitions de T et de Φ. Nous débutons par r(m) > r(t) :

T (faa(m, [t | q])) + Φ(faa(m, [t | q]))− Φ([t | q])= Définition de T et de Φ1 + Φ([t | q]) + 1 − Φ([t | q])

= Définition de Φ et arithmétique2

Poursuivons par r(m) = r(t) :

T (faa(m, [t | q])) + Φ(faa(m, [t | q]))− Φ([t | q])= Définition de T et de Φ2 + Φ(q) + 1 − (1 + Φ(q))

= Définition de Φ et arithmétique2

Le cas r(m) < r(t) ∧ r(t′) = r(t) se traite comme suit :

T (faa(m, [t | q])) + Φ(faa(m, [t | q]))− Φ([t | q])= Définition de T et de Φ

T (faa(m, q)) + 1 + Φ(faa(m, q)) − (1 + Φ(q))= Arithmétique et définition de M

M(faa(m, q))

Enfin, le cas r(m) < r(t) ∧ r(t′) < r(t) se développe par :

T (faa(m, [t | q])) + Φ(faa(m, [t | q]))− Φ([t | q])= Définition de T et de Φ

T (faa(m, q)) + Φ(faa(m, q)) + 1 − (1 + Φ(q))= Arithmétique et définition de M

M(faa(m, q))

Au total, nous avons calculé la version récurrente suivante deM(faa(m, f)) :⎧⎨⎩M(faa(m, [ ])) = 2M(faa(m, [t | q])) = 2 si r(m) ≥ r(t)M(faa(m, [t | q])) =M(faa(m, q)) si r(m) < r(t)

dont la solution immédiate est M(faa(m, f)) = 2. La complexité amortie defaa(m, f) est donc en temps constant. Il s’en déduit :

M(fpAjout_fb(v, f)) ∈ O(1)

Nous aurions pu calculer une représentation de fpAjout_fb(v, f) à partirde l’opération de fusion fpFus_fb. Nous serions parvenu au résultat suivant :

function fpAjout_fb(v, f) ∈ N× fB(j)→ fB(i) =fpFus_fb([〈v, [ ]〉 | [ ]], f)

Cependant, la complexité amortie de cette version n’est pas en temps constant(cf. exercice 9.4.9).

Page 360: Structures de données et méthodes formelles ||

9. Files de priorité 353

Calcul d’une représentation de l’opération fpSupp_fb

Ce calcul nous conduit à l’utilisation de l’opération de fusion de files. Nousdémarrons le calcul avec comme argument [t | q] (c’est possible car la précondi-tion de fpSupp_fb(f) est équivalente à f = [ ]). Cependant, le développementdoit s’accompagner de l’hypothèse d’induction suivante, qui est utilisée et prou-vée conjointement au développement.

Hypothèse d’induction 7 (Dim(f)). Si f ∈ fB(i) alors r(f) −r(fpSupp_fb(f)) ∈ {0, 1}.

Cette hypothèse exprime que la suppression dans une file binomiale diminue lerayon de la file d’au plus 1. Débutons le calcul de l’opération fpSupp_fb :

A(fpSupp_fb([t | q]))= Propriété caractéristique de fpSupp_fb

A([t | q]) − �bMin(A([t | q]))�= Définition de A(A′(t)�A(q)) − �bMin(A([t | q]))�

= Propriété caractéristique de fpPrio_fb(A′(t)�A(q)) − �fpPrio_fb([t | q])� (9.4.20)

Posons t = 〈v, g〉 :

(A′(t)�A(q)) − �fpPrio_fb([t | q])�= Hypothèse(A′(〈v, g〉)�A(q)) − �fpPrio_fb([t | q])�

= Définition de A′(�v��A(g)�A(q)) − �fpPrio_fb([t | q])�

Effectuons une analyse par cas, selon que v = fpPrio_fb([t | q]) ou quev > fpPrio_fb([t | q]) (ce sont bien sûr les deux seuls cas possibles). Nousdébutons par v = fpPrio_fb([t | q]).

(�v��A(g)�A(q)) − �fpPrio_fb([t | q])�= Hypothèse(�v��A(g)�A(q)) − �v�

= Propriété 3.7.5, page 104(A(g)�A(q))� (�v� − �v�)

= Propriétés 3.7.4 et 3.7.2, page 104A(g)�A(q)

= Propriété caractéristique de l’opération fpFus_fbA(fpFus_fb(g, q))

D’où la première équation gardée :

let 〈v, g〉 := t infpPrio_fb([t | q]) = v →

fpSupp_fb([t | q]) = fpFus_fb(g, q)end

Page 361: Structures de données et méthodes formelles ||

354 Structures de données et méthodes formelles

Soit r([t | q]) = n. Nous avons alors r(g) = n − 1 et r(q) ≤ n − 1. D’aprèsl’hypothèse d’induction 7, r(fpFus_fb(g, q)) ∈ {n, n−1}. Après suppression, lerayon de la file binomiale diminue donc au plus de 1. L’hypothèse d’induction estsatisfaite dans ce cas. Pour le second cas, v > fpPrio_fb([t | q]), il est facilede démontrer que dans cette hypothèse fpPrio_fb([t | q]) = fpPrio_fb(q).En repartant de la formule 9.4.20 ci-dessus, nous avons :

(A′(t)�A(q)) − �fpPrio_fb([t | q])�= Propriété 3.7.5, page 104

A′(t)� (A(q) − �fpPrio_fb([t | q])�)= Propriété caractéristique de fpSupp_fb

A′(t)�A(fpSupp_fb(q))

Compte tenu de l’hypothèse d’induction 7, le rayon de fpSupp_fb(q) est infé-rieur à celui de t, nous sommes donc en mesure d’appliquer la fonction d’abs-traction A :

A′(t)�A(fpSupp_fb(q))= Définition de A

A([t | fpSupp_fb(q)])

D’où la seconde équation gardée :

let 〈v, g〉 := t infpPrio_fb([t | q]) = v →

fpSupp_fb([t | q]) = [t | fpSupp_fb(q)]end

Le résultat est bien une file binomiale dont le rayon, égal à celui de t, resteinchangé. L’hypothèse d’induction 7 est bien satisfaite. Au total, nous avonscalculé la représentation suivante de l’opération fpSupp_fb :

function fpSupp_fb([t | q]) ∈ fB(i) �� fB(j) =pre

i > 0then

let 〈v, g〉, p := t, fpPrio_fb([t | q]) inif v = p →

fpFus_fb(g, q)| v > p →[t | fpSupp_fb(q)]

fiend

end

L’hypothèse d’induction 7 permet en outre d’affirmer que j ∈ {i − 1, i}.Quelle est la complexité au pire de cette version de l’opération fpSupp_fb ?Tentons de répondre à cette question. Soit S(l) la fonction qui délivre le nombremaximum de conditions de conditionnelles évaluées pour une file f de longueurl et de poids n. S(l) satisfait l’équation récurrente suivante dans laquelle P et F

Page 362: Structures de données et méthodes formelles ||

9. Files de priorité 355

sont les fonctions 9.4.10, page 342, et 9.4.14, page 346, associées respectivementà la recherche de l’élément prioritaire et à la fusion :

S(1) = P(1)+ Recherche de l’élément prioritaire1 Garde de la conditionnelle

S(l) = P(l)+ Recherche de l’élément prioritaire1+ Garde de la conditionnellemax({ Recherche de la pire des branches de la conditionnelle

F(l − 1 + (l − 1)), Première branche : fusionS(l − 1), Seconde branche : appel récursif

})

Il est a priori difficile de déterminer la pire solution. Celle pour laquelle l’élémentprioritaire est en tête de file ? Ou celle qui parcourt toute la file ? Dans le premiercas, après le parcours initial, la fusion se fait au pire sur deux listes de longueurl − 1, dans le second cas la fusion se fait sur deux listes vides mais la recherchede l’élément prioritaire est réalisée plusieurs fois. Le calcul montre que dans lepremier cas nous obtenons la solution suivante : S(l) = 14 · l − 10 et dans lesecond S(l) = l2+ l. C’est donc cette seconde solution qu’il faut retenir pour uncalcul de complexité au pire. Nous en déduisons immédiatement que l’opérationfpSupp_fb calculée ci-dessus a une complexité au pire en O(l2), soit d’après lapropriété 9.4.4, page 334, en O(log2(n)).

Est-il possible d’améliorer cette situation ? Nous avons ci-dessus fourni unindice en constatant que, dans le cas où la valeur prioritaire n’est pas situéeen tête de liste, la recherche de cette valeur est réalisée à chaque invocation del’opération. Il est bien entendu préférable de n’effectuer cette recherche qu’uneseule fois. Pour cela, il faut définir une opération auxiliaire fpSuppAux_fb(f, w)dans laquelle f est la file considérée et w est la valeur prioritaire, supposéeconnue. Plus précisément, cette opération se spécifie comme suit dans la rubriqueauxiliaryOperationSpecifications :

concreteType fb(n) = · · ·...

auxiliaryOperationSpecificationsfunction fpSuppAux_fb(f, w) ∈ fB(i)× N �� fB(j) =pre

w = bMin(A(f)) ∧ i > 0then

q : (q ∈ fB(j) ∧ A(q) = fpSupp(A(f)))end

end

Calculons une représentation de cette opération. À l’instar de fpSupp_fbnous pouvons considérer que f = [t | q] puisque la file n’est pas vide.

A(fpSuppAux_fb([t | q], w))= Propriété caractéristique de fpSupp_fb

Page 363: Structures de données et méthodes formelles ||

356 Structures de données et méthodes formelles

(A′(t)�A(q)) − �bMin(A([t | q]))�= Spécification de fpSuppAux_fb(A′(t)�A(q)) − �w� (9.4.21)

Posons t = 〈v, g〉. Procédons à une analyse par cas selon que �w� ! A′(t) ounon. Si �w� ! A′(t), alors v = w. Dans cette hypothèse nous avons :

(A′(t)�A(q)) − �w�= Hypothèse(A′(〈v, g〉)�A(q)) − �w�

= Définition de A′(�v��A(g)�A(q)) − �w�

= Propriétés 3.7.5, 3.7.4 et 3.7.2, page 104A(g)�A(q)

= Propriété caractéristique de l’opération fpFus_fbA(fpFus_fb(g, q))

Nous obtenons la première équation gardée :

let 〈v, g〉 := t inv = w →

fpSuppAux_fb([t | q], w) = fpFus_fb(g, q)end

Le cas v = w a comme conséquence v�−A(q). Nous repartons de la formule 9.4.21 :

(A′(t)�A(q)) − �w�= Propriété 3.7.5, page 104

A′(t)� (A(q) − �w�)= Propriété caractéristique de fpSuppAux_fb

A′(t)�A(fpSuppAux_fb(q, w))= Définition de A

A([t | fpSuppAux_fb(q, w)])

Ce calcul nous fournit la seconde équation gardée :

let 〈v, g〉 := t inv = w →

fpSuppAux_fb([t | q], w) = [t | fpSuppAux_fb(q, w)]end

Au total, nous avons calculé la représentation suivante de l’opérationfpSuppAux_fb :

Page 364: Structures de données et méthodes formelles ||

9. Files de priorité 357

function fpSuppAux_fb([t | q], w) ∈ fB(i)× N �� fB(j) =pre

w = bMin(A(f))then

let 〈v, g〉 := t inif v = w →

fpFus_fb(g, q)| v = w →[t | fpSuppAux_fb(q, w)]

fiend

end

Cette version nous apprend que, connaissant la valeur prioritaire à supprimer, sicette valeur est en tête de file, alors le résultat est la fusion de la queue de file etde la file qui reste quand on écrête le minimier de tête, sinon, le résultat est unefile constituée du minimier de tête et de la file obtenue en supprimant la valeurprioritaire de la queue de file.

Préoccupons-nous à présent d’évaluer la complexité au pire de cette opéra-tion. Soit S ′(l) la fonction qui délivre le nombre de conditions de conditionnellesévaluées pour une file f de longueur l et de poids n. S ′(l) satisfait l’équationrécurrente suivante :

S ′(1) =1+ Garde de la conditionnelleF(0) Fusion de deux files vides

S ′(l) = 1+ Garde de la conditionnellemax({ Recherche de la pire des branches de la conditionnelle

F(l − 1 + (l − 1)), Première branche : fusionS ′(l − 1), Seconde branche : appel récursif

})

Par un calcul et des hypothèses similaires à ceux effectués pour l’opérationfpSupp_fb, il est facile de montrer que la solution la plus coûteuse est :

S ′(l) = 12 · l − 9 (9.4.22)

Cette formule va nous être utile pour l’évaluation de la complexité de la nouvelleversion de fpSupp_fb. Nous pouvons à présent reprendre le calcul de l’opérationfpSupp_fb :

A(fpSupp_fb(f))= Spécification de fpSupp_fb

fpSupp(A(f))= Spécification de fpSuppAux_fb

A(fpSuppAux_fb(f, bMin(A(f))))= Propriété caractéristique de fpPrio_fb

A(fpSuppAux_fb(f, fpPrio_fb(f)))

Page 365: Structures de données et méthodes formelles ||

358 Structures de données et méthodes formelles

D’où la nouvelle version de l’opération fpSupp_fb :

function fpSupp_fb(f) ∈ fB(i) �� fB(j) =pre

i > 0then

fpSuppAux_fb(f, fprio_fb(f))end

Cette fois, la recherche de la valeur prioritaire n’est effectuée qu’une seule fois.La complexité devrait s’en trouver améliorée : soit S(l) la fonction qui délivrele nombre maximum de conditions évaluées lors de la suppression de la valeurprioritaire dans une file f de longueur l et de poids n. S(l) se définit par :

S(l) = P(l)+ Recherche de l’élément prioritaire (9.4.10)S ′(l) Opération auxiliaire (9.4.22)

Soit, sous forme close, S(l) = 14 · l−10. En utilisant la propriété 9.4.4, page 334,nous obtenons S(l) < 14 · log(n+1)−10. Sous l’hypothèse que le calcul du rayonest « gratuit », le coût au pire de cette version de l’opération est cette fois enO(log n).

9.4.5 Renforcement du support par décompositiondu rayon

Revenons sur le problème de l’évaluation de la fonction rayon évoquée dansla représentation de la fonction fpFus_fb. Lors de l’évaluation de la complexitéde cette opération, nous avons fait l’hypothèse que le calcul de r(f) présente uncoût négligeable. À l’évidence ce n’est pas le cas. Nous avons déjà eu l’occasiond’appliquer à ce type de problème la technique du renforcement de support pardécomposition (cf. sections 1.10 et 2.4). Celle-ci consiste à échanger du tempscontre de la place. Plus précisément, il s’agit de modifier légèrement la structurede données de façon à introduire dans chaque nœud un champ (appelons-le régalement) représentant la valeur du rayon pour le nœud considéré et à exploitercette valeur en consultant directement le champ en question. La technique exigeégalement de modifier les opérations de façon à mettre à jour ou à consulterle nouveau champ. Ce raffinement peut sans danger être réalisé directement demanière empirique. Le support mB devient alors (les ajouts sont encadrés) :

i ∈ N ∧ f ∈ fBC(i) ∧ a ∈ N ∧ a ≤ bMin(A′(f)) ∧r ∈ N1 ∧ r = r(f) + 1

⇔〈 a �→ r , f〉 ∈ mB(i+ 1)

Parmi les opérations qui demandent à être modifiées, il y a fpFus_fb que nousébauchons ici :

Page 366: Structures de données et méthodes formelles ||

9. Files de priorité 359

Application des files de priorité : le codage d’Huffman

Compresser un texte consiste à exploiter la redondance qu’il recèle afinde lui faire occuper moins de place. Une technique de compression consisteà coder chacun des caractères du vocabulaire sur une chaîne de bits delongueur variable, contrairement au codage ascii où chaque caractère estcodé par 8 bits. Considérons le texte suivant : t = elle�aime�le�miel.Ce texte s’exprime sur le vocabulaire V = {e,l,�,a,i,m}. En ascii toccupe 136 bits. Un code est dit préfixe si aucun de ses caractères n’estcodé par une chaîne de bits qui serait le début du codage d’un autre ca-ractère, au contraire de 110 et 11011. Un code préfixe est optimal pourt s’il n’existe pas d’autres codages offrant une meilleure compression det. Le codage d’Huffman fournit un code préfixe optimal. De plus, il pré-sente, pour ce qui nous concerne, un double intérêt puisque la structurede données qui aboutit à l’arbre de codage est une file de priorité de tries(sur 0/1).

1

a

2

i

2

m

3

4

l

5

e

2

m

3

a i

3

4

l

5

e

3

4

l

5

m •

a i

5

e

5

m •

a i

5

e

7

� l

7

� l

10

m •

a i

e

17

�0

l1

0•

m0

a0

i1

1

0e1

1

L’algorithme d’Huffman débute avec une file de priorité dans laquellechaque élément du vocabulaire est présent avec sa fréquence dans le texte ten guise de priorité (schéma en haut à gauche). L’étape suivante regroupeles deux éléments prioritaires en un arbre binaire ayant comme prioritéla somme des priorités initiales : les lettres a et i sont regroupées dansun arbre-trie de priorité 3. Le processus se répète jusqu’à obtention d’unefile réduite à un seul élément qui est l’arbre de codage recherché. Il suffitalors d’étiqueter chaque branche pour doter chaque feuille d’un code sur1/0. Par exemple, le code de i est 1011. Le codage du texte initial se faitalors sur 55 bits (au lieu de 136).

Historiquement, D. Huffman a été initié à la théorie de l’informationau mit au début des années 1950, en tant que doctorant, par C. Shannonet R.M. Fano. En 1952, ce dernier a présenté un algorithme de codage nonoptimal que D. Huffman s’est empressé d’améliorer sous la forme qu’onlui connaît aujourd’hui (cf. [65, 63, 74]).

Page 367: Structures de données et méthodes formelles ||

360 Structures de données et méthodes formelles

function fpFus_fb(f, f ′) ∈ fB(j)× fB(k)→ fB(i) =if f = [ ] →

f ′

| f = [t | q] →if f ′ = [ ]→

f| f ′ = [t′ | q′] →

let 〈v �→ r, g〉, 〈v′ �→ r′, g′〉 := t, t′ in

if r > r′ →let [t′′ | q′′] := fpFus_fb(q, f ′) in

let 〈v′′ �→ r′′, g′′〉 := t′′ in

if r > r′′ →...

La fusion augmente de un le rayon du résultat. Il suffit donc, lors de la créationdu nœud racine, d’associer l’ancien rayon plus un à la valeur à la racine. Rap-pelons que la fusion de minimiers considère deux minimiers de même rayon :r = r′. L’opération fpFus_fb ne modifie pas directement le champ r. Le paride disposer un rayon « gratuit » est donc gagné : les coûts les pires obtenusprécédemment sont confirmés, ils sont tous en O(log(n)).

9.4.6 Conclusion et remarques bibliographiques

Les files binomiales ont été découvertes par J. Vuillemin [114, 116]. Différentesreprésentations et propriétés ont été étudiées par M.R. Brown [19], y compris desversions non fonctionnelles. Dans [73], D.J. King effectue la présentation d’unemise en œuvre fonctionnelle incluant l’opération (non étudiée ici) de décrémen-tation d’une valeur donnée de la file. Enfin, dans [53], R. Hinze décrit une miseen œuvre en Haskell. Sur le site [118], M. Woo présente un arbre généalogiquedes files de priorité et montre que les files binomiales ont inspiré plusieurs autresreprésentations telles que les arbres de Fibonacci ou encore les files maigres etépaisses (« thin and thick ») de H. Kaplan et R.E. Tarjan.

Dans [116], J. Vuillemin décrit une autre structure de données concrète per-mettant la fusion de files de priorité : les pagodes. Cette structure n’est pasfonctionnelle. Elle n’est donc pas étudiée ici.

Exercices

Exercice 9.4.1 Quel serait l’inconvénient d’utiliser des listes triées par ordre croissant pourreprésenter les files binomiales ? Justifier votre réponse.

Exercice 9.4.2 Spécifier puis calculer les trois représentations naïves des files de priorité : partableau, par listes non triées puis triées.

Exercice 9.4.3 Démontrer les propriétés du tableau 9.1, page 334.

Page 368: Structures de données et méthodes formelles ||

9. Files de priorité 361

Exercice 9.4.4 Démontrer que dans un arbre binomial de rayon r, le nombre de nœuds

présents au niveau k est donné par la formule(r − 1k

)(cf. page 335).

Exercice 9.4.5 Démontrer les deux propriétés 9.4.6 et 9.4.7, page 338.

Exercice 9.4.6 Effectuer le calcul de l’opération fpPrio_mb.

Exercice 9.4.7 Le calcul de complexité de l’opération fpFus_fb nous a conduit à utiliser lapropriété suivante : soit a et b deux réels strictement positifs, alorslog(a.b) < 2 · log(a+ b).

Démontrer cette propriété. Suggestion : le log est une fonction concave. Utiliser une propriétédes fonctions concaves.

Exercice 9.4.8 Lors du calcul de la représentation de fpAjout_fb, nous avons supposé que,sous les hypothèses f = [t | q], [t′ | q′] = faa(m, q) et r(m) < r(t), seuls deux cas sont àenvisager : r(t′) < r(t) et r(t′) = r(t). Démontrer que le cas r(t′) > r(t) ne peut survenir.

Exercice 9.4.9 Calculer une représentation de l’opération fpAjout_fb sans utiliser d’opéra-tion auxiliaire, à partir de l’opération de fusion fpFus_fb. Effectuer une analyse amortie decette représentation.

Exercice 9.4.10 La spécification des files de priorité fpabst de la figure 9.1, page 329, estneutre vis-à-vis de la politique de service quand plusieurs clients sont candidats à être servis(les clients ne sont pas discernables). Modifier la spécification de façon à adopter une politique« premier entré, premier sorti » pour les clients de même priorité. En adoptant le supportconcret de votre choix, fournir une spécification concrète et calculer la représentation desopérations. Calculer leur complexité au pire.

Exercice 9.4.11 Mettre en œuvre les files de priorité en utilisant les arbres de Braun (cf. sec-tion 10.4, page 378).

Exercice 9.4.12 (Files de priorité de trous fusionnables) Dans les structures de donnéestraditionnelles (ensembles, files, etc.) l’insertion d’un nouvel élément n’a pas d’influence surl’existence ou les propriétés des éléments déjà présents. Ce caractère d’indépendance n’est pastoujours vérifié. Considérons en effet le cas d’une mémoire segmentée débutant à l’adresse 1et de taille indéterminée pour laquelle on répertorie les emplacements libres (trous) tel que lasuppression d’un emplacement libre (l’acquisition d’un segment de mémoire par le système)porte sur le plus grand élément. Dans une telle structure de données, l’adjonction d’un nouvelintervalle peut avoir des conséquences sur les trous 2 existants puisqu’elle peut entraîner desfusions.

1. Proposer une spécification du type abstrait « mémoire à trous fusionnables ».2. Mettre en œuvre cette spécification sur la base d’un support représenté par une structure

d’arbre binaire qui est un abr sur l’indice de début des trous et un maximier sur lalongueur des trous.

9.5 Méthodes autoadaptatives : les minimiersobliques (skew heaps)

La mise en œuvre des files de priorité fusionnables par minimiers obliques estune solution autoadaptative : aucun équilibre explicite n’est recherché. Malgré

2. Par convention, nous réservons le terme de trou aux emplacements disponibles dansla structure de données et celui d’intervalle aux éléments à introduire dans la structure dedonnées.

Page 369: Structures de données et méthodes formelles ||

362 Structures de données et méthodes formelles

cela l’heuristique utilisée garantit une bonne complexité amortie de toutes lesopérations présentes dans le type abstrait.

Dans cette mise en œuvre, toutes les opérations se fondent sur une opérationde base : la fusion. On y exploite la propriété des minimiers qui affirme qu’échan-ger les deux sous-arbres d’un minimier binaire préserve sa nature de minimier.La fusion se faisant entre branches droites, l’heuristique de la fusion tente doncd’obtenir une branche droite aussi courte que possible. Et, bien qu’un minimieroblique puisse être arbitrairement déséquilibré 3, l’objectif est atteint ainsi quele montre l’analyse amortie développée à la section 9.5.5.

Un minimier oblique est un minimier sans point simple à droite. Dans unminimier oblique, il n’existe donc pas de nœud qui aurait un fils droit mais pasde fils gauche.

1

6

7

9

8

2

5

6 8

3

4

1

7

9 8

2

5

6 8

3

4

(1) (2)

Dans le schéma ci-dessus, (1) est un minimier oblique tandis que (2) ne l’estpas : il possède un point simple à droite (désigné par la flèche). Cette formede déséquilibre en faveur de la gauche n’interdit cependant pas à un minimieroblique d’être déséquilibré en faveur de la droite, que ce soit en poids ou en rayonainsi que le montre l’arbre (1) ci-dessus dont le sous-arbre droit a un poids (resp.un rayon) de 6 (resp. de 3) alors que le sous-arbre gauche a un poids (resp. unrayon) de 3 (resp. de 2).

9.5.1 Définition du support concret

Nous définissons formellement le support mo du type concret mo de la ma-nière suivante :

1) 〈〉 ∈ mo2) r ∈ N ⇒ 〈〈〉, r, 〈〉 〉 ∈ mo3) g ∈ mo− {〈〉} ∧ d ∈ mo ∧ r ∈ N ∧ r = bMin(A(〈g, r, d〉))

⇒〈g, r, d〉 ∈ mo

La clause 2) précise qu’une feuille est un minimier oblique. La clause 3) utilisela fonction d’abstraction A afin de préciser que la racine d’un minimier obliqueest un représentant du plus petit élément du sac mis en œuvre par le minimier〈g, r, d〉. Par ailleurs, cette clause exclut les points simples à droite en interdisant,pour cette clause, qu’un sous-arbre gauche soit vide.

3. Ou presque comme nous le verrons ci-dessous.

Page 370: Structures de données et méthodes formelles ||

9. Files de priorité 363

9.5.2 Définition de la fonction d’abstraction

La fonction d’abstraction délivre le sac représenté par le minimier oblique.Elle s’obtient par induction structurelle sur l’argument ; cependant, les clauses2) et 3) du support conduisent à la même expression :

function A(f) ∈ mo� fpAbst =if f = 〈〉 →��

| f = 〈g, r, d〉 →A(g)� �r��A(d)

fi

La fonction A est totale, surjective mais pas injective : toute file de priorité peutêtre représentée par un minimier oblique mais, pour une file donnée, il existe engénéral plusieurs représentations possibles.

9.5.3 Spécification des opérations concrètes

Afin de bien distinguer les deux fonctionnalités de la fusion (en tant qu’opé-ration du type abstrait d’une part et en tant qu’outil pour représenter les autresopérations d’autre part), nous introduisons l’opération auxiliaire fus. Comptetenu de son rôle central, fus est la première opération à calculer. L’ensembledes informations sur la spécification du type mo se retrouve à la figure 9.6, pagesuivante.

9.5.4 Calcul d’une représentation des opérations concrètes

Intuitivement, ajouter un élément dans une file représentée par un mini-mier oblique f (opération fpAjout_mo) se fait en érigeant l’élément en mini-mier oblique avant d’effectuer une fusion avec f . Supprimer l’élément prioritaired’une file représentée par un minimier oblique (opération fpSupp_mo) se faiten supprimant la racine puis en fusionnant les deux sous-arbres restants. Cesdeux opérations s’appuient donc sur l’opération de fusion fus dont nous allonsà présent calculer une représentation.

Calcul d’une représentation de l’opération fus

La principale difficulté dans ce calcul est de choisir parmi les nombreusespossibilités qui s’offrent à nous. Ce choix est dicté en priorité par le fait que lerésultat de la fusion est un minimier oblique.

A(fus(f, f ′))= Propriété caractéristique de fus

A(f)�A(f ′) (9.5.1)

À ce stade, nous procédons à une induction primaire sur f puis à une induc-tion secondaire sur f ′. Considérons tout d’abord le cas f = 〈〉 :

Page 371: Structures de données et méthodes formelles ||

364 Structures de données et méthodes formelles

concreteTypemo = (mo, (fpV ide_mo, fpAjout_mo, fpSupp_mo, fpFus_mo),(fpPrio_mo, fpEstV ide_mo))

uses bool,Nrefines fpabst

support1) 〈〉 ∈ mo2) r ∈ N ⇒ 〈〈〉, r, 〈〉 〉 ∈ mo3) g ∈ mo− {〈〉} ∧ d ∈ mo ∧ r ∈ N ∧ r = bMin(A(〈g, r, d〉))

⇒〈g, r, d〉 ∈ mo

abstractionFunctionfunction A(f) ∈ mo� fpAbst = . . .

operationSpecificationsfunction fpV ide_mo() ∈ mo = q : (q ∈ mo ∧ A(q) = fpV ide())

; function fpAjout_mo(v, f) ∈ N×mo→mo =q : (q ∈ mo ∧ A(q) = fpAjout(v,A(f)))

; function fpSupp_mo(f) ∈ mo ��mo =pre

A(f) = ��then

q : (q ∈ mo ∧ A(q) = fpSupp(A(f)))end

; function fpFus_mo(f, f ′) ∈ mo×mo�mo =q : (q ∈ mo ∧ A(q) = fpFus(A(f),A(f ′)))

; function fpPrio_mo(f) ∈ mo �� N = . . .; function fpEstV ide_mo(f) ∈ mo� bool = fpEstV ide(A(f))auxiliaryOperationSpecifications

function fus(f, f ′) ∈ mo×mo�mo =q : (q ∈ mo ∧ A(q) = fpFus(A(f),A(f ′)))

end

Figure 9.6 – Spécification du type concret « minimier oblique ».Un minimier oblique est un minimier particulier. Les opérations nevéhiculent aucune contrainte de spécification, seul le souci d’atteindreune solution efficace (en analyse amortie) guide le calcul.

A(f)�A(f ′)= Hypothèse

A(〈〉)�A(f ′)= Définition de A et propriétés 3.7.1 et 3.7.2, page 104

A(f ′)

D’où la première équation gardée pour l’opération fus :

f = 〈〉 →fus(f, f ′) = f ′

Page 372: Structures de données et méthodes formelles ||

9. Files de priorité 365

Pour la partie inductive, nous posons f = 〈g, r, d〉 et procédons à l’inductionsecondaire sur f ′. Le cas de base (f ′ = 〈〉) se développe comme ci-dessus etconduit à l’équation gardée :

f = 〈〉 →f ′ = 〈〉 →

fus(f, f ′) = f

Pour la partie inductive secondaire, nous posons f ′ = 〈g′, r′, d′〉 et repartons dela formule 9.5.1 :

A(f)�A(f ′)= Hypothèses

A(〈g, r, d〉)�A(〈g′, r′, d′〉)= Définition de A

A(g)� �r��A(d)�A(g′)� �r′��A(d′)

À ce stade, nous devons procéder à une analyse par cas selon que r ≤ r′ ou quer′ < r. Considérons tout d’abord le premier cas. La commutativité de l’opérateur� (propriété 3.7.1, page 104) permet de réorganiser les termes à notre convenancesous réserve que le résultat soit un minimier oblique. Cependant, obtenir unminimier n’est garanti que si A(g′)� �r′��A(d′) est regroupé en A(f ′) :

A(g)� �r��A(d)�A(g′)� �r′��A(d′)= Définition de A

A(g)� �r��A(d)�A(f ′)

Il subsiste alors trente-six solutions. Douze d’entre elles sont des solutionsdu type �r� � (. . .), où �r� apparaît au début de l’expression. À l’évidence, cessolutions conduisent à des minimiers qui ne sont pas obliques (le sous-arbregauche est vide alors que le sous-arbre droit ne l’est pas). Elles sont à rejeter.Douze autres solutions sont issues d’expressions de la forme (. . .)��r�. Il est facilede montrer que, construites à partir d’un ajout ou d’une fusion, ces solutionsproduisent des arbres filiformes à gauche (cf. exercice 9.5.5). Elles ne peuventconduire à des opérations performantes et doivent donc être écartées.

Tableau 9.3 – Les 12 parenthésages possibles.La commutativité et l’associativité de l’opérateur � permettent deprendre en considération 12 variantes de l’expression initiale.

1 A(g)� �r� � (A(d)�A(f ′)) 2 (A(g)�A(d)) � �r��A(f ′)3 A(g)� �r� � (A(f ′)�A(d)) 4 (A(g)�A(f ′)) � �r��A(d)5 A(d)� �r� � (A(g)�A(f ′)) 6 (A(d)�A(g)) � �r��A(f ′)7 A(d)� �r� � (A(f ′)�A(g)) 8 (A(d)�A(f ′)) � �r��A(g)9 A(f ′)� �r� � (A(g)�A(d)) 10 (A(f ′)�A(g)) � �r��A(d)11 A(f ′)� �r� � (A(d)�A(g)) 12 (A(f ′)�A(d)) � �r��A(g)

Restent enfin les douze solutions qui sont répertoriées dans le tableau 9.3 ci-dessus. Six d’entre elles, les solutions 1, 2, 3, 5, 6 et 7, peuvent donner naissance

Page 373: Structures de données et méthodes formelles ||

366 Structures de données et méthodes formelles

à des minimiers qui ne sont pas obliques. En effet, pour ces six cas, le sous-arbre gauche peut être vide sans que le sous-arbre droit ne le soit. Restent lessolutions 4, 8, 9, 10, 11 et 12. Les solutions 4 et 10 sont à l’origine de minimiersfiliformes (cf. exercice 9.5.6). Il reste à considérer les quatre solutions 8, 9, 11 et12. Ces solutions produisent en général des minimiers obliques non dégénérés.Nous retenons la solution 8 pour laquelle nous achevons le développement avantd’effectuer l’analyse amortie. Le cas des trois solutions restantes est laissé enexercice (cf. exercice 9.5.7).

A(g)� �r��A(d)�A(f ′)= Propriété 3.7.1, page 104(A(d)�A(f ′)) � �r��A(g)

= Spécification de fpFus(fpFus(A(d),A(f ′)) � �r��A(g)

= Spécification de fusA(fus(d, f ′))� �r��A(g)

= Définition de AA(〈fus(d, f ′), r, g〉)

Nous avons donc calculé l’équation gardée suivante :

let 〈g, r, d〉, 〈g′, r′, d′〉 := f, f ′ inr ≤ r′ →

fus(f, f ′) = 〈fus(d, f ′), r, g〉end

Une solution au second cas (r′ < r) s’obtient par des considérations de sy-métrie. Au total, nous avons calculé la représentation suivante de l’opérationfus :

function fus(f, f ′) ∈ mo×mo→mo =if f = 〈〉 →

f ′

| f = 〈〉 →if f ′ = 〈〉 →

f| f ′ = 〈〉 →

let 〈g, r, d〉, 〈g′, r′, d′〉 := f, f ′ inif r ≤ r′ →

〈fus(d, f ′), r, g〉| r′ < r →

〈fus(d′, f), r′, g′〉fi

endfi

fi

Page 374: Structures de données et méthodes formelles ||

9. Files de priorité 367

La complexité au pire classique de cette opération est en O(n) si n est la sommedes poids de f et de f ′. En effet, pour un minimier oblique de poids m, lenombre d’éléments présents sur la branche droite est inférieur ou égal à �m2 �(cf. exercice 9.5.2). Pour ce qui concerne la complexité amortie, nous y consacronsla section 9.5.5 ci-dessous.

Calcul d’une représentation de l’opération fpAjout_mo

Le calcul ci-dessous valide l’intuition que l’adjonction peut s’obtenir à partird’une fusion :

A(fpAjout_mo(v, f))= Propriété caractéristique

A(f)� �v�= Propriétés 3.7.2 et 3.7.1, page 104

A(f) � ��� �v����= Définition de A

A(f) � A(〈〉)� �v��A(〈〉)= Définition de A

A(f)�A(〈〈〉, v, 〈〉〉)= Propriété caractéristique de fus

A(fus(f, 〈〈〉, v, 〈〉〉))

Nous en déduisons la version suivante de la représentation de l’opérationfpAjout_mo :

function fpAjout_mo(v, f) ∈ N×mo→mo = fus(f, 〈〈〉, v, 〈〉〉)

En terme de complexité classique, cet algorithme est en O(n) si n est le poidsde l’arbre f .

Calcul d’une représentation de l’opération fpSupp_mo

Nous savons déjà, d’après la définition du support, que dans un minimier nonvide f de racine r, r = bMin(f). Nous savons par ailleurs, d’après la préconditionde l’opération, que la file de priorité considérée ne peut être vide et donc que leminimier f qui le représente est différent de 〈〉. Posons f = 〈g, r, d〉. Le calcul del’opération fpSupp_mo s’en déduit :

A(fpSupp_mo(f))= Propriété caractéristique

A(f) − �bMin(f)�= Hypothèse

A(〈g, r, d〉) − �bMin(f)�= Définition du support

A(〈g, r, d〉) − �r�= Définition de A(A(g)� �r��A(d)) − �r�

Page 375: Structures de données et méthodes formelles ||

368 Structures de données et méthodes formelles

= Propriété 3.7.5, page 104(A(g)�A(d)) � (�r� − �r�)

= Propriété 3.7.4, page 104(A(g)�A(d)) � ��

= Propriété 3.7.4, page 104A(g)�A(d)

= Propriété caractéristique de fusA(fus(g, d))

En admettant que la précondition abstraite se traduise par f = 〈〉, nous endéduisons la version suivante de la représentation de l’opération fpSupp_mo :

function fpSupp_mo(f) ∈ mo ��mo =pre

f = 〈〉then

let 〈g, r, d〉 := f infus(g, d)

endend

En terme de complexité classique, si n est le poids de l’arbre f , cet algorithmeest également en O(n).

L’opération fpFus_mo est identique à fus. Pour les autres opérations, lecalcul de la représentation est simple, il est laissé en exercice.

9.5.5 Analyse amortie de l’opération fus

Si nous en restions là en ce qui concerne la complexité, cette structure dedonnées ne présenterait que peu d’intérêt. Elle serait, sur de nombreux points,de moins bonne qualité que la représentation par files binomiales. Mais outre lasimplicité de sa mise en œuvre, son avantage réside dans une propriété que nousn’avons fait qu’évoquer : la complexité amortie de l’opération de fusion fus (etpar ricochet celle des opérations de mise à jour), qui est en O(log n) si n est lasomme des poids des arbres en arguments.

Nous proposons un « programme de démonstration » qui se présente en troispoints principaux :1. définition de la fonction de potentiel Φ,2. recherche d’une forme récurrente pour la fonction M(fus(f, f ′)) qui four-

nit le coût amorti de la fusion,3. majoration de cette fonction par une fonction logarithmique.

Notation. Si f est un minimier oblique, nous appelons f le poids de f plus 1 :f = w(f) + 1.

Une conséquence de cette définition est que la fonction telle que a ∈ mo→N1 peut être définie de la manière suivante :

Page 376: Structures de données et méthodes formelles ||

9. Files de priorité 369

Notation Définition Condition〈 〉 1〈g, r, d〉 g + d g ∈ mo ∧ d ∈ mo ∧ r ∈ N

Notons immédiatement la propriété suivante (non démontrée) : fus(a, b) = a+ b.

Selon la définition 4.3.2, page 125, le coût amorti M(fus(f, f ′)) de l’opéra-tion de fusion est donné par :

M(fus(f, f ′)) = T (fus(f, f ′)) + Φ(fus(f, f ′))− Φ((f, f ′))

où T (fus(f, f ′)) est le coût « réel » d’une opération de fusion, Φ la fonction depotentiel à valeurs dans R+ qui est telle que Φ(fus(f, f ′)) est le potentiel dela structure de données obtenue par la fusion et Φ((f, f ′)) le potentiel avant lafusion. Le potentiel du couple (f, f ′) est bien entendu égal à la somme du po-tentiel de chaque arbre : Φ((f, f ′)) = Φ(f) + Φ(f ′). Nous définissons la fonctionT comme la fonction qui délivre le nombre d’appels à la fonction fus. La repré-sentation calculée ci-dessus de la fonction fus permet de fournir une définitionformelle de T par l’équation récurrente suivante :⎧⎪⎪⎨⎪⎪⎩

T (fus(〈〉, f ′)) = 1T (fus(f, 〈〉)) = 1T (fus(〈g, r, d〉, 〈g′, r′, d′〉)) = 1 +

{T (fus(d, f ′)) Si r ≤ r′

T (fus(d′, f)) Si r′ < r

Quant à la fonction de potentiel Φ(f) retenue, elle dénombre les arbres p-déséquilibrés (déséquilibrés du point de vue du poids) en faveur de la droite. Ellese définit par :{

Φ(〈〉) = 0Φ(〈g, r, d〉) = Φ(g) + ϕ(g, d) + Φ(d)

(9.5.2)

où la fonction ϕ se définit par 4 :

ϕ(a, b) ∈ mo×mo→ R+

ϕ(a, b) =

{1 si a < b

0 si a ≥ b(9.5.3)

Nous sommes prêt à aborder la seconde étape de la démonstration : la misesous forme d’équation récurrente deM(fus(f, f ′)). En utilisant la représentationde l’opération fus calculée ci-dessus, nous procédons à une induction sur lastructure des arguments. Pour le cas de base f = 〈〉 nous avons :

M(fus(f, f ′))= Hypothèse

M(fus(〈〉, f ′))= Définition de M

4. On montre (cf. [101]) que cette définition est telle que ϕ(a, b) = max({�log( 2 · ba+b

)�, 0}).

Page 377: Structures de données et méthodes formelles ||

370 Structures de données et méthodes formelles

T (fus(〈〉, f ′)) + Φ(fus(〈〉, f ′))− Φ(〈〉)− Φ(f ′)= Définition de T et représentation de fus1 + Φ(f ′)− Φ(〈〉)− Φ(f ′)

= Définition de Φ1 + Φ(f ′)− 0− Φ(f ′)

= Calcul sur R1

Le cas f ′ = 〈〉 se développe de la même façon et fournit le même résultat. Pourle cas inductif, f = 〈〉 et f ′ = 〈〉, nous posons f = 〈g, r, d〉 et f ′ = 〈g′, r′, d′〉.

M(fus(f, f ′))= Hypothèse

M(fus(〈g, r, d〉, 〈g′, r′, d′〉))= Définition de M

T (fus(〈g, r, d〉, 〈g′, r′, d′〉)) + Φ(fus(〈g, r, d〉, 〈g′, r′, d′〉))−Φ(f)− Φ(f ′)

Nous devons procéder à une analyse par cas selon que r ≤ r′ ou que r′ < r. Lesdeux cas étant symétriques, seul le premier cas est développé.

T (fus(〈g, r, d〉, 〈g′, r′, d′〉)) + Φ(fus(〈g, r, d〉, 〈g′, r′, d′〉))−Φ(f)− Φ(f ′)

= Définition de T1 + T (fus(d, f ′)) + Φ(fus(〈g, r, d〉, 〈g′, r′, d′〉))− Φ(f)− Φ(f ′)

= Représentation de fus, hypothèse (r ≤ r′)1 + T (fus(d, f ′)) + Φ(〈fus(d, f ′), r, g〉)− Φ(f)− Φ(f ′)

= Définition de Φ1 + T (fus(d, f ′)) + Φ(fus(d, f ′)) + ϕ(fus(d, f ′), g) + Φ(g)

−Φ(g)− ϕ(g, d)− Φ(d)− Φ(f ′)= Calcul sur R+ et définition de M1 +M(fus(d, f ′)) + ϕ(fus(d, f ′), g)− ϕ(g, d)

Nous pouvons exploiter la symétrie et proposer la formulation récurrente suivantede M (la troisième équation fait l’hypothèse que f = 〈〉 et f ′ = 〈〉) :⎧⎪⎪⎨⎪⎪⎩M(fus(〈〉, f ′)) = 1M(fus(f, 〈〉)) = 1M(fus(f, f ′)) = 1 +

{M(fus(d, f ′)) + ϕ(fus(d, f ′), g)− ϕ(g, d) Si r ≤ r′

M(fus(d′, f)) + ϕ(fus(d′, f), g′)− ϕ(g′, d′) Si r′ < r

Nous abordons la troisième partie de la démonstration, celle qui consisteà majorer la fonction M(fus(f, f ′)). Nous choisissons de ne pas tenter de ré-soudre directement cette équation récurrente. Nous proposons de démontrer parinduction que :

M(fus(f, f ′)) ≤ log(f + f ′) + log f + log f ′ + 1 (9.5.4)

Débutons par le cas de base f = 〈〉. D’après l’équation récurrente ci-dessus,nous avons M(fus(〈〉, f ′)) = 1. Par ailleurs :

Page 378: Structures de données et méthodes formelles ||

9. Files de priorité 371

log(f + f ′) + log f + log f ′ + 1= Hypothèselog(〈〉+ f ′) + log 〈〉+ log f ′ + 1

= Définition de log(1 + f ′) + log 1 + log f ′ + 1

≥ est positive et propriétés du loglog(1) + 1

= Propriétés du log1

D’où, par transitivité, la propriété 9.5.4 pour le cas f = 〈〉. Le second cas debase (f ′ = 〈〉) se traite de la même façon et conduit au même résultat. Les deuxcas de la partie inductive sont également symétriques. Nous ne traitons que lecas r ≤ r′. Le calcul se fait sous l’hypothèse d’induction :

M(fus(d, f ′)) ≤ log(d+ f ′) + log d+ log f ′ + 1

Compte tenu de la structure de la définition de la fonction ρ, ce calcul nousconduit à considérer (a priori) quatre sous-cas : deux cas pour chaque sous-formule du type ϕ(. . .) dans la définition récurrente deM. C’est ce que montre letableau 9.4. Le sous-cas (15) devrait respecter simultanément les deux inégalitésd+ f ′ < g et g < d, ce qui entraînerait f ′ < 0, qui est impossible. Pour les troisautres cas, le tableau fournit la valeur des expressions ϕ(. . .) ainsi que l’inégalitéqui synthétise la condition représentée.

Tableau 9.4 – Analyse amortie de l’opération fus – les sous-cas.Ce tableau présente les quatre cas possibles pour les deux expressionsde la forme ϕ(. . .) présentes dans l’équation récurrente définissant lavaleur de la complexité amortie de l’opération fus. Parmi ces quatrecas, seuls trois sont possibles, le cas (15) conduit à une incohérence.Chaque cellule du tableau fournit les valeurs des deux expressions ϕ(. . .)ainsi qu’une synthèse des conditions sous la forme d’inégalités.

fus(d, f ′) < g fus(d, f ′) ≥ g

g < dCas (15) :impossible

Cas (16) :ϕ(fus(d, f ′), g) = 0ϕ(g, d) = 1

1 ≤ g < d < d+ f ′

g ≥ d

Cas (17) :ϕ(fus(d, f ′), g) = 1ϕ(g, d) = 0

1 ≤ d < d+ f ′ < g

Cas (18) :ϕ(fus(d, f ′), g) = 0ϕ(g, d) = 0

1 ≤ d ≤ g ≤ d+ f ′

Le calcul débute comme suit :

Page 379: Structures de données et méthodes formelles ||

372 Structures de données et méthodes formelles

M(fus(f, f ′))= Équation récurrente1 +M(fus(d, f ′)) + ϕ(fus(d, f ′), g)− ϕ(g, d)

≤ Hypothèse d’induction2 + log(d+ f ′) + log d+ log f ′ + ϕ(fus(d, f ′), g)− ϕ(g, d) (9.5.5)

À ce stade, il faut distinguer les trois cas significatifs qui sont présentés dans letableau 9.4, page précédente. Débutons par le cas (16) :

2 + log(d+ f ′) + log d+ log f ′ + ϕ(fus(d, f ′), g)− ϕ(g, d)= Cas (16)2 + log(d+ f ′) + log d+ log f ′ + 0− 1

= Calcul sur R+

log(d+ f ′) + log d+ log f ′ + 1≤ Propriétés de et du loglog(g + d+ f ′) + log(g + d) + log f ′ + 1

= Définition de log(f + f ′) + log(f) + log f ′ + 1

Ce qui démontre l’inégalité pour le cas (16). Abordons à présent le cas (17) enrepartant de la formule 9.5.5 :

2 + log(d+ f ′) + log d+ log f ′ + ϕ(fus(d, f ′), g)− ϕ(g, d)= Cas (17)2 + log(d+ f ′) + log d+ log f ′ + 1− 0

= Calcul sur R+

3 + log(d+ f ′) + log d+ log f ′

Nous devons montrer que cette formule est inférieure ou égale à log(f + f ′) +log f + log f ′ + 1 :

3 + log(d+ f ′) + log d+ log f ′ ≤ log(f + f ′) + log f + log f ′ + 1⇔ Calcul sur R+ définition de 2 + log(d+ f ′) + log d ≤ log(g + d+ f ′) + log(g + d)

⇔ Calcul sur R+ et propriétés du log2 ≤ log g+d+ f ′

d+ f ′ + log g+dd

⇔ Calcul sur R+ et propriétés du log2 ≤ log(1 + g

d+ f ′ ) + log(1 +gd) (9.5.6)

Les inégalités du tableau 9.4, cas (17), permettent de minorer les expressionsg

d+ f ′ etgdpar 1. Puisque la fonction log est croissante, nous avons donc :

log(1 + gd+ f ′ ) + log(1 +

gd)

≥ Propriétés du loglog(1 + 1) + log(1 + 1)

= Propriétés du log2

Page 380: Structures de données et méthodes formelles ||

9. Files de priorité 373

Ce qui démontre l’inégalité 9.5.6 et achève la démonstration du cas (17). Abor-dons enfin le cas (18) en repartant de la formule 9.5.5 :

2 + log(d+ f ′) + log d+ log f ′ + ϕ(fus(d, f ′), g)− ϕ(g, d)= Cas (18)2 + log(d+ f ′) + log d+ log f ′ + 0− 0

= Calcul sur R+

2 + log(d+ f ′) + log d+ log f ′

Nous devons montrer que cette formule est inférieure ou égale à log(f + f ′) +log f+log f ′+1. De manière analogue au cas (17), ceci nous conduit à démontrerque :

1 ≤ log(1 + gd+ f ′ ) + log(1 +

gd)

Les inégalités du cas (18) nous permettent de minorer gd+ f ′ par 0 et

gdpar 1. En

conséquence, nous avons :

log(1 + gd+ f ′ ) + log(1 +

gd)

≥ Propriétés du loglog(1) + log(1 + 1)

= Propriétés du log1

Ce qui achève la démonstration du cas (18). Nous avons donc démontré l’in-égalité 9.5.4 pour r ≤ r′. Par symétrie nous en déduisons que l’inégalité estégalement démontrée pour le cas r > r′. Le calcul se poursuit et s’achève par :

M(fus(f, f ′))≤ Propriété 9.5.4log(f + f ′) + log f + log f ′ + 1

≤ log est une fonction croissantelog(f + f ′) + log(f + f ′) + log(f + f ′) + 1

= Calcul sur R+

3 · log(f + f ′) + 1

D’où le résultat recherché :M(fus(f, f ′)) est en O(log(f+ f ′)). Il est facile d’endéduire que le coût amorti des opérations fpAjout_mo et fpSupp_mo sur unarbre f est enO(log f) et celui de l’opération fpFus_mo(f, f ′) enO(log(f+f ′)).

9.5.6 Conclusion et remarques bibliographiquesÀ condition d’accepter les restrictions inhérentes à l’analyse amortie, la re-

présentation par minimiers obliques constitue une très bonne solution pour lamise en œuvre de files de priorité fusionnables. Cette solution a été proposéeinitialement par D.D. Sleator et R.E. Tarjan en 1986 [110] dans le cadre de leurstravaux sur les structures autoadaptatives, sur la complexité amortie et les re-lations qu’entretiennent ces deux concepts. L’article initial est plutôt de nature

Page 381: Structures de données et méthodes formelles ||

374 Structures de données et méthodes formelles

descriptive et informelle. En particulier, à l’instar d’ailleurs de la majorité desarticles sur le sujet, un minimier oblique est défini comme étant soit un arbrebinaire vide soit le résultat de la fusion de deux minimiers obliques, ignorant dece fait les incidences que cette définition peut avoir sur la structure des arbreset en particulier sur l’absence de point simple à droite (la figure 1 de la page 55de [110] présente d’ailleurs comme minimiers obliques des arbres dotés de pointssimples à droite). Concernant l’analyse amortie, celle-ci est introduite selon uneapproche « itérative ». Nous avons adopté la fonction de potentiel de D.D. Slea-tor et R.E. Tarjan, cependant, par son caractère inductif, notre analyse amortie 5s’inspire plus des travaux d’A. Kaldewaij et B. Schoenmakers [69, 101]. L’objec-tif de ces derniers auteurs est non seulement de déterminer un comportementasymptotique pour la fonction M(fus(f, f ′)) mais aussi de rechercher la pluspetite borne possible. Ils montrent, par une analyse sophistiquée, que, si φ est lenombre d’or,

M(fus(f, f ′)) ≤ logφ(w(f) + w(f ′))

Dans un article ultérieur, B. Schoenmakers s’est attaché à rechercher uneborne minimale la plus grande possible. Ces développements vont bien entenduau-delà de nos objectifs qui, rappelons-le, se limitent à la recherche d’un com-portement asymptotique (pour une analyse amortie ou classique).

L’article de D.D. Sleator et R.E. Tarjan [110] étudie une version ascendantedes minimiers obliques. En terme d’analyse amortie, cette version est très effi-cace (temps constant pour toutes les opérations sauf pour l’opération fpPrio).Cependant, cette structure n’est pas de nature fonctionnelle (cf. [101] pour uneétude fonctionnelle des minimiers obliques ascendants).

Les minimiers gauchistes, qui font l’objet de l’exercice 9.5.9, sont souventconsidérés comme des précurseurs des minimiers obliques. Il s’agit cependantd’arbres explicitement équilibrés. Selon D. Knuth [75], ils doivent être attribuésà C.A. Crane, en 1972.

Il existe des files de priorité fusionnables probabilistes, dotées d’excellentesperformances. C’est le cas des trois structures de données SBSH (Simple Bottom-up Sampled Heap), BSH1 et BSH1 décrites par R. Sridhar et al. dans [98].Cependant, ces structures de données ne sont pas de nature fonctionnelle. Ellesne sont donc pas étudiées ici.

Exercices

Exercice 9.5.1 On appelle arbre oblique un arbre non étiqueté satisfaisant les propriétésstructurelles du support mo. Énumérer les arbres obliques de 1, 2, 3, . . . nœuds.

Exercice 9.5.2 Montrer que dans un arbre oblique de poids n la branche de droite contientun nombre de nœuds inférieur ou égal à �n

2�.

Exercice 9.5.3 Quel est le minimier oblique obtenu par l’ajout successif des valeurs suivantes :10, 7, 14, 1, 8, 19, 14, 2, 5, 17 et 7 dans un minimier vide ?

Exercice 9.5.4 Réaliser l’anatomie de la fusion des deux minimiers obliques ci-dessous :

5. Présentée initialement dans [48].

Page 382: Structures de données et méthodes formelles ||

9. Files de priorité 375

1

35 12

14

17

22

26

6

21

50

13

30

31

19

Exercice 9.5.5 Dans le calcul de l’opération fus, montrer que les expressions du type (. . .)��r�conduisent à des arbres filiformes.

Exercice 9.5.6 Dans le calcul de l’opération fus, montrer que les solutions 4 et 10 du ta-bleau 9.3, page 365, conduisent à des arbres filiformes.

Exercice 9.5.7 En utilisant la même fonction de potentiel que celle utilisée dans l’analyse decomplexité ci-dessous, montrer

1. que la complexité amortie du parenthésage 12 du tableau 9.3, page 365, est la mêmeque celle développée pour le parenthésage 8,

2. que la complexité amortie des parenthésages 9 et 11 du tableau 9.3 n’est pas en O(log(n+n′)).

Exercice 9.5.8 Dans cet exercice on cherche à représenter les files de priorité par des minimiersquelconques. Fournir une spécification concrète puis calculer la représentation de la fusion quiinterclasse la branche droite de l’arbre gauche et la branche gauche de l’arbre droit. Quepeut-on dire de la complexité des opérations ?

Exercice 9.5.9 (arbres gauchistes/leftist trees) L’objectif de l’exercice est d’implanterdes files de priorité en utilisant un type particulier de minimiers appelé minimiers gauchistes.Compte tenu de la nature des minimiers binaires, il est possible d’échanger leurs deux sous-arbres sans altérer la propriété d’être un minimier. Cette possibilité peut être exploitée pourrétablir si nécessaire une propriété qui aurait été perdue au cours de manipulations. Dans unarbre binaire, on appelle nœud externe (au sens large) un nœud qui n’a pas deux descendants(qui est une feuille ou un point simple donc). Étant donné un arbre non vide, on considèretous les chemins entre la racine et les nœuds externes. Parmi tous ces chemins, il en existe(au moins un) de longueur inférieure ou égale à tous les autres en terme de nombre de nœudsfranchis. On appelle S la fonction qui, appliquée à un arbre binaire, délivre cette valeur. Lesupport des arbres gauchistes se définit par :

1) a = 〈〉 ⇒ a ∈ mg2) a = 〈g, r, d〉 ∧ g, d ∈ mg ×mg ∧ r ∈ N ∧ r = bMin(A(a)) ∧ S(g) ≥ S(d) ⇒ a ∈ mg

1. Définir la fonction S.2. Montrer que, dans un arbre gauchiste, parmi tous les chemins entre la racine et les

nœuds externes, le chemin droit est le plus court.3. Fournir une spécification concrète des files de priorité fusionnables par arbres gauchistes.4. L’opération centrale de la mise en œuvre des files de priorité fusionnables à partir de

minimiers gauchistes est l’opération de fusion entre deux minimiers gauchistes. Elle sedéfinit comme suit. On considère le cas général où les deux arbres à fusionner ne sontpas vides. Soit a celui des deux arbres qui a la racine la plus petite et b l’autre arbre.L’un des deux sous-arbres du résultat est le sous-arbre gauche de a, l’autre sous-arbredu résultat est l’arbre obtenu par la fusion du sous-arbre droit de a avec l’arbre b. Cesdeux sous-arbres sont positionnés à gauche et à droite de la racine de l’arbre résultatde façon à préserver la propriété d’être un arbre gauchiste. Calculer une représentationde l’opération de fusion. En déduire la représentation des autres opérations.

5. Quel est selon vous l’avantage des minimiers gauchistes sur les simples minimiers pourla mise en œuvre de files de priorité ?

Exercice 9.5.10 Dans [93], C. Okasaki développe les files de priorité avec le support et lesheuristiques des arbres déployés (cf. section 6.8). Faire de même après avoir étudié cette sec-tion 6.8 sur les arbres déployés en calculant la représentation des opérations puis en effectuantune analyse amortie.

Page 383: Structures de données et méthodes formelles ||

Chapitre 10

Tableaux flexibles

10.1 Introduction

Dans la plupart des langages de programmation, le concept de tableaus’identifie à celui de fonction définie sur un intervalle constant de relatifs, inter-valle connu dès la compilation (Pascal, C, etc.) ou au plus tard au moment oùs’exécute la déclaration du tableau (comme en Ada par exemple). On parle alorsde tableaux statiques. L’inconvénient bien connu de cette construction est quele programmeur doit connaître, au plus tard quand l’exécutif réserve les empla-cements pour le tableau, la taille maximale que peuvent avoir ses données (lataille physique du tableau). En outre, il est parfois obligé de gérer séparémentla taille logique, quand celle-ci peut être inférieure ou égale à la taille physique.Cet inconvénient, connu depuis longtemps, a incité les concepteurs de langagesde programmation à introduire plus de souplesse dans la gestion des tableauxtout en préservant l’efficacité (par des opérations qui s’exécutent en temps quasiconstant). Pour simplifier, nous nous intéressons uniquement à des tableaux àune seule dimension. Le terme de tableau flexible recouvre les différentes pos-sibilités offertes au programmeur de faire varier le domaine de définition i .. sd’un tableau au cours de son existence. Nous pouvons distinguer deux princi-pales formes de flexibilité, la faible et la forte. La flexibilité faible se caractérisepar le fait que la modification n’est possible qu’aux bornes, soit en ajoutant soiten supprimant une valeur. Si la variation ne peut avoir lieu que sur la bornesupérieure (resp. inférieure), nous parlons de flexibilité faible à droite (resp. àgauche). La flexibilité forte se définit par la possibilité d’ajouter ou de suppri-mer une valeur en toute position. Là aussi nous pouvons parler de flexibilité àgauche ou à droite. Une opération complémentaire, la concaténation de tableaux,est parfois intégrée au type abstrait « tableau flexible ».

Ce chapitre s’intéresse d’une part à une mise en œuvre particulière de laflexibilité faible, celle par arbres de Braun, et d’autre part au principe de laflexibilité forte par minimiers. Nous verrons que l’on sait parfaitement mettre enœuvre la flexibilité faible sans concaténation alors que le problème de la flexibilitéforte n’est résolu que de façon imparfaite.

Page 384: Structures de données et méthodes formelles ||

378 Structures de données et méthodes formelles

10.2 Flexibilité faible à droite : présentationinformelle

Outre les opérations usuelles sur les tableaux à une dimension (consultationde la valeur en un point du domaine de définition, modification d’une valeur),un tableau faiblement flexible à droite autorise la création d’un tableau vide,l’allongement du domaine de définition par ajout d’un élément au-delà de laborne supérieure, le raccourcissement du domaine de définition d’une positionde la borne supérieure et la consultation de la longueur courante du tableau. Parconvention, la borne inférieure est fixée à 1. Les six opérations suivantes sontdonc définies :

– twCreer, (tableau faiblement (weak) flexible, créer) opération qui délivreun tableau faiblement flexible vide (dont le domaine de définition est 1..0) ;

– twAll(v, t), (tableau faiblement flexible, allonger) opération d’allongementd’une unité de la borne supérieure, qui délivre un tableau identique à t surle domaine de définition de t et valant v pour la nouvelle borne supérieure ;

– twRac(t), (tableau faiblement flexible, raccourcir) opération de raccourcis-sement d’une unité de la borne supérieure, qui délivre un tableau identiqueà t sur le nouveau domaine de définition. Cette opération exige que le do-maine de définition initial de t ne soit pas vide ;

– twAff(v, p, t), (tableau faiblement flexible, affectation) opération qui dé-livre un tableau identique à t sauf au point p où il vaut v. Cette opérationexige que p appartienne au domaine de définition de t ;

– twV al(p, t), (tableau faiblement flexible, valeur) opération qui délivre lavaleur située à la position p du tableau t. Cette opération exige que pappartienne au domaine de définition de t ;

– twLong(t), (tableau faiblement flexible, longueur) opération qui délivre lalongueur du tableau flexible t.

Notons qu’un tableau faiblement flexible à droite n’est autre qu’une pilepermettant l’adressage sur toute la pile.

10.3 Flexibilité faible à droite : spécification dutype abstrait twabst

Cette spécification est présentée à la figure 10.1. Dans la spécification desopérations twAff et twV al, la précondition implique que t = ∅. Le type estparamétré par E, type des éléments du tableau, dont le support est e.

10.4 Flexibilité faible à droite : mise en œuvrepar arbres de Braun

Une forme d’arbres binaires particulièrement bien équilibrés, les arbres deBraun, peut être utilisée pour mettre en œuvre les tableaux faiblement flexiblesà droite, de manière particulièrement efficace.

Page 385: Structures de données et méthodes formelles ||

10. Tableaux flexibles 379

abstractTypetwabst(E) = (twAbst, (twCreer, twAll, twRac, twAff),(twV al, twLong))

usesN

supports ∈ N ∧ t ∈ 1 .. s→ e ⇔ t ∈ twAbst(E)

operationsfunction twCreer() ∈ twAbst(E) = 1 .. 0�∅

;function twAll(v, t) ∈ e× twAbst(E)�� twAbst(E) =t�− {max(dom(t)) + 1 �→ v}

;function twRac(t) ∈ twAbst(E) �→ twAbst(E) =pre

t = ∅then1 ..max(dom(t))− 1� t

end;

function twAff(v, p, t) ∈ e× N1 × twAbst(E) �→ twAbst(E) =pre

p ∈ dom(t)then

t�− {p �→ v}end

;function twV al(p, t) ∈ N1 × twAbst(E) �→ e =pre

p ∈ dom(t)then

t(p)end

;function twLong(t) ∈ twAbst(E)→ N = max(dom(t))

end

Figure 10.1 – Spécification du type abstrait twabst.Le type abstrait twabst spécifie les tableaux faiblement flexibles àdroite. e est le support du type E. L’adjonction et la suppression nesont autorisées qu’à la borne supérieure du tableau. twAll est l’opérationd’allongement, twRac l’opération de raccourcicement, twAff l’opéra-tion d’affectation, twV al l’opération de consultation, enfin twLong dé-livre la longueur courante du tableau.

Page 386: Structures de données et méthodes formelles ||

380 Structures de données et méthodes formelles

Flexibilité faible et langages de programmation

Pour ce qui concerne les langages de programmation universels in-cluant le concept de tableau faiblement flexible, le premier en date estAlgol 68 [1]. Avec ce langage, le programmeur a la possibilité de dé-clarer des tableaux dotés ou non de bornes flexibles. La déclaration[0 flex : 10 flex] int t1 définit un tableau d’entiers t1 dont l’intervallede définition vaut 0 .. 10 lors de l’exécution de cette déclaration.

Dans [30] (page 99 et suivantes), E.W. Dijkstra définit un langagedisposant d’une forme de flexibilité permettant d’étendre ou de réduireexplicitement les bornes de l’intervalle de définition d’un tableau. Si t estdéclaré par t int array := (1, 13,−1), t est un tableau dont la borneinférieure du domaine de définition est 1, la taille 2 (car 2 valeurs, 13 et−1, sont présentes après la mention de la borne inférieure) et les valeursinitiales de t[1] et t[2] sont respectivement 13 et −1. Le domaine de dé-finition initial est donc 1 .. 2. L’exécution de t.hiext(x) (resp. t.loext(x))a pour effet d’ajouter l’élément x immédiatement après (resp. avant) laborne supérieure (resp. inférieure) courante (soit à la position d’indice 3– resp. 0), tout en redimensionnant le domaine de définition (qui devient1 .. 3 – resp. 0 .. 2).

Le langage Java [121] offre la possibilité de faire varier la bornesupérieure d’un tableau en utilisant la classe ArrayListe. Le texteArrayListe t= new ArrayListe(); déclare un tableau flexible définisur un intervalle débutant en 0 et ne contenant initialement aucun élé-ment. t.add(new Integer(5)); a pour effet d’allonger la borne supérieuredu domaine de définition de un et de placer l’objet 5 dans le nouvel em-placement. L’instruction t.remove(i) supprime (si i appartient bien audomaine de définition de t) l’emplacement d’indice i tout en décalant lescellules d’indices supérieurs à i vers le bas. La borne supérieure diminuede un. Il s’agit donc d’une flexibilité faible pour les ajouts et forte pourles suppressions.

Pour les deux langages Algol 68 et Java, la forme de flexibilité pro-posée impose ou suggère la même stratégie de mise en œuvre. C’est cellequi consiste à abandonner la zone de mémoire contiguë devenue trop ré-duite pour en allouer une plus grande avant d’y effectuer la recopie desvaleurs initiales. Les actions d’allocation, de désallocation et de copie sontautomatiques et confiées à l’exécutif. Cette stratégie n’est pas aussi pé-nalisante qu’il y paraît. En effet, il est possible de montrer qu’avec unedéfinition appropriée des structures de données et des opérations, une af-fectation dans un contexte de recopie possède un coût amorti en O(1).C’est également sans doute l’une des raisons du désintérêt relatif enversla flexibilité faible : hormis le contexte du temps réel, la solution naïve deréallocation et recopie est efficace (cf. exercice 10.4.11).

Page 387: Structures de données et méthodes formelles ||

10. Tableaux flexibles 381

10.4.1 Flexibilité faible à droite : définition du supportconcret

Un arbre de Braun est un arbre binaire étiqueté tel que, pour tous les nœuds,la différence de poids entre le sous-arbre gauche et le sous-arbre droit est comprisedans l’intervalle 0 ..1. Formellement, si w est la fonction qui délivre le poids d’unarbre, un tel arbre se décrit de la manière suivante :

1) 〈〉 ∈ twBr(E)2) r ∈ e ∧ g, d ∈ twBr(E)× twBr(E) ∧ w(g)− w(d) ∈ {0, 1}

⇒〈g, r, d〉 ∈ twBr(E)

Le schéma ci-dessous montre un arbre de Braun de 8 éléments, pour E = N.

12

14

3

7

10

7

3 15

L’une des caractéristiques des arbres de Braun est que le nombre de nœuds(le poids) détermine la structure de l’arbre de manière unique. Ainsi le schéma ci-dessous montre la structure des douze arbres de Braun depuis l’arbre de poids 1jusqu’à l’arbre de poids 12 (les valeurs associées aux nœuds sont ignorées pourle moment).

•1 •

•1

2

• •

1

2 3

1

2

4

3

1

2

4

3

5

• •

1

2

4 6

3

5

• •

• •

1

2

4 6

3

5 7

• •

1

2

4

8

6

3

5 7

1

2

4

8

6

3

5

9

7

1

2

4

8

6

10

3

5

9

7

1

2

4

8

6

10

3

5

9

7

11

• •

1

2

4

8 12

6

10

3

5

9

7

11

Page 388: Structures de données et méthodes formelles ||

382 Structures de données et méthodes formelles

Tableau 10.1 – Propriétés des arbres de Braun.Ce tableau présente quelques-unes des relations qui lient le poids del’arbre et celui de ses sous-arbres. a est un arbre de Braun non vide etw est la fonction qui délivre le poids d’un arbre.

Propriété Condition Ident.

w(g) = w(a)÷ 2 a = 〈g, r, d〉 (10.4.1)

w(d) = (w(a)− 1)÷ 2 a = 〈g, r, d〉 (10.4.2)

w(a) = 2 · w(g) + 1 ∧ w(d) = w(g) a = 〈g, r, d〉 ∧ w(a) mod 2 = 1 (10.4.3)

w(a) = 2 · w(g) ∧ w(d) = w(g)− 1 a = 〈g, r, d〉 ∧ w(a) mod 2 = 0 (10.4.4)

Dans un arbre de Braun, connaître le poids de l’arbre est équivalent àconnaître le poids de chacun des sous-arbres. Le tableau 10.1 regroupe plusieursdes propriétés des arbres de Braun.

Les propriétés 10.4.1 et 10.4.2 peuvent être utilisées pour calculer le poids dessous-arbres à partir du poids de l’arbre. L’ensemble de ces propriétés est mis àprofit lors du calcul des opérations ainsi que lors de la phase de raffinement visantà s’affranchir des appels à la fonction w (cf. chapitre 10.4.5). La démonstrationde ces propriétés est laissée en exercice (cf. exercice 10.4.2).

La relation qui lie le poids n et le rayon r dans un arbre de Braun est lasuivante : r = �log n� + 1. Nous en concluons qu’à la condition d’éliminer lesappels aux fonctions auxiliaires éventuelles (cf. sections 1.10 et 2.4), toutes lesopérations qui parcourent tout ou partie du chemin de la racine vers une feuillesont en O(log n). C’est le cas de toutes les opérations de mises à jour définiesdans le type abstrait.

10.4.2 Flexibilité faible à droite : définition de la fonctiond’abstraction

Plus qu’ailleurs, la compréhension de la fonction d’abstraction conditionne lacompréhension de cette mise en œuvre. La fonction d’abstraction est telle qu’unarbre de Braun a représente un tableau flexible à droite t défini sur l’intervalle1 .. w(a). La racine représente t(1), le sous-arbre gauche (resp. droit) représenteles valeurs aux positions d’indices pairs à partir de 2 (resp. impairs à partir de 3).Sur le schéma ci-dessus, les valeurs apposées aux nœuds représentent les indicesdans le tableau. Compte tenu de ces conventions, nous avons la correspondancesuivante entre l’arbre étiqueté ci-dessous et le tableau qu’il représente :

12

14

3

7

10

7

2 15

12 14 7 3 2 10 15 7

1 2 3 4 5 6 7 8

Page 389: Structures de données et méthodes formelles ||

10. Tableaux flexibles 383

Pour obtenir ce résultat, il suffit d’appliquer inductivement le schéma deconstruction ci-dessous (le cas de base est trivial) :1. placer la racine en t(1),2. construire un tableau tg (resp. td) à partir du sous-arbre gauche (resp.

droit),3. ventiler les valeurs du tableau tg (resp. td) sur les positions paires (resp.

impaires et différentes de un) d’un tableau tg′ (resp. td′),4. fusionner les trois tableaux t, tg′ et td′ par des surcharges.

Il n’est pas inutile d’insister sur le fait que la fonction d’abstraction n’a pasà être implantée, elle ne sert que pour calculer les opérations. Ce processus depassage de l’arbre au tableau se représente par la fonction d’abstraction A définieci-dessous. L’arbre vide correspond à un tableau vide. Un arbre non vide 〈g, r, d〉délivre un tableau dont le premier élément est r et dont les éléments situésaux positions paires (resp. impaires) s’obtiennent par ventilation du tableaucorrespondant au sous-arbre gauche (resp. droit) sur les positions paires (resp.impaires).

function A(a) ∈ twBr(E)�� twAbst(E) =if a = 〈〉 →1 .. 0�∅

| a = 〈g, r, d〉 →{1 �→ r}

�−A(g) ◦ (λi ·(i ∈ N | 2 · i))−1

�−A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

fi

Les expressions de surcharge méritent d’être explicitées. Prenons par exemplel’expression A(g) ◦ (λi ·(i ∈ N | 2 · i))−1. Ainsi que le montre la première tabu-lation du tableau 10.2, la lambda expression λi ·(i ∈ N | 2 · i) représente la

14

3

7

10

7

2 15

14 3 10 7

1 2 3 47 2 15

1 2 3

14 3 10 7

2 3 4 5 6 7 87 2 15

3 4 5 6 7

12 14 7 3 2 10 15 7

1 2 3 4 5 6 7 8

ventilation

ventilation

surcharge

tg

td

tg′

td′

t(1) : hyp. d’induction

(1)

(1)

Page 390: Structures de données et méthodes formelles ||

384 Structures de données et méthodes formelles

Tableau 10.2 – Tabulations.Tabulation de la fonction λi ·(i ∈ N | 2 · i) et de sa réciproque.

λi ·(i ∈ N | 2 · i)Argument Valeur

0 �→ 01 �→ 22 �→ 43 �→ 64 �→ 85 �→ 10

...

(λi ·(i ∈ N | 2 · i))−1

Argument Valeur0 �→ 02 �→ 14 �→ 26 �→ 38 �→ 410 �→ 5

...

Tableau 10.3 – Tabulation de la fonction A(g).

A(g)Argument Valeur

1 �→ 142 �→ 33 �→ 104 �→ 7

fonction qui à tout entier associe son double. Sa réciproque est la fonction qui àtout entier pair associe sa moitié (cf. la seconde tabulation).

D’après l’hypothèse d’induction, A(g) est le tableau obtenu à partir du sous-arbre gauche. La représentation en extension de cette fonction est donnée autableau 10.3.

La composition des deux fonctions A(g) et (λi ·(i ∈ N | 2 · i))−1 est unefonction de 4 éléments. Le tableau 10.4 détaille son calcul.

10.4.3 Flexibilité faible à droite : spécification des opéra-tions concrètes

La figure 10.2, page 386, fournit la description du type concret twbr eten particulier la spécification des opérations concrètes. De même que le typeabstrait, ce type est paramétré par E, qui est le type des éléments du tableau. Eneffet la technique des arbres de Braun présente l’avantage de n’imposer aucunecontrainte sur ce type, qui peut tout à fait être un type structuré quelconque.

Page 391: Structures de données et méthodes formelles ||

10. Tableaux flexibles 385

Tableau 10.4 – Tabulation de la fonction A(g) ◦ (λi ·(i ∈ N | 2 · i))−1.Ce tableau montre d’une part comment se composent les deux fonctionsA(g) et (λi ·(i ∈ N | 2 · i))−1 et d’autre part la tabulation du résultat dela composition.

A(g) ◦ (λi ·(i ∈ N | 2 · i))−1

Argument Valeur0 �→ 02 �→ 1 �→ 144 �→ 2 �→ 36 �→ 3 �→ 108 �→ 4 �→ 710 �→ 5

...

A(g) ◦ (λi ·(i ∈ N | 2 · i))−1

Argument Valeur2 �→ 144 �→ 36 �→ 108 �→ 7

10.4.4 Flexibilité faible à droite : calcul des opérationsconcrètes

L’expression abstraite dom(A(a)) apparaît dans certaines préconditions ainsique dans certains développements. Le calcul de sa contrepartie concrète 1 ..w(a)est proposé à l’exercice 10.4.1. Nous développons successivement le calcul desopérations twV al_br et twAll_br. Le calcul d’une représentation de l’opérationtwRac_br est semblable à celui de l’opération twAll_br, seul le résultat estproposé. Enfin, le calcul des autres opérations est laissé en exercice.

Calcul d’une représentation de l’opération twV al_br

L’opération twV al_br(p, a) délivre la valeur située à la position p du tableaureprésenté par l’arbre a. La précondition p ∈ dom(A(a)) se réécrit p ∈ 1 .. w(a).Elle implique que w(a) > 0 et donc que a = 〈〉. Nous pouvons poser a = 〈g, r, d〉.

twV al_br(p, a)= Propriété caractéristique

A(a)(p)= Hypothèse

A(〈g, r, d〉)(p)= Définition de A⎛⎝ {1 �→ r}�−

A(g) ◦ (λi ·(i ∈ N | 2 · i))−1�−A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

⎞⎠ (p) (10.4.5)

Procédons à une induction selon que p = 1 ou que p = 1. Débutons par lecas de base p = 1.

({1 �→ r} �− A(g) ◦ (λi ·(· · · ))−1 �− A(d) ◦ (λi ·(· · · ))−1)(p)

Page 392: Structures de données et méthodes formelles ||

386 Structures de données et méthodes formelles

concreteTypetwbr(E) = (twBr, (twCreer_br, twAll_br, twRac_br, twAff_br),(twV al_br, twLong_br))

uses N,N1

refines twabst(E)support

1) 〈〉 ∈ twBr(E)2) r ∈ e ∧ g, d ∈ twBr(E)× twBr(E) ∧ w(g)− w(d) ∈ {0, 1}

⇒〈g, r, d〉 ∈ twBr(E)

abstractionFunctionfunction A(a) ∈ twBr(E)�� twAbst(E) = . . .

operationSpecificationsfunction twCreer_br() ∈ twBr(E) = . . .

; function twAll_br(v, a) ∈ e× twBr(E)� twBr(E) =b : (b ∈ twBr(E) ∧ A(b) = twAll(v,A(a)))

; function twRac_br(a) ∈ twBr(E) �→ twBr(E) =pre

A(a) = ∅then

b : (b ∈ twBr(E) ∧ A(b) = twRac(A(a)))end

; function twAff_br(v, p, a) ∈ e× N1 × twBr(E) �→ twBr(E) = . . .; function twV al_br(p, a) ∈ N1 × twBr(E) �→ e =

prep ∈ dom(A(a))

thentwV al(p,A(a))

end; function twLong_br(a) ∈ twBr(E)→ N = twLong(A(a))end

Figure 10.2 – Spécification du type concret twbr.Le type concret twbr implante des tableaux faiblement flexibles à droitepar des arbres de Braun. La fonction d’abstraction est détaillée à lasection 10.4.2. Observons que ce type est paramétré par le type E, desupport e. w est la fonction qui délivre le poids d’un arbre de Braun.

= Hypothèse({1 �→ r} �− A(g) ◦ (λi ·(· · · ))−1 �− A(d) ◦ (λi ·(· · · ))−1)(1)

= Propriété C.13{1 �→ r}(1)

= Propriété C.17r

D’où la première équation gardée :

Page 393: Structures de données et méthodes formelles ||

10. Tableaux flexibles 387

let 〈g, r, d〉 := a inp = 1→

twV al_br(p, a) = rend

L’étape inductive, p = 1, se décompose en deux sous-cas : p pair et p impair.Débutons par le cas où p est pair (p mod 2 = 0) en repartant de la formule 10.4.5ci-dessus.

({1 �→ r} �− A(g) ◦ (λi ·(· · · ))−1 �− A(d) ◦ (λi ·(· · · ))−1)(p)= p ∈ dom(A(g) ◦ (λi ·(i ∈ N | 2 · i))−1) : propriétés C.14 et C.13(A(g) ◦ (λi ·(i ∈ N | 2 · i))−1)(p)

= Propriété C.7A(g)((λi ·(i ∈ N | 2 · i))−1)(p)

= Définition de −1, section 1.6.3A(g)(λi ·(i ∈ N ∧ i mod 2 = 0 | i÷ 2))(p)

= Propriété C.3 et substitutionA(g)(p÷ 2)

= Propriété caractéristique de l’opération twV al_brtwV al_br(p÷ 2, g)

D’où l’équation gardée suivante :

let 〈g, r, d〉 := a inp = 1→

p mod 2 = 0→twV al_br(p, a) = twV al_br(p÷ 2, g)

end

Pour le cas où p est impair et différent de 1, le calcul est similaire. Au total,nous avons calculé la version suivante de l’opération twV al_br :

function twV al_br(p, a) ∈ N1 × twBr(E)→ e =pre

p ∈ 1 .. w(a)then

let 〈g, r, d〉 := a inif p = 1 →

r| p = 1 →

if p mod 2 = 0 →twV al_br(p÷ 2, g)

| p mod 2 = 0 →twV al_br(p÷ 2, d)

fifi

endend

La complexité de cette opération est en O(log n) pour un arbre de poids n.

Page 394: Structures de données et méthodes formelles ||

388 Structures de données et méthodes formelles

Calcul d’une représentation de l’opération twAll_br

L’opération twAll_br(v, a) permet d’allonger le tableau représenté parl’arbre a à l’extrémité de la borne supérieure et de placer la valeur v dans lenouvel emplacement.

A(twAll_br(v, a))= Propriété caractéristique de l’opération twAll_br

A(a)�− {max(dom(A(a))) + 1 �→ v}= dom(A(a)) = 1 .. w(a)

A(a)�− {w(a) + 1 �→ v} (10.4.6)

À ce stade, il faut procéder à une induction sur la structure de a. Soit a = 〈〉soit a = 〈〉. Débutons par le cas de base a = 〈〉.

A(a)�− {w(a) + 1 �→ v}= Hypothèse et définition de w

A(〈〉)�− {1 �→ v}= Définition de A{1 �→ v}

= Propriétés B.161 et B.162{1 �→ v}�−∅�−∅

= Propriété B.87{1 �→ v}�− (∅ ◦ (λi ·(i ∈ N | 2 · i))−1)�− (∅ ◦ (λi ·(i ∈ N | 2 · i+ 1))−1)

= Définition de A{1 �→ v}�−A(〈〉) ◦ (λi ·(i ∈ N | 2 · i))−1 �−A(〈〉) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

= Définition de AA(〈〈〉, v, 〈〉〉)

D’où la première équation gardée :

a = 〈〉 →twAll_br(v, a) = 〈〈〉, v, 〈〉〉

Pour l’étape inductive (a = 〈〉), nous pouvons poser a = 〈g, r, d〉 et repartir dela formule 10.4.6 ci-dessus :

A(a)�− {w(a) + 1 �→ v}= Hypothèse

A(〈g, r, d〉)�− {w(a) + 1 �→ v}= Définition de A⎛⎝ {1 �→ r} �−

A(g) ◦ (λi ·(i ∈ N | 2 · i))−1 �−A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

⎞⎠ �− {w(a) + 1 �→ v} (10.4.7)

Nous réalisons une analyse par cas selon la parité de w(a). Considérons toutd’abord le cas w(a) mod 2 = 0 en supposant démontré le lemme suivant (cf. exer-cice 10.4.3) :

Lemme 4. {w(a) + 1 �→ v} = {w(d) + 1 �→ v} ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

Page 395: Structures de données et méthodes formelles ||

10. Tableaux flexibles 389

Poursuivons le calcul :

⎛⎝ {1 �→ r} �−A(g) ◦ (λi ·(i ∈ N | 2 · i))−1 �−A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

⎞⎠ �− {w(d) + 1 �→ v}

= Propriété B.159⎛⎝ {1 �→ r} �−A(g) ◦ (λi ·(i ∈ N | 2 · i))−1 �−(A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1) �− {w(d) + 1 �→ v}

⎞⎠ (10.4.8)

Arrêtons-nous sur la dernière sous-formule afin de la simplifier :

(A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1) �− {w(d) + 1 �→ v}= Lemme 4(

A(d)◦(λi ·(i ∈ N | 2 · i+ 1))−1

)�−({w(d) + 1 �→ v}◦(λi ·(i ∈ N | 2 · i+ 1))−1

)= Propriété B.82(A(d)�− {w(d) + 1 �→ v}) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

= Propriété caractéristique de twAll_brA(twAll_br(v, d)) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1

Reportons ce dernier résultat dans la formule 10.4.8 ci-dessus :

⎛⎝ {1 �→ r} �−A(g) ◦ (λi ·(i ∈ N | 2 · i))−1 �−(A(d) ◦ (λi ·(i ∈ N | 2 · i+ 1))−1) �− {w(d) + 1 �→ v}

⎞⎠= Calcul ci-dessus⎛⎝ {1 �→ r} �−

A(g) ◦ (λi ·(i ∈ N | 2 · i))−1 �−A(twAll_br(v, d)) ◦ λi ·(i ∈ N | 2 · i+ 1)−1

⎞⎠= Définition de A

A(〈g, r, twAll_br(v, d)〉)

D’où l’équation gardée :

a = 〈g, r, d〉 →w(a) mod 2 = 0→

twAll_br(v, a) = 〈g, r, twAll_br(v, d)〉

Dans le cas ou w(a) est impair, des considérations de symétrie nous conduisentau résultat. Au total, nous obtenons la version suivante de l’opération twAll_br :

Page 396: Structures de données et méthodes formelles ||

390 Structures de données et méthodes formelles

function twAll_br(v, a) ∈ e× twBr(E)→ twBr(E) =if a = 〈〉 →

〈〈〉, v, 〈〉〉| a = 〈g, r, d〉 →

if w(a) mod 2 = 0 →〈g, r, twAll_br(v, d)〉

| w(a) mod 2 = 0 →〈twAll_br(v, g), r, d〉

fifi

Reste à régler le problème de l’évaluation de la fonction w. Un renforcementpar décomposition est possible puisqu’à l’évidence la fonction w est décompo-sable sur la structure de données. Sous cette hypothèse, la complexité de cetteopération est en O(log n) pour un arbre de poids n. Nous verrons cependant,à la section 10.4.5, qu’il existe une solution préférable à la décomposition pourraffiner la version ci-dessus de l’opération twAll_br.

Une représentation de l’opération twRac_br

L’opération twRac_br(a) supprime la cellule de droite du tableau représentépar l’arbre a. Un calcul similaire au précédent nous conduit à la représentationsuivante :

function twRac_br(a) ∈ twBr(E) �→ twBr(E) =pre

w(a) = 0then

if w(a) = 1 →〈〉

| w(a) = 1 →let 〈g, r, d〉 := a in

if w(a) mod 2 = 0 →〈twRac_br(g), r, d〉

| w(a) mod 2 = 0 →〈g, r, twRac_br(d)〉

fiend

fiend

Si l’opération w est en temps constant, cette opération est en O(log(n) pourun arbre de poids n. Concernant l’évaluation de la fonction w, la situation estidentique à celle rencontrée lors de l’opération twAll_br. Nous y consacrons laprochaine section.

Page 397: Structures de données et méthodes formelles ||

10. Tableaux flexibles 391

10.4.5 Décomposer la fonction w ?Les deux opérations twRac_br et twAll_br ne sont pas utilisables en l’état :

le coût induit par l’évaluation de la fonction w est rédhibitoire. Ainsi que nousl’avons vu aux sections 1.10 et 2.4, il est parfois possible d’améliorer la situationen renforçant le support afin d’y héberger la valeur d’une fonction telle quew. Cette solution est envisageable dans le cas des arbres de Braun (puisquela fonction w est O(1)-décomposable). Elle conduit cependant à échanger unproblème de temps contre un problème de place. Compte tenu des propriétés desarbres de Braun et en particulier du fait que la connaissance du poids d’un arbreest équivalente à la connaissance de celui de ses sous-arbres, il est possible delimiter le renforcement à l’ajout du poids de l’arbre « principal ». Nous sommesalors à même de calculer quand nécessaire le poids de chaque sous-arbre. Cecalcul se limite à une division par deux 1, la complexité est préservée et deplus le surcoût entraîné en terme d’espace mémoire est négligeable : un seulemplacement pour le poids de l’arbre principal.

En guise d’exemple, nous présentons ci-dessous une version aménagée del’opération twAll_br exploitant la remarque ci-dessus. Le traitement de l’opé-ration twRac_br serait similaire. Pour des raisons de lisibilité, nous n’avons pastenu compte de la modification exigée par le renforcement du support.

function twAll_br(v, a , w ) ∈ e× twBr(E) ×N → twBr(E) =

if a = 〈〉 →〈〈〉, v, 〈〉〉

| a = 〈g, r, d〉 →if w mod 2 = 0 →

〈g, r, twAll_br(v, d, w ÷ 2− 1 )〉| w mod 2 = 0 →

〈twAll_br(v, g, w ÷ 2 ), r, d〉fi

fi

Moyennant ce type d’aménagement, la complexité de toutes les opérationsest en O(log n) pour des arbres de poids n.

10.4.6 Conclusion et remarques bibliographiquesRelativement peu d’auteurs se sont penchés sur les tableaux faiblement

flexibles. Les chercheurs ont préféré se consacrer soit à la recherche de repré-sentations fonctionnelles efficaces de tableaux statiques [29, 95, 23] soit (quipeut le plus peut le moins) aux tableaux fortement flexibles (cf. section 10.5 etsuivantes). Il est vrai que face aux performances des arbres de Braun, apporterune amélioration est un défi de taille. Une solution intéressante, bien que légè-rement moins efficace, est proposée par V.J. Dielsen et A. Kaldewaij [28]. Elleconsiste à utiliser des arbres externes particuliers (cf. exercice 10.4.9). Cet article

1. Qui pour des programmes critiques peut être factorisée et réalisée par décalage. Il estégalement possible de déléguer ce travail d’optimisation à un bon compilateur.

Page 398: Structures de données et méthodes formelles ||

392 Structures de données et méthodes formelles

se présente comme un plaidoyer pour les arbres externes dont les avantages sontillustrés à travers l’exemple des tableaux faiblement flexibles.

Dans [21], D.J. Challab s’intéresse également à la mise en œuvre de tableauxfaiblement flexibles à droite. Il utilise des arbres 2-3 particuliers (précurseurs desB-arbres) pour lesquels les 3-nœuds sont situés sur la branche droite. L’extensionaux tableaux faiblement flexibles à gauche n’est pas envisagée et le résultat, bienqu’en O(log n), est de qualité médiocre par rapport aux arbres de Braun.

D’autres tentatives méritent d’être citées [87, 90]. La solution proposée parC. Okasaki dans [90] se situe dans le cadre de listes à accès direct. Elle peutfacilement être adaptée aux tableaux flexibles à droite. À l’évidence inspirée desfiles binomiales de J. Vuillemin (cf. [114, 115] et section 9.4), il s’agit malgrétout d’une solution originale qui peut donner lieu à un excellent projet sur lesstructures de données (cf. exercice 10.4.7).

Les arbres de Braun ont été découverts en 1983 par W. Braun et M. Rem.La présentation la plus accessible est cependant celle de R. Hoogerwoord [61].C. Okasaki présente dans [92] une étude des arbres de Braun qui inclut la re-cherche d’un algorithme efficace de construction d’un arbre de Braun à partird’une liste. L’un des seuls inconvénients qui puisse être opposé aux arbres deBraun est qu’ils violent facilement le principe de localité (des accès mémoireconsécutifs peuvent être très dispersés), ce qui peut être préjudiciable à unegestion efficace de la mémoire.

Exercices

Exercice 10.4.1 Calculer la représentation concrète de l’expression dom(A(a)).

Exercice 10.4.2 Démontrer les propriétés du tableau 10.1.

Exercice 10.4.3 Démontrer le lemme 4.

Exercice 10.4.4 Calculer l’équation gardée de l’opération twRac_br(a) dans le cas où w(a) =1 ∧ w(a) mod 2 = 0

Exercice 10.4.5 Mettre en œuvre les files simples (cf. section 8.1)1. par arbres de Braun,2. par tableaux faiblement flexibles à droite.

Exercice 10.4.6 Fournir une spécification abstraite des tableaux faiblement flexibles auxdeux extrémités. Compléter pour cela la spécification de la figure 10.1. Mettre en œuvre cettespécification par arbres de Braun.

Exercice 10.4.7 (Tableaux flexibles à droite par listes gloutonnes) Étant donné unentier naturel n, il est possible de le décomposer de manière unique en un sac d’entiers naturels�v1, v2, v3 · · · , vm� tel que :

1.∑m

i=1 vi = n et v1 ≤ v2 < v3 · · · < vm (seuls éventuellement les deux plus petitséléments sont identiques),

2. tous les vi sont de la forme 2k − 1 (éléments de la suite de Mersenne 0, 1, 3, 7, 15, . . .).�3, 3, 7� est une décomposition correcte de 13, �1, 1, 1, 3, 7� ne l’est pas. �1, 3, 3, 7� n’est pas unedécomposition correcte de 14.

Il est possible de s’inspirer de ce système de numération (voir [90], ainsi que l’encadréde la page 132) pour définir des « listes gloutonnes » destinées à représenter des tableauxfaiblement flexibles. Une liste gloutonne est une liste triée sur les poids croissants d’arbrespleins (cf. figure 3.3, page 89). Ainsi la structure suivante :

Page 399: Structures de données et méthodes formelles ||

10. Tableaux flexibles 393

5

12 13

4

8 2

10

7

9 6

11

15 1

est une liste gloutonne. En effet, le sac des poids, �3, 3, 7�, est une décomposition correcte de13. Un arbre plein de poids 2k − 1 peut représenter un tableau flexible de 2k − 1 éléments,il suffit d’adopter par exemple un parcours postfixé droite-gauche. Par extension, une listegloutonne de n éléments peut représenter un tableau de longueur n quelconque.

1. Montrer que la décomposition définie ci-dessus est unique.2. Spécifier le type concret twlg(E) (tableaux faiblement flexibles par listes gloutonnes)

qui raffine, par des listes gloutonnes, le type abstrait twabst de la page 379. Calculerune représentation de ses opérations.

3. Implanter une version finale des opérations exige – pour des raisons d’efficacité – d’éli-miner les appels à la fonction auxiliaire w. Proposer plusieurs méthodes. Discuter deleur efficacité.

4. Calculer la complexité au pire des opérations du type twlg.

Exercice 10.4.8 (Tableaux faiblement flexibles à droite par files binomiales) Lesfiles binomiales ont été utilisées à la section 9.4, page 331, pour mettre en œuvre les files depriorité fusionnables. En définissant une variante des files binomiales dans laquelle la propriétéde minimier disparaît, il est possible de mettre en œuvre efficacement des tableaux flexiblesà droite. Spécifier le type concret correspondant, calculer les opérations et en déduire leurscomplexités.

Exercice 10.4.9 (Tableaux faiblement flexibles par arbres externes) Les arbres ex-ternes ont été introduits à la section 3.6. Dans cet exercice (inspiré de [28]), nous souhaitonsimplanter les tableaux faiblement flexibles à droite par des arbres externes particuliers : lesarbres externes parfaits à gauche.

Un arbre externe plein est un arbre dont toutes les feuilles sont à la même hauteur. Unarbre externe parfait à gauche est un arbre dans lequel le sous-arbre gauche est un arbre plein,le sous-arbre droit est un arbre parfait à gauche et le rayon du sous-arbre gauche est supérieurou égal à celui du sous-arbre droit.

Il est possible de montrer qu’étant donné n ∈ N, il n’existe qu’un seul arbre parfait (nonétiqueté) à gauche possédant n feuilles. Ci-dessous sont représentés les 8 arbres parfaits àgauche correspondant aux entiers de l’intervalle 1 .. 8.

Questions1. Fournir la spécification concrète de la mise en œuvre des tableaux faiblement flexibles

selon la méthode des arbres parfaits à gauche.2. Calculer la représentation fonctionnelle des opérations et leur complexité.3. Sur la base des développements réalisés, réfléchir à une extension aux tableaux faible-

ment flexibles aux deux extrémités. Suggestion : utiliser des arbres externes tels que lesous-arbre gauche (resp. droit) est un arbre parfait à droite (resp. à gauche).

Page 400: Structures de données et méthodes formelles ||

394 Structures de données et méthodes formelles

Exercice 10.4.10 (Tableaux flexibles à droite par listes d’arbres externespleins) Dans cet exercice, nous proposons de mettre en œuvre des tableaux flexibles sur letype E de support e en utilisant des files d’arbres externes pleins (faeP ). Le support aeP (E)des arbres externes pleins se définit par :

1) v ∈ e⇒ 〈v〉 ∈ aeP (E)2) g, d ∈ aeP (E)× aeP (E) ∧ r(g) = r(d) ⇒ 〈g, d〉 ∈ aeP (E)

où r(a) représente le rayon de l’arbre a.1. Compléter la définition du type concret aep(E).2. Définir le support faeP (E) des files d’arbres externes pleins. Ce support spécifie que

la file est triée sur les rayons décroissants. Montrer qu’il existe une relation biunivoqueentre le nombre d’éléments du tableau flexible et la structure de la file.

3. Compléter la spécification concrète faep(E).4. Calculer les opérations concrètes. En déduire leurs complexités.

Exercice 10.4.11 (Tableaux flexibles à droite par réallocation) On cherche à évaluerla complexité amortie des tableaux faiblement flexibles gérés par réallocation. Le principe estle suivant. Un tableau t possède une longueur logique n courante et une longueur physiquemax (max ≥ n). On s’intéresse aux deux opérations twAll_r(v, t) et twRac_r(t) qui respec-tivement introduit v en t(n + 1) et réduit de un la longueur logique de t. Initialement, n = 0et max = 1. Le coût réel de twAll_r est de 1, cependant, si avant exécution de twAll_r,n = max alors le tableau est réalloué dans une zone de taille 2 ·max et les n valeurs sontrecopiées, auquel cas le coût réel est de n. Le coût réel de twRacc_r est de 1 sauf si aprèsl’opération, n ≤ max÷4, auquel cas le tableau est réalloué dans une zone de longueur max÷2et les n éléments y sont recopiés. Dans cette éventualité, le coût réel de l’opération est de n.Montrer que la complexité amortie des deux opérations est en temps constant.

10.5 Flexibilité forte : présentation informelleLes tableaux fortement flexibles sont des tableaux ayant les fonctionnalités

de leurs homologues faiblement flexibles auxquelles s’ajoute la possibilité d’in-sérer ou de supprimer une cellule à une position quelconque. Nous complétonsces fonctionnalités par l’introduction de la concaténation de deux tableaux. Lecontraste entre le potentiel de ce type abstrait et l’échec dans la recherche d’unemise en œuvre efficace en fait le Graal des structures de données. Les opéra-tions d’insertion et de suppression généralisent les opérations twRac et twAlldes tableaux faiblement flexibles. Ces dernières disparaissent donc de la spéci-fication abstraite. Nous n’avons pas défini l’équivalent de l’opération twAff .Elle s’obtient en composant les opérations tsSupp et tsIns. Elle peut égalementapparaître en tant qu’opération primitive (cf. exercice 10.7.2).

Le type abstrait définit les opérations suivantes :– tsCreer, opération qui délivre un tableau flexible vide ;– tsIns(v, p, t), si t est un tableau de n éléments, c’est une opération quidélivre un tableau identique à t à l’exception de la position p qui contientla valeur v. La position p est définie si 1 ≤ p ≤ n + 1, expression quipréconditionne cette opération. Cette opération provoque, dans le résultat,le décalage « vers la droite » de la position des éléments qui étaient situésaux positions p, p+ 1, . . . , n ;

– tsSupp(p, t), si t est un tableau de n éléments, c’est une opération qui dé-livre un tableau identique à t à l’exception la cellule située à la position p

Page 401: Structures de données et méthodes formelles ||

10. Tableaux flexibles 395

qui disparaît du résultat. La position p est définie si 1 ≤ p ≤ n, expressionqui préconditionne cette opération. Cette opération provoque, dans le ré-sultat, le décalage « vers la gauche » de la position des éléments qui étaientsitués aux positions p+ 1, . . . , n ;

– tsConc(t, t′), opération qui délivre un tableau flexible résultant de la conca-ténation des deux tableaux fortement flexibles t et t′ ;

– tsV al(p, t), si t est un tableau de n éléments, c’est une opération qui délivrel’élément situé en position p dans le tableau flexible t (position définie si1 ≤ p ≤ n, expression qui préconditionne cette opération) ;

– tsLong(t), opération qui délivre la longueur du tableau flexible t.

10.6 Flexibilité forte à droite : spécification dutype abstrait tsabst

Le type abstrait tsabst est spécifié formellement à la figure 10.3, page sui-vante. Le support abstrait définit tsAbst comme une fonction totale sur unintervalle d’entiers naturels débutant à 1. La spécification des opérations re-prend les descriptions ci-dessus en les formalisant. Ainsi par exemple l’opérationtsIns(v, p, t) délivre un tableau défini en trois parties. La première partie estidentique au fragment de t qui va de 1 à p − 1. La deuxième partie se réduit àla cellule rajoutée, qui contient v. La troisième partie est identique au secondfragment de t sur lequel est opéré un décalage vers la droite d’une position.

10.7 Flexibilité forte à droite : mise en œuvre parminimiers

10.7.1 PrincipeCette solution exige que les valeurs du tableau proviennent d’un ensemble sur

lequel est définie une structure d’ordre. Pour simplifier, nous considérons qu’ils’agit d’entiers naturels. Nous assimilons pour cela le support N au « type » N. Ils’agit d’une contrainte forte, qui ne facilite pas la généralisation à des tableauxà deux dimensions ou plus.

Le support concret de cette représentation est un minimier sur N. Il se dé-nomme tsMb et se spécifie formellement par :

1) 〈〉 ∈ tsMb2) r ∈ N ∧ g, d ∈ tsMb× tsMb ∧ a = 〈g, r, d〉 ∧ r = min(ens(a))

⇒a ∈ tsMb

La fonction ens(a) délivre l’ensemble des valeurs présentes dans le minimiera. Le schéma ci-dessous montre deux exemples de minimiers. L’exemple de droitemontre un minimier (très) déséquilibré puisqu’il s’agit d’un arbre filiforme. Lefait que le concept de minimier ne véhicule pas de notion d’équilibre laisse pré-sager des algorithmes dont la complexité au pire est en O(n).

Page 402: Structures de données et méthodes formelles ||

396 Structures de données et méthodes formelles

abstractTypetsabst(E) = (tsAbst, (tsCreer, tsIns, tsSupp, tsConc), (tsV al, tsLong))

uses N,N1

supportn ∈ N ∧ t ∈ 1 .. n→ e ⇔ t ∈ tsAbst(E)

operationsfunction tsCreer() ∈ tsAbst(E) = 1 .. 0�∅

;function tsIns(v, p, t) ∈ e× N1 × tsAbst(E) �→ tsAbst(E) =pre

p ∈ 1 ..max(dom(t)) + 1then1 .. p− 1� t �− {p �→ v} �− ((p ..max(dom(t))� t)� 1)

end;

function tsSupp(p, t) ∈ N1 × tsAbst(E) �� tsAbst(E) =pre

p ∈ dom(t)then1 .. p− 1� t �− ((p+ 1 ..max(dom(t))� t)�−1)

end;

function tsConc(t, t′) ∈ tsAbst(E)× tsAbst(E)� tsAbst(E) =t�− (t′� card(dom(t)))

;function tsV al(p, t) ∈ N1 × tsAbst(E) �→ e =pre

p ∈ dom(t)then

t(p)end

;function tsLong(t) ∈ tsAbst(E)→ N = max(dom(t))

end

Figure 10.3 – Spécification du type abstrait tsabst.tsabst représente les tableaux fortement flexibles à droite. Les inser-tions sont possibles sur toute position existante ainsi qu’à l’extrémitédroite. Les suppressions sont possibles sur tout l’intervalle de définition.L’opération de concaténation de deux tableaux est également spécifiée.

7

9

17 10

14

7

10

15 17

19

7

7

8

19

23

Page 403: Structures de données et méthodes formelles ||

10. Tableaux flexibles 397

La fonction d’abstraction A associe à chaque élément du support tsMb untableau dont le domaine est un intervalle qui débute en position 1. La fonctionw, définie comme fonction auxiliaire du type tsmb, délivre le poids (le nombred’éléments) d’un arbre tsMb. Un arbre vide correspond à un tableau vide. Leschéma ci-dessous montre comment un minimier non vide représente un tableaufortement flexible à droite. En supposant que nous sachions obtenir les tableauxreprésentés par les sous-arbres gauche et droit (hypothèse d’induction), le tableaufinal s’obtient en concaténant le premier tableau, la valeur issue de la racine etle second tableau décalé vers la droite de la longueur du premier tableau plusun.

C’est cette conversion qui est décrite par la fonction d’abstraction ci-dessous.

function A(a) ∈ tsMb� tsAbst =if a = 〈〉 →1 .. 0�∅

| a = 〈g, r, d〉 →A(g) �− {w(g) + 1 �→ r} �− A(d)�w(g) + 1

fi

Le calcul complet de cette solution est proposé à l’exercice 10.7.1. La seulefonction utilisée dans la représentation des opérations est la fonction w qui dé-livre le poids d’un arbre. Ainsi que nous l’avons déjà vu à plusieurs reprises,nous devons songer à renforcer la structure de données (cf. 6.5.5). La fonctionw est en O(1). Elle est donc décomposable sur la structure de données : il suf-fit d’enrichir chaque nœud par un champ destiné à recevoir le poids de l’arbrecorrespondant. Nous obtenons ainsi une solution pour les tableaux fortementflexibles à droite dont la complexité est au pire de O(n). En retenant l’hypo-thèse suivante : tableaux sans doublon de n éléments pour lesquels les n! ordres

7

9

17 10

14

7

10

13 17

19

17 9 14 10

1 2 3 4

13 10 17 7 19

1 2 3 4 5

17 9 14 10 7 13 10 17 7 19

1 2 3 4 5 6 7 8 9 10

hyp. d’induction

concaténation

Page 404: Structures de données et méthodes formelles ||

398 Structures de données et méthodes formelles

relatifs sont équiprobables, on montre (cf. [115, 116]) que la complexité moyennedes opérations est en O(log n).

10.7.2 Conclusion et remarques bibliographiques

La solution ébauchée ci-dessus pour les tableaux fortement flexibles avecconcaténation est due à J. Vuillemin [115, 116]. Dans ces documents fondateurs,la décomposition du poids sur la structure de données est faite d’emblée, et noncomme ici par raffinement. Dans [115] le type abstrait est appelé (abusivementselon notre terminologie) « liste linéaire » tandis que la structure de donnéesconcrète est dénommée « tournoi binaire de position (ou de rang) ». Dans [116]elle est présentée comme une variante d’arbres « à tout faire » : les arbres car-tésiens (cf. section 6.9.6).

L’atout principal de cette solution est de permettre une mise en œuvre rai-sonnablement efficace d’une structure aussi complexe que les tableaux fortementflexibles. Dans l’absolu, ses points faibles sont tout d’abord la complexité des opé-rations mais également l’obligation qu’il y a à travailler sur des valeurs dotéesd’une structure d’ordre total. Cependant on ne sait guère faire mieux aujour-d’hui.

À défaut de mettre la main sur le Graal des structures de données, les cher-cheurs se sont tournés vers des types abstraits moins ambitieux, en supprimantune ou plusieurs opérations du type abstrait « tableaux fortement flexibles »,ou en les remplaçant parfois par d’autres opérations mais toujours en recher-chant des performances les meilleures possibles. Le cas le plus typique est celuioù l’on supprime les opérations à adressage direct (consultation, modificationinsertion ou suppression d’un élément quelconque) tout en préservant les autresopérations. Le type abstrait obtenu, qui n’est plus un tableau, est traditionnel-lement dénommé « deque » (Double-Ended Queue) concaténable (si l’opérationde concaténation est autorisée). L’objectif étant alors d’obtenir des opérationsen temps constant, soit par une analyse de complexité classique soit par uneanalyse amortie. Parmi les références les plus intéressantes, citons [91, 72, 70].

Dans le cas où l’affaiblissement du type abstrait se fait simplement en suppri-mant l’opération de concaténation, certains des supports déjà utilisés à d’autresfins peuvent être réemployés. C’est par exemple le cas des Avl (cf. section 6.6),des files binomiales (cf. section 9.4), des files gloutonnes (cf. ce chapitre, exer-cice 10.4.7), etc.

Exercices

Exercice 10.7.1 Compléter la spécification et le calcul des opérations de la mise en œuvredes tableaux fortement flexibles par minimiers. Réfléchir à la décomposition de la fonction wsur la structure de données.

Exercice 10.7.2 Nous voulons introduire l’opération tsAff(v, p, t) dans le type abstraittsabst. Cette opération délivre un tableau flexible dans lequel l’élément en position p a commevaleur v, le reste du tableau étant inchangé. Spécifier l’opération abstraite. Spécifier l’opérationconcrète correspondante tsAff_mb(v, p, a), puis calculer une représentation en utilisant uncalcul direct.

Page 405: Structures de données et méthodes formelles ||

10. Tableaux flexibles 399

Exercice 10.7.3 Après avoir spécifié le type abstrait « tableau fortement flexible sans conca-ténation », développer une mise en œuvre sur la base de l’un des supports suivants : Avl, filebinomiale ou file gloutonne (cf. ce chapitre, exercice 10.4.7 pour les files gloutonnes).

Page 406: Structures de données et méthodes formelles ||

AnnexesRépertoire de propriétés

Page 407: Structures de données et méthodes formelles ||

Annexe A

Propriétés générales desensembles

Avertissement. La plupart des théorèmes et propriétés regroupés dans lesannexes ont été publiés sous cette forme dans l’ouvrage [3].

Propriétés des ensembles Condition Ident.

v ∈ (a ∪ b) ⇔ v ∈ a ∨ v ∈ b v ∈ s ∧ a ⊆ s ∧ b ⊆ s (A.1)

v ∈ (a ∩ b) ⇔ v ∈ a ∧ v ∈ b v ∈ s ∧ a ⊆ s ∧ b ⊆ s (A.2)

v ∈ (a− b) ⇔ v ∈ a ∧ v /∈ b v ∈ s ∧ a ⊆ s ∧ b ⊆ s (A.3)

v ∈ {w} ⇔ (v = w) v ∈ s ∧ w ∈ s (A.4)

v ∈ a ⇔ {v} ⊆ a v ∈ s ∧ a ⊆ s (A.5)

¬(v ∈ ∅) v ∈ s (A.6)

a ∪ b = b ∪ a a ⊆ s ∧ b ⊆ s (A.7)

(a ∪ b) ∪ c = a ∪ (b ∪ c) a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.8)

a ∪ b = a a ⊆ s ∧ b ⊆ s ∧ b ⊆ a (A.9)

((b− a) ∪ a) = b a ⊆ s ∧ b ⊆ s ∧ a ⊆ b (A.10)

(a ∪ b = ∅) ⇔ (a = ∅ ∧ b = ∅) a ⊆ s ∧ b ⊆ s (A.11)

⋃i ·(i ∈ u ∪ v | E) =

⎛⎜⎜⎝

⋃i ·(i ∈ u | E)

∪⋃i ·(i ∈ v | E)

⎞⎟⎟⎠

u ⊆ s ∧ v ⊆ s∧E expressionensembliste

(A.12)

⋃i ·(i ∈ u− v | E) =

⎛⎜⎜⎝

⋃i ·(i ∈ u | E)

−⋃i ·(i ∈ v | E)

⎞⎟⎟⎠

u ⊆ s ∧ v ⊆ s∧E expressionensembliste

(A.13)

⋃i ·(i ∈ u ∪ v | R[{i}]) =⎛

⎜⎜⎝⋃

i ·(i ∈ u | (u�R)[{i}])∪⋃i ·(i ∈ v | (v �R)[{i}])

⎞⎟⎟⎠

u ⊆ s ∧ v ⊆ s∧dom(R) ⊆ s∧R relation

(A.14)

⋃i ·(i = j | E) = [i := j]E i ∈ s ∧ j ∈ s (A.15)

Page 408: Structures de données et méthodes formelles ||

404 Structures de données et méthodes formelles

Propriétés des ensembles Condition Ident.

a− b = aa ⊆ s ∧ b ⊆ s

∧ a ∩ b = ∅(A.16)

(a ∪ b)− c = (a− c) ∪ (b− c) a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.17)

a− b = ∅a ⊆ s ∧ b ⊆ s

∧ a ⊆ b(A.18)

a ⊆ b ∧ b ⊆ c ⇒ a ⊆ c a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.19)

a ∩ b = b ∩ a a ⊆ s ∧ b ⊆ s (A.20)

(a ∩ b) ∩ c = a ∩ (b ∩ c) a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.21)

a ∩ a = a a ⊆ s (A.22)

a ∩ ∅ = ∅ a ⊆ s (A.23)

b ⊆ a ∧ a ∩ c = ∅ ⇒ b ∩ c = ∅ a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.24)

a ⊆ (b ∪ c) ∧ a ∩ c = ∅ ⇒ a ⊆ b a ⊆ s ∧ b ⊆ s ∧ c ⊆ s (A.25)

a ∩ b = a a ⊆ s ∧ b ⊆ s ∧ a ⊆ b (A.26)

{x | x ∈ u ∧ P} ∩ {x | x ∈ u ∧ ¬P} = ∅ P prédicat quelconque (A.27)

{x | x ∈ s ∧ x ∈ a} = a a ⊆ s (A.28)

Page 409: Structures de données et méthodes formelles ||

Annexe B

Propriétés des relationsbinaires

Propriétés des relations binaires Condition Ident.

u� {i, j | i ∈ s ∧ j ∈ t ∧ P}⇔

{i, j | i ∈ s ∧ j ∈ t ∧ i ∈ u ∧ P}u ⊆ s (B.1)

Propriétés de l’inverse Condition Ident.

r−1−1 = r r ∈ s↔ t (B.2)(p ; q)−1 = q−1 ; p−1 p ∈ s↔ t ∧ q ∈ t↔ u (B.3)id(s)−1 = id(s) (B.4)(u� r)−1 = r−1 � u u ⊆ s ∧ r ∈ s↔ t (B.5)(r � v)−1 = v � r−1 r ∈ s↔ t ∧ v ⊆ t (B.6)(u�− r)−1 = r−1 �− u u ⊆ s ∧ r ∈ s↔ t (B.7)(r �− v)−1 = v �− r−1 r ∈ s↔ t ∧ v ⊆ t (B.8)

(p�− q)−1 = (p−1 �− dom(q)) ∪ q−1 p ∈ s↔ t ∧ q ∈ s↔ t (B.9)

(p ∪ q)−1 = p−1 ∪ q−1 p ∈ s↔ t ∧ q ∈ s↔ t (B.10)(p ∩ q)−1 = p−1 ∩ q−1 p ∈ s↔ t ∧ q ∈ s↔ t (B.11)

(p− q)−1 = p−1 − q−1 p ∈ s↔ t ∧ q ∈ s↔ t (B.12){x �→ y}−1 = {y �→ x} x ∈ s ∧ y ∈ t (B.13)r−1 = ∅ r ∈ s↔ t ∧ r = ∅ (B.14)(s× t)−1 = t× s (B.15)

Page 410: Structures de données et méthodes formelles ||

406 Structures de données et méthodes formelles

Propriétés du domaine Condition Ident.

dom(f) = s f ∈ s→ t (B.16)dom(r−1) = ran(r) r ∈ s↔ t (B.17)dom(p ; q) = p−1[dom(q)] p ∈ s↔ t ∧ q ∈ t↔ u (B.18)dom(p ◦ q) = q−1[dom(p)] p ∈ t↔ u ∧ q ∈ s↔ t (B.19)

dom(p ; q) = dom(p)p ∈ s↔ t ∧ q ∈ t↔ u∧ran(p) ⊆ dom(q)

(B.20)

dom(id(s)) = s (B.21)dom(u� r) = u ∩ dom(r) u ⊆ s ∧ r ∈ s↔ t (B.22)dom(r � v) = r−1[v] r ∈ s↔ t ∧ v ⊆ s (B.23)dom(u�− r) = dom(r)− u u ⊆ s ∧ r ∈ s↔ t (B.24)dom(f �− v) = dom(f)− f−1[v] r ∈ s↔ t ∧ v ⊆ s (B.25)dom(p�− q) = dom(p) ∪ dom(q) p ∈ s↔ t ∧ q ∈ s↔ t (B.26)dom(p ∪ q) = dom(p) ∪ dom(q) p ∈ s↔ t ∧ q ∈ s↔ t (B.27)

dom(f ∩ g) = dom(f) ∩ dom(g) f ∈ s �→ t ∧ g ∈ s �→ t∧dom(f)� g = dom(g)� f

(B.28)

dom(f − g) = dom(f)− dom(g) f ∈ s �→ t ∧ g ∈ s �→ t∧dom(f)� g = dom(g)� f

(B.29)

dom({x �→ y}) = {x} x ∈ s ∧ y ∈ t (B.30)dom(r) = ∅ x ∈ s↔ t ∧ r = ∅ (B.31)dom(s× t) = s t = ∅ (B.32)

Propriétés du codomaine Condition Ident.

ran(f) = t f ∈ s �� t (B.33)

ran(r−1) = dom(r) r ∈ s↔ t (B.34)

ran(p ; q) = q[ran(p)] p ∈ s↔ t ∧ q ∈ t↔ u (B.35)

ran(p ; q) = ran(p)p ∈ s↔ t ∧ q ∈ t↔ u

dom(q) ⊆ ran(p)(B.36)

ran(id(s)) = s (B.37)

ran(u� r) = r[u] u ⊆ s ∧ r ∈ s↔ t (B.38)

ran(u� v) = ran(r) ∩ v r ∈ s↔ t ∧ v ⊆ t (B.39)

ran(u�− r) = ran(r)− r[u] u ⊆ s ∧ r−1 ∈ t �→ s (B.40)

ran(u�− v) = ran(r)− v r ∈ s↔ t ∧ v ⊆ t (B.41)

ran(p�− q) = ran(dom(q)�− p) ∪ ran(q) p ∈ s↔ t ∧ q ∈ s↔ t (B.42)

ran(p ∪ q) = ran(p) ∪ ran(q) p ∈ s↔ t ∧ q ∈ s↔ t (B.43)

ran(p ∩ q) = ran(p) ∩ ran(q)p−1 ∈ t �→ s ∧ q−1 ∈ t �→ s

q � ran(p) = p� ran(q)(B.44)

Page 411: Structures de données et méthodes formelles ||

B. Propriétés des relations binaires 407

Propriétés du codomaine Condition Ident.

ran(p− q) = ran(p)− ran(q)p−1 ∈ t �→ s ∧ q−1 ∈ t �→ s

q � ran(p) = p� ran(q)(B.45)

ran({x �→ y}) = {y} x ∈ s ∧ y ∈ t (B.46)

ran(r) = ∅ r ∈ s↔ t ∧ r = ∅ (B.47)

ran(s× t) = t s �= ∅ (B.48)

Propriétés de l’image Condition Ident.

(p ; q)[u] = q[p[u]] p ∈ s↔ t ∧ q ∈ t↔ v ∧ u ⊆ s (B.49)(r ; r−1)[u] = u r−1 ∈ t �→ s ∧ u ⊆ dom(r) (B.50)id(u)[v] = u ∩ v u ⊆ s ∩ v ⊆ s (B.51)(u� r)[v] = r[u ∩ v] u ⊆ s ∧ r ∈ s↔ t ∧ v ⊆ s (B.52)(r � v)[u] = r[u] ∩ v r ∈ s↔ t ∧ v ⊆ t ∧ u ⊆ s (B.53)(u�− r)[v] = r[u− v] u ⊆ s ∧ r ∈ s↔ t ∧ v ⊆ s (B.54)(r �− v)[u] = r[u]− v r ∈ s↔ t ∧ v ⊆ t ∧ u ⊆ s (B.55)(p�− q)[u] =

(dom(q)�− p)[u] ∪ q[u]p ∈ s↔ t ∧ q ∈ s↔ t ∧ u ⊆ s (B.56)

(p ∪ q)[u] = p[u] ∪ q[u] p ∈ s↔ t ∧ q ∈ s↔ t ∧ u ⊆ s (B.57)

(p ∩ q)[u] = p[u] ∩ q[u]p−1 ∈ t �→ s ∧ q−1 ∈ t �→ s ∧ u ⊆ s∧(p� ran(q)) = (q � ran(p))

(B.58)

(p− q)[u] = p[u]− q[u]p−1 ∈ t �→ s ∧ q−1 ∈ t �→ s ∧ u ⊆ s∧(p� ran(q)) = (q � ran(p))

(B.59)

{x �→ y}[u] = {y} x ∈ s ∧ y ∈ t ∧ u ⊆ s ∧ x ∈ u (B.60){x �→ y}[u] = ∅ x ∈ s ∧ y ∈ t ∧ u ⊆ s ∧ x /∈ u (B.61)

r[u] = ∅ r ∈ s↔ t ∧ (dom(r) ∩ u) = ∅ (B.62)(u× t)[v] = t u ⊆ s ∧ v ⊆ s ∧ u ∩ v = ∅ (B.63)(u× t)[v] = ∅ u ⊆ s ∧ v ⊆ s ∧ u ∩ v = ∅ (B.64)r[u ∪ v] = r[u] ∪ r[v] r ∈ s↔ t ∧ u ⊆ s ∧ v ⊆ s (B.65)r[u ∩ v] = r[u] ∩ r[v] r−1 ∈ t �→ s ∧ u ⊆ s ∧ v ⊆ s (B.66)r[u− v] = r[u]− r[v] r−1 ∈ t �→ s ∧ u ⊆ s ∧ v ⊆ s (B.67)f [{x}] = {f(x)} f ∈ s �→ t ∧ x ∈ dom(f) (B.68)r[∅] = ∅ r ∈ s↔ t (B.69)r[dom(r)] = ran(r) r ∈ s↔ t (B.70)r−1[ran(r)] = dom(r) r ∈ s↔ t (B.71)(p� v)[u] = p[u��−v] p ∈ s↔ t ∧ v ∈ Z ∧ u ⊆ s (B.72)p[u] = (p� v)[u�� v] p ∈ s↔ t ∧ v ∈ Z ∧ u ⊆ s (B.73)f [u] = ran(f) f ∈ s �→ t ∧ dom(f) ⊆ u (B.74)

Page 412: Structures de données et méthodes formelles ||

408 Structures de données et méthodes formelles

Propriétés de la composition Condition Ident.

r ; (p ; q) = r ; p ; q r ∈ s↔ t ∧ p ∈ t↔ u ∧ q ∈ u↔ v (B.75)

r ; id(v) = r � v r ∈ s↔ t ∧ v ⊆ t (B.76)

r ; id(t) = r r ∈ s↔ t (B.77)

r ; (v � p) = (r � v) ; p r ∈ s↔ t ∧ v ⊆ t ∧ p ∈ t↔ u (B.78)

r ; (p� w) = (r ; p)� w r ∈ s↔ t ∧ p ∈ t↔ u ∧ w ⊆ t (B.79)

r ; (v �− p) = (r �− v) ; p r ∈ s↔ t ∧ v ⊆ t ∧ p ∈ t↔ u (B.80)

r ; (p�− w) = (r ; p)�− w r ∈ s↔ t ∧ p ∈ t↔ u ∧ w ⊆ t (B.81)

f ; (p�− q) = (f ; p)�− (f ; q) f ∈ s �→ t ∧ p ∈ t↔ u ∧ q ∈ t↔ u (B.82)

r ; (p ∪ q) = (r ; p) ∪ (r ; q) r ∈ s↔ t ∧ p ∈ t↔ u ∧ q ∈ t↔ u (B.83)

f ; (p ∩ q) = (f ; p) ∩ (f ; q) f ∈ s �→ t ∧ p ∈ t↔ u ∧ q ∈ t↔ u (B.84)

f ; (p− q) = (f ; p)− (f ; q) f ∈ s �→ t ∧ p ∈ t↔ u ∧ q ∈ t↔ u (B.85)

r ; {x �→ y} = r−1[{x}]× {y} r ∈ s↔ t ∧ x ∈ t ∧ y ∈ u (B.86)

r ; p = ∅ r ∈ s↔ t ∧ p ∈ t↔ u ∧ p = ∅ (B.87)

r ; (u× v) = r−1[u]× v r ∈ s↔ t ∧ u ⊆ t (B.88)

id(u) ; r = u� r u ⊆ s ∧ r ∈ s↔ t (B.89)

id(s) ; r = r r ∈ s↔ t (B.90)

(u� p) ; r = u� (p ; r) u ⊆ s ∧ p ∈ s↔ t ∧ r ∈ t↔ u (B.91)

(p� v) ; r = p ; (v � r) p ∈ s↔ t ∧ v ⊆ t ∧ r ∈ t↔ u (B.92)

(u�− p) ; r = u�− (p ; r) u ⊆ s ∧ p ∈ s↔ t ∧ r ∈ t↔ u (B.93)

(p�− v) ; r = p ; (v �− r) p ∈ s↔ t ∧ v ⊆ t ∧ r ∈ t↔ u (B.94)

(p�− q) ; r = (p ; r)�− (q ; r)p ∈ s↔ t ∧ q ∈ s↔ t∧r ∈ t↔ u ∧ ran(q) ⊆ dom(r)

(B.95)

(p ∪ q) ; r = (p ; r) ∪ (q ; r) p ∈ s↔ t ∧ q ∈ s↔ t ∧ r ∈ t↔ u (B.96)

(p ∩ q) ; r = (p ; r) ∩ (q ; r) p ∈ s↔ t ∧ q ∈ s↔ t ∧ r−1 ∈ u �→ t (B.97)

(p− q) ; r = (p ; r)− (q ; r) p ∈ s↔ t ∧ q ∈ s↔ t ∧ r−1 ∈ u �→ t (B.98)

{x �→ y} ; r = {x} × r[{y}] x ∈ s ∧ y ∈ t ∧ r ∈ t↔ u (B.99)

p ; r = ∅ p ∈ s↔ t ∧ r ∈ t↔ u ∧ p = ∅ (B.100)

(u× v) ; r = u× r[v] v ⊆ s ∧ r ∈ s↔ t (B.101)

f−1 ; f = id(ran(f)) f ∈ s �→ t (B.102)

r ; r−1 = id(dom(r)) r−1 ∈ t �→ s (B.103)

id(u) ; id(v) = id(u ∩ v) u ⊆ s ∧ v ⊆ s (B.104)

Propriétés de la restriction Condition Ident.u� r = r u ⊆ s ∧ r ∈ s↔ t ∧ dom(r) ⊆ u (B.105)u� r = r � r[u] u ⊆ s ∧ r−1 ∈ t �→ s (B.106)u� (r ; p) = (u� r) ; p u ⊆ s ∧ r ∈ s↔ t ∧ p ∈ t↔ u (B.107)u� id(v) = id(u ∩ v) u ⊆ s ∧ u ⊆ s (B.108)u� (v � r) = (u ∩ v)� r u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.109)u� (r � w) = (u� r)� w u ⊆ s ∧ r ∈ s↔ t ∧ w ⊆ t (B.110)

Page 413: Structures de données et méthodes formelles ||

B. Propriétés des relations binaires 409

Propriétés de la restriction Condition Ident.u� (v �− r) = (u− v)� r u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.111)u� (r �− w) = (u� r)�− w u ⊆ s ∧ r ∈ s↔ t ∧ w ⊆ t (B.112)u� (p�− q) = (u� p)�− (u� q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.113)u� (p ∪ q) = (u� p) ∪ (u� q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.114)u� (p ∩ q) = (u� p) ∩ (u� q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.115)u� (p− q) = (u� p)− q u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.116)u� {x �→ y} = {x �→ y} u ⊆ s ∧ x ∈ s ∧ y ∈ t ∧ x ∈ u (B.117)u� {x �→ y} = ∅ u ⊆ s ∧ x ∈ s ∧ y ∈ t ∧ x /∈ u (B.118)

u� r = ∅u ⊆ s ∧ r ∈ s↔ t∧dom(r) ∩ u = ∅

(B.119)

u� (v × t) = (u ∩ v)× t u ⊆ s ∧ v ⊆ s (B.120)(u ∪ v)� r = (u� r) ∪ (v � r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.121)(u ∩ v)� r = (u� r) ∩ (v � r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.122)(u− v)� r = (u� r)− (v � r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.123)dom(r)� r = r r ∈ s↔ t (B.124)f−1[v]� f = f � v f ∈ s �→ t ∧ v ⊆ t (B.125){x}� r = {x} × r[{x}] x ∈ s ∧ r ∈ s↔ t (B.126){x}� f = {x �→ f(x)} x ∈ s ∧ f ∈ s �→ t ∧ x ∈ dom(f) (B.127)∅� r = ∅ r ∈ s↔ t (B.128)

Propriétés de l’antirestriction Condition Ident.

u�− r = ru ⊆ s ∧ r ∈ s↔ t∧dom(r) ∩ u = ∅

(B.129)

u�− r = r �− r[u] u ⊆ s ∧ r−1 ∈ t �→ s (B.130)

u�− (r ; p) = (u�− r) ; p u ⊆ s ∧ r ∈ s↔ t ∧ p ∈ t↔ u (B.131)

u�− id(v) = id(v − u) u ⊆ s ∧ v ⊆ s (B.132)

u�− (v � r) = (v − u)� r u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.133)

u�− (r � w) = (u�− r)� w u ⊆ s ∧ r ∈ s↔ t ∧ w ⊆ t (B.134)

u�− (v �− r) = (u ∪ v)�− r u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.135)

u�− (r �− w) = (u�− r)�− w u ⊆ s ∧ r ∈ s↔ t ∧ w ⊆ t (B.136)

u�− (p�− q) = (u�− p)�− (u�− q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.137)

u�− (p ∪ q) = (u�− p) ∪ (u�− q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.138)

u�− (p ∩ q) = (u�− p) ∩ (u�− q) u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.139)

u�− (p− q) = (u�− p)− q u ⊆ s ∧ p ∈ s↔ t ∧ q ∈ s↔ t (B.140)

u�− {x �→ y} = {x �→ y} u ⊆ s ∧ x ∈ s ∧ y ∈ t ∧ x /∈ u (B.141)

u�− {x �→ y} = ∅ u ⊆ s ∧ x ∈ s ∧ y ∈ t ∧ x ∈ u (B.142)

u�− r = ∅ u ⊆ s ∧ r ∈ s↔ t ∧ dom(r) ⊆ u (B.143)

u�− (v × t) = (v − u)× t u ⊆ s ∧ v ⊆ s (B.144)

(u ∪ v)�− r = (u�− r) ∩ (v �− r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.145)

(u ∩ v)�− r = (u�− r) ∪ (v �− r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.146)

(u− v)�− r = (u�− r) ∪ (v � r) u ⊆ s ∧ v ⊆ s ∧ r ∈ s↔ t (B.147)

Page 414: Structures de données et méthodes formelles ||

410 Structures de données et méthodes formelles

Propriétés de l’antirestriction Condition Ident.

dom(r)�− r = ∅ r ∈ s↔ t (B.148)

f−1[v]�− f = f �− v f ∈ s �→ t ∧ v ⊆ t (B.149)

∅�− r = r r ∈ s↔ t (B.150)

Propriétés de la corestriction Condition Ident.

f � u = fu ⊆ t ∧ f ∈ s↔ t ∧ran(f) ⊆ u

(B.151)

(f ∪ g)� u = (f � u) ∪ (g � u) f ∈ s↔ t ∧ g ∈ s↔ t ∧ u ⊆ t (B.152)(f − g)� u = (f � u)− g f ∈ s↔ t ∧ g ∈ s↔ t ∧ u ⊆ t (B.153){x �→ y}� u = {x �→ y} x ∈ s ∧ y ∈ t ∧ u ⊆ t ∧ y ∈ u (B.154){x �→ y}� u = ∅ x ∈ s ∧ y ∈ t ∧ u ⊆ t ∧ y /∈ u (B.155)(f � u)�− (g � u) = (f �− g)� u f ∈ s↔ t ∧ g ∈ s↔ t ∧ u ⊆ t (B.156)∅� f = ∅ f ∈ s↔ t (B.157)ran(f� v) = ran(f) v ∈ Z ∧ f ∈ s↔ t (B.158)

Propriétés de la surcharge Condition Ident.

p�− (q �− r) = p�− q �− r p ∈ s↔ t ∧ q ∈ s↔ t ∧ r ∈ s↔ t (B.159)

p�− q = p ∪ qp ∈ s↔ t ∧ q ∈ s↔ t∧dom(q)� p = dom(p)� q

(B.160)

∅�− r = r r ∈ s↔ t (B.161)

r �−∅ = r r ∈ s↔ t (B.162)

({x} × v)�− {x �→ y} = {x �→ y} x ∈ s ∧ v ⊆ t ∧ y ∈ t (B.163)

(u× {y})�− {x �→ y} =

(u ∪ {x})× {y}u ⊆ s ∧ y ∈ t ∧ x ∈ s (B.164)

p�− q = qp ∈ s↔ t ∧ q ∈ s↔ t ∧dom(p) ⊆ dom(q)

(B.165)

(p− q)�− r = p�− r

p ∈ s↔ t ∧ q ∈ s↔ t ∧r ∈ s↔ t∧dom(q) ⊆ dom(r)

(B.166)

Propriétés de l’identité Condition Ident.

id(u ∪ v) = id(u) ∪ id(v) u ⊆ s ∧ v ⊆ s (B.167)id(u ∩ v) = id(u) ∩ id(v) u ⊆ s ∧ v ⊆ s (B.168)id(u− v) = id(u)− id(v) u ⊆ s ∧ v ⊆ s (B.169)id({x}) = {x �→ x} x ∈ s (B.170)id(u) = ∅ u ⊆ s ∧ u = ∅ (B.171)

Page 415: Structures de données et méthodes formelles ||

Annexe C

Propriétés des fonctions

Propriétés de l’évaluation Condition Ident.

(x, f(x)) ∈ f f ∈ s �→ t ∧ x ∈ dom(f) (C.1)

λx ·(x ∈ s | E) ∈ s→ t ∀x ·(x ∈ s⇒ E ∈ t) (C.2)

λx ·(x ∈ s | E)(V ) = [x := V ]E ∀x ·(x ∈ s⇒ E ∈ t) ∧ V ∈ s (C.3)

λx ·(x ∈ s ∧ P | E)(V ) = [x := V ]E∀x ·(x ∈ s ∧ P ⇒ E ∈ t)∧V ∈ s ∧ [x := V ]P

(C.4)

(x, y) ∈ f ⇔ (x ∈ dom(f) ∧ y = f(x)) f ∈ s �→ t (C.5)

f−1(f(x)) = x f ∈ s �� x ∈ dom(f) (C.6)

(p ; q)(x) = q(p(x)) p ∈ s �→ t ∧ q ∈ t �→ u ∧ x ∈ dom(p ; q) (C.7)

id(s)(x) = x x ∈ s (C.8)

(u � f)(x) = f(x) u ⊆ s ∧ f ∈ s �→ t ∧ x ∈ u ∩ dom(f) (C.9)

(f � v)(x) = f(x) f ∈ s �→ t ∧ v ⊆ t ∧ x ∈ f−1[v] (C.10)

(u �− f)(x) = f(x) u ⊆ s ∧ f ∈ s �→ t ∧ x ∈ dom(f)− u (C.11)

(f �− v)(x) = f(x) f ∈ s �→ t ∧ v ⊆ t ∧ x ∈ dom(f)− f−1[v] (C.12)

(f �− g)(x) = f(x)f ∈ s �→ t ∧ g ∈ s �→ t∧x ∈ dom(f)− dom(g)

(C.13)

(f �− g)(x) = g(x) f ∈ s �→ t ∧ g ∈ s �→ t ∧ x ∈ dom(g) (C.14)

(f ∪ g)(x) = f(x)f ∈ s �→ t ∧ g ∈ s �→ t

dom(g) � f = dom(f) � g ∧ x ∈ dom(g)(C.15)

(f − g)(x) = f(x) f ∈ s �→ t ∧ g ∈ s �→ t ∧ x ∈ dom(f − g) (C.16)

{x �→ y}(x) = y x ∈ s ∧ y ∈ t (C.17)

(u× {y})(x) = y u ⊆ s ∧ x ∈ u ∧ y ∈ t (C.18)

x ∈ dom(f)⇔ (x, f(x)) ∈ f x ∈ s ∧ f ∈ s �→ t (C.19)

x ∈ dom(f � u)⇔(x ∈ dom(f) ∧ f(x) ∈ u)

f ∈ s �→ t ∧ x ∈ s ∧ u ⊆ t (C.20)

(f� v)(p) = f(p− v) v ∈ Z ∧ f ∈ s↔ t ∧ p ∈ dom(f� v) (C.21)

f(v : (v ∈ dom(f) ∧ f(v) = c)) = c c ∈ ran(f) ∧ f ∈ s �→ t (C.22)

Page 416: Structures de données et méthodes formelles ||

Annexe D

Propriétés des entiers

Propriétés des relatifs Condition Ident.

min({a}) = a a ∈ Z (D.1)min({a, b}) = a a ∈ Z ∧ b ∈ Z ∧ a ≤ b (D.2)min({a, b}) = b a ∈ Z ∧ b ∈ Z ∧ b ≤ b (D.3)a < min(u)⇒ a /∈ u u ⊂ Z ∧ a ∈ Z (D.4)min({a}) = min({∞, a}) a ∈ Z (D.5)min({a,min({b, c})})= min({min({a, b}), c})

a ∈ Z ∧ b ∈ Z ∧ c ∈ Z (D.6)

max({a}) = a a ∈ Z (D.7)max({a, b}) = a a ∈ Z ∧ b ∈ Z ∧ b ≤ a (D.8)max({a, b}) = b a ∈ Z ∧ b ∈ Z ∧ a ≤ b (D.9)max(u ∪ v) = max({max(u),max(v)}) u ⊂ Z ∧ v ⊂ Z (D.10)max(u ∪ {a}) = max({max(u), a}) u ⊂ Z ∧ a ∈ Z (D.11)a > max(u)⇒ a /∈ u u ⊂ Z ∧ a ∈ Z (D.12)max({a}) = max({−∞, a}) a ∈ Z (D.13)max({a,max({b, c})})= max({max({a, b}), c})

a ∈ Z ∧ b ∈ Z ∧ c ∈ Z (D.14)

m .. m = {m} m ∈ Z (D.15)

m .. n = ∅m ∈ Z ∧ n ∈ Z ∧m ≥ n+ 1

(D.16)

m .. n = (m .. k) ∪ (k + 1 .. n)m ∈ Z ∧ n ∈ Z∧k ∈ Z ∧ k ∈ m− 1 .. n

(D.17)

m .. n ∩ p .. q =

max({m, p}) ..min({n, q})m ∈ Z ∧ n ∈ Z∧p ∈ Z ∧ q ∈ Z∧

(D.18)

Page 417: Structures de données et méthodes formelles ||

414 Structures de données et méthodes formelles

Dans le tableau ci-dessous s ⊆ Z et v ∈ Z.

Propriétés du décalage Condition Ident.p� 0 = p p ∈ s↔ t (D.19)p� v = ∅ p ∈ s↔ t ∧ p = ∅ (D.20)(p� v)� v′ = p�(v + v′) v ∈ Z ∧ v′ ∈ Z ∧ p ∈ s↔ t (D.21)(p� v)−1 = p−1 ; (id(dom(p))� v)−1 p ∈ s↔ t (D.22)(p ; q)� v = (p� v) ; q p ∈ s↔ t ∧ q ∈ t↔ r (D.23)(u� p)� v = (u�� v)� (p� v) u ⊆ Z ∧ p ∈ s↔ t (D.24)(p� u)� v = (p� v)� u u ⊆ t ∧ p ∈ s↔ t (D.25)(u�− p)� v = (u�� v)�− (p� v) u ⊆ Z ∧ p ∈ s↔ t (D.26)(p�− u)� v = (p� v)�− u u ⊆ t ∧ p ∈ s↔ t (D.27)(p�− q)� v = (p� v)�− (q� v) p ∈ s↔ t ∧ q ∈ s↔ t (D.28)λx ·(x ∈ s | E)� v =

λx ·(x ∈ (s�� v) | [x := x− v]E)E une expression (D.29)

λx ·(x ∈ s ∧ P | E)� v =

λx ·(x ∈ (s�� v) ∧ [x := x− v]P | [x := x− v]E)

E une expression,P un prédicat

(D.30)

Dans le tableau ci-dessous s ⊆ Z, v ∈ Z et v′ ∈ Z.

Propriétés de la translation Condition Ident.a�� 0 = a a ⊆ s (D.31)(a�� v)�� v′ = a��(v + v′) a ⊆ s (D.32)dom(p)�� v = dom(p� v) p ∈ s↔ t (D.33)

Propriétés des parties entières Condition Ident.�n2 �+ �n2 � = n n ∈ Z (D.34)�x� ≤ y x, y ∈ R∗+ × R∗+ ∧ x ≤ y (D.35)

Page 418: Structures de données et méthodes formelles ||

Annexe E

Opérateurs et priorités

Le tableau ci-dessous récapitule les différents opérateurs, en précisant leurspriorités. Plus la priorité est élevée plus l’opérateur est prioritaire. À prioritéségales, les opérateurs s’associent à gauche, à l’exception de xy (élévation à lapuissance) et de · (séparateur de quantificateur) qui s’associent à droite.

Op. Description Pri. Op. Description Pri.∀ Quantificateur universel 25 ∃ Quantificateur existentiel 25λ Lambda expression 25 r−1 Relation inverse 23· Séparateur de quantificateur 22 − Moins unaire 21˜ Inversion de liste 21 ¬ Négation 21xy Puissance 20 · Multiplication 19÷, / Divisions 19 × Produit cartésien 19mod Modulo 19 + Addition 18− Soustraction 18 .. Intervalle 17 = Inégalité 16 ∩ Intersection 16� Intersection (sacs) 16 ∪ Union 16� Union (sacs) 16 − Différence 16− Différence (sacs) 16 � Addition (sacs) 16< Inférieur strict 16 ≤ Inférieur ou égal 16> Supérieur strict 16 ≥ Supérieur ou égal 16�− Surcharge 16 �− Soustraction de domaine 16�− Soustraction de codomaine 16 � Restriction de domaine 16� Restriction de codomaine 16 �→ Maplet 16� Décalage de domaine 16 �� Translation 16 Concaténation de listes 16 �→ Fonction partielle 13�� Surjection partielle 13 → Fonction totale 13� Surjection totale 13 ↔ Relation 13�� Injection partielle 13 � Injection totale 13

�� Bijection totale 13 ∈ Appartenance 12/∈ Non appartenance 12 �− Appartenance (sacs) 12 �− Non appartenance (sacs) 12 ⊆ Non inclusion 11 ⊂ Non inclusion stricte 11 ⊆ Inclusion 11� Inclusion (sacs) 11 ⊂ Inclusion stricte 11� Inclusion stricte (sacs) 11 ⇔ Équivalence 6= Égalité 6 ∧ Et logique 4

Page 419: Structures de données et méthodes formelles ||

416 Structures de données et méthodes formelles

Op. Description Pri. Op. Description Pri.∨ Ou logique 4 ⇒ Implication 3→ Conditionelle 2 : any 1; Composition de relations 1 ◦ Composition de relations 1| Séparateur 1 = Définition 0

Page 420: Structures de données et méthodes formelles ||

Bibliographie

[1] Groupe Algol de l’Afcet. Définition du langage algorithmique Algol 68.Hermann, Paris, 1972.

[2] NIST. Dictionary of algorithms and data structures. Site du NationalInstitute for Standards and Technology. URL http://xw2k.nist.gov/

dads//. Consulté le 8 juillet 2008.[3] Abrial J.-R. The B-Book: Assigning Programs to Meanings. Cambridge

University Press, 1996.[4] Abrial J.-R. Introduction à la méthode B. iut de Nantes, 1997. Cassettes

vhs.[5] Abrial Jean-Raymond. Modeling in Event-B. System and Software Ingi-

neering. Cambridge University Press, 2010.[6] Abrial Jean-Raymond and Mussat Louis. On using conditional defi-

nitions in formal theories. In 2nd International Conference of B and ZUsers, France, January 23–25, volume 2272 of Lecture Notes in ComputerScience, pages 242–269. Springer, 2002.

[7] Aho A. and Hopcroft J. Structures de données et algorithmes. Inter-Editions, 1987.

[8] Allen Brian andMunro Ian. Self-organizing binary search trees. Journalof the ACM, 25(4): 526–535, 1978.

[9] Arnold André and Guessarian Irène. Mathématiques pour l’informa-tique. Masson, 1997. 3e édition.

[10] Arsac J. Premières leçons de programmation. Cédic/F. Nathan, 1980.[11] Arsac J. Les bases de la programmation. Dunod, 1983.[12] Bayer R. andMcCreight Edward M. Organization and maintenance of

large ordered indexes. Acta Informatica, 1(3): 173–189, 1972.[13] Bentley Jon Louis. Multidimensional binary search trees used for asso-

ciative searching. Commun. ACM, 18(9): 509–517, 1975.[14] Berlioux P. and Bizard Ph. Algorithmique. Construction preuve et éva-

luation des programmes. Dunod Bordas, 1983.[15] Bird Richard S.,Morgan Carroll, andWoodcock Jim, editors. volume

669 of Lecture Notes in Computer Science, 1993. Springer.[16] Bitner James R. Heuristics that dynamically organize data structures.

Page 421: Structures de données et méthodes formelles ||

418 Structures de données et méthodes formelles

SIAM J. Comput., 8(1): 82–110, 1979.[17] Brassard Gilles and Bratley Paul. Fundamentals of algorithmics. Pear-

son – Prentice-Hall, Inc., 1996.[18] Brett D. and Flegg A. Spatial indexing. URL http://www.flegg.

net/brett/pubs/spatial/index.html.[19] Brown Mark R. Implementation and analysis of binomial queue algo-

rithms. SIAM J. Comput., 7(3): 298–319, 1978.[20] Burton F. Warren. An efficient functional implementation of fifo queues.

Inf. Process. Lett., 14(5): 205–206, 1982.[21] Challab D.J. Implementation of flexible arrays using balanced trees.

Comput. J., 34(5): 386–396, 1991.[22] Chanzy P., Devroye L., and Zamora-cura C. Analysis of range search

for random k-d trees. Acta Informatica, 37(4–5): 355–383, 1999.[23] Chuang Tyng-Ruey. Fully persistent arrays for efficient incremental up-

dates and voluminous reads. In 4th European Symposium on Programming,pages 1–20, 1992.

[24] Cohen E. Programming in the 1990s, an Introduction to the Calculationof Programs. Springer-Verlag, 1990.

[25] Cormen T., Leiserson Ch., Rivest R., and Stein C. Introduction toAlgorithms. Mit Press, McGraw-Hill Book Company, 2005. Sixth printing.

[26] Csürös M. Cours de structures de données, 2006. URLhttp://www.iro.umontreal.ca/~csuros/IFT2010/materiel/arbres-

pp31_42.pdf. Consulté le 23 septembre 2009.[27] Derniame J.-C. and Finance J.-P. Types abstraits de données : spéci-

fication, utilisation et réalisation. CRIN, Nancy, École d’été de l’Afcet,Monastir, 79.E.57, 1979.

[28] Dielissen Victor J. andKaldewaij Anne. A simple, efficient, and flexibleimplementation of flexible arrays. In Mathematics of Program Construc-tion, MPC’95, Proceedings, volume 947 of Lecture Notes in ComputerScience, pages 232–241, 1995.

[29] Dietz P.F. Fully persistent arrays (extended array). In WADS ’89: Pro-ceedings of the Workshop on Algorithms and Data Structures, volume 382,pages 67–74, London, UK, 1989. Springer-Verlag.

[30] Dijkstra E.W. A Discipline of Programming. Prentice-Hall, 1976.[31] Dijkstra E.W. and FeijenW.H.J. A Method of Programming. Addison-

Wesley Longman Publishing Co., Inc., Boston, MA, USA, 1988.[32] Ducrin A. Programmation. Du problème à l’algorithme, volume 1. Dunod,

1984.[33] Ducrin A. Programmation. De l’algorithme au programme, volume 2.

Dunod, 1984.[34] Enbody R. J. and Du H.C. Dynamic hashing schemes. ACM Computing

Surveys, 20(2): 85–113, 1988.[35] Finkel Raphael A. and Bentley Jon Louis. Quad trees: A data structure

Page 422: Structures de données et méthodes formelles ||

Bibliographie 419

for retrieval on composite keys. Acta Inf., 4(1): 1–9, 1974.[36] Foster C.C. Information storage and retrieval using Avl trees. In ACM.

20th National Conference, Session 8, 1965.[37] Fraenkel A.B. Systems of numeration. CH1892-9. IEEE, 1983.[38] Fredkin Edward. Trie memory. Commun. ACM, 3(9): 490–499, 1960.[39] Friedman J.H., Bentley J., and Finkel R. An algorithm for finding

best matches in logarithmic expected time. Technical Report CS-TR-75-482, Stanford University, Department of Computer, July 1976.

[40] Gaudel M.-C., Soria M., and Froidevaux C. Types de données etalgorithmes. Informatique. McGraw-Hill, 1990.

[41] Gibbons J. Calculating functional programs. In Keiichi Nakata, editor,Proceedings of ISRG/SERG Research Colloquium. School of Computingand Mathematical Sciences. Oxford Brookes University, November 1997.

[42] Gibbons J. Calculating functional programs. In Backhouse R., CroleR., and Gibbons J., editors, Algebraic and Coalgebraic Methods in theMathematics of Program Construction, volume 2297 of Lecture Notes inComputer Science, pages 148–203. Springer-Verlag, 2002.

[43] Graham R.L., Knuth D.E., and Patashnik O. Mathématiques concrètes– Fondations pour l’informatique. Édition Vuibert, 2003. Seconde édition.

[44] Gries D. and Schneider F.B. A logical approach to discrete math.Springer-Verlag New York, Inc., New York, NY, USA, 1994.

[45] Gries David. The Science of Programming. Springer-Verlag, 1981. Secondprinting.

[46] Guttag John V. and Horning James J. The algebraic specification ofabstract data types. Acta Inf., 10: 27–52, 1978.

[47] Guyomard M. EB: A constructive approach for the teaching of datastructures. In Formal Methods in Computer Science Education, Satelliteworkshop of ETAPS, pages 25–36, Budapest, Hungary, March 29th 2008.

[48] Guyomard M. The teaching of data structures : A balanced presentationof skew heaps. In The B method : from Research to Teaching, pages 45–64,Nantes, June 7th 2010.

[49] Guyomard M., Alain P., Hadjali A., Jaudoin H., and Smits G. Firstbalance sheet of a formal approach in the teaching of data structures. InThe B method: from Research to Teaching, pages 66–91, Nantes, June 16th2008.

[50] Habrias H. and Chauvet J.-Y. Introduction à la spécification formelleavec B. Technical report, iut de Nantes, Département Informatique, Mai2000. Version provisoire.

[51] Habrias H. and Frappier M. Software Specification Methods. interEdi-tions. Wiley-ISTE, May 2006.

[52] Heinz Steffen, Zobel Justin, andWilliams Hugh E. Burst tries : A fast,efficient data structure for string keys. ACM Transactions on InformationSystems, 20(2): 192–223, April 2002.

Page 423: Structures de données et méthodes formelles ||

420 Structures de données et méthodes formelles

[53] Hinze R. Functional pearls: Explaining binomial heaps. Journal of Func-tional Programming, 9(1): 93–104, January 1999.

[54] Hinze Ralf. Generalizing generalized tries. J. Funct. Program., 10(4) :327–351, July 2000.

[55] Hoare C.A.R. An axiomatic basis for computer programming. Comm.ACM 22, 12(10): 576–580, October 1969.

[56] Hoare C.A.R. Proof of correctness of data representations. Acta Inf., 1:271–281, 1972.

[57] Hoare C.A.R. An overview of some formal methods for program design.IEEE Computer, pages 85–91, 1987.

[58] Hofstadter D. Gödel, Escher, Bach : les brins d’une guirlande éternelle.interEditions, 1979.

[59] Hood Robert T. and Melville Robert C. Real time queue operations inpure LISP. Information Processing Letters, 13(2): 50–54, November 1981.

[60] Hoogerwoord R. The Design of functional Programs: a CalculationalApproach. PhD thesis, Eindhoven University of Technology, Eindhoven,The Netherlands, 1989.

[61] Hoogerwoord Rob R. A logarithmic implementation of flexible arrays.In Bird Richard S. et al. [15], pages 191–207.

[62] Hoogerwoord Rob R. Functional pearls – a symmetric set of efficientlist operations. J. Funct. Program., 2(4): 505–513, 1992.

[63] Hoogerwoord Rob R. A derivation of Huffman’s algorithm. In Bird

Richard S. et al. [15], pages 375–378.[64] Hoogerwoord Rob R. Programming by calculation. In Lucio Pa-

qui, Martelli Maurizio, and Navarro Marisa, editors, APPIA-GULP-PRODE, pages 407–426, 1996.

[65] Huffman David A. A method for the construction of minimum-redundancy codes. Proceedings of the Institute of Radio Engineers, 40(9):1098–1101, September 1952.

[66] Kaldewaij A. Programming : the derivation of algorithms. Prentice-Hall,Inc., Upper Saddle River, NJ, USA, 1990.

[67] Kaldewaij Anne. Programming : the derivation of algorithms, Teacher’sManual. Prentice-Hall, Inc., Upper Saddle River, NJ, USA, 1991.

[68] Kaldewaij Anne and Dielissen Victor J. Decomposable func-tions and leaf trees : A systematic approach. In Proceedings of theIFIP TC2/WG2.1/WG2.2/WG2.3 Working Conference on ProgrammingConcepts, Methods and Calculi, San Miniato, Italy, volume A-56 of IFIPTransactions, pages 3–17. North-Holland, 1994.

[69] Kaldewaij Anne and Schoenmakers Berry. The derivation of a tighterbound for top-down skew heaps. Information processing letters, 37(5) :265–271, March 1991.

[70] Kaplan H., Okasaki C., and Tarjan R.E. Simple confluently persistentcatenable lists. SIAM J. Comput., 30(3): 965–977, 2000.

Page 424: Structures de données et méthodes formelles ||

Bibliographie 421

[71] Kaplan Haim. Persistent data structures. In Mehta D. and Sahni S.,editors, In Handbook on Data Structures and Applications, pages 1.1–1.27.CRC Press, 2001.

[72] Kaplan Haim and Tarjan Robert E. Purely functional, real-time dequeswith catenation. J. ACM, 46(5): 577–603, 1999.

[73] King D. Functional binomial queues. In Proceedings of the Glasgow Work-shop on Functional Programming, pages 141–150, Ayr, Scotland, 1994.Springer-Verlag.

[74] Kleinberg J. and Tardos É. Algorithm Design. Person – Addison-Wesley, 2005.

[75] Knuth Donald E. The Art of Computer Programming, volume 3. Addison-Wesley, 1998.

[76] Krivine J.-L. Théorie des ensembles. Nouvelle bibliothèque mathéma-tique. Cassini, Paris, 1998.

[77] Lalement R. Logique réduction et résolution. Masson, Paris, 1990.[78] Larson P.-Å. Dynamic hashing. BIT, 18: 184–201, 1978.[79] Livercy C. Théorie des programmes, schémas, preuves, sémantique. Du-

nod Informatique, 1978.[80] Manber U. Introduction to Algorithms: A Creative Approach. Addison-

Wesley, Boston, MA, USA, 1989.[81] Martínez C. and Roura S. Randomized binary search trees. J. Assoc.

Comput. Mach., 45(2): 288–323, 1998.[82] McCreight Edward M. Priority search trees. SIAM J. Comput., 14(2):

257–276, 1985.[83] Monin J.-F. Introduction aux méthodes formelles. Hermes Science et

france telecom, 2000. 2e édition.[84] Moore Andrew. A tutorial on kd-trees. PhD thesis, University of

Cambridge Computer Laboratory Technical, Report No 209, 1991. URLhttp://www.cs.cmu.edu/$sim$awm/papers.html.

[85] Morris F.L. and Jones C.B. An early program proof by Alan Turing.IEEE Annals of the History of Computing, 6: 139–143, April 1984.

[86] Morrison Donald R. PATRICIA - practical algorithm to retrieve infor-mation coded in alphanumeric. J. ACM, 15(4): 514–534, October 1968.

[87] Myers Eugene W. An applicative random-access stack. Inf. Process.Lett., 17(5): 241–248, 1983.

[88] Nguyen D., Duprie K., and Zografou P. A multidimensional binarysearch tree for star catalog correlations. In Albrecht R., Hook R.N.,and Bushouse H.A., editors, In Astronomical Data Analysis software andSystems VII ASP Conference Series, volume 145, 1998.

[89] Nievergelt Jürg and Reingold Edward M. Binary search trees of boun-ded balance. In Proceedings of the fourth annual ACM symposium onTheory of computing, pages 33–43, 1972.

[90] Okasaki Chris. Purely functional random-access lists. Functional Pro-

Page 425: Structures de données et méthodes formelles ||

422 Structures de données et méthodes formelles

gramming Languages and Computer Architecture, pages 86–95, June 1995.[91] Okasaki Chris. Simple and efficient purely functional queues and deques.

J. Funct. Program., 5(4): 583–592, October 1995.[92] Okasaki Chris. Functional pearls – three algorithms on Braun trees. J.

Funct. Program., 7(6): 661–666, 1997.[93] Okasaki Chris. Purely functional data structures. Cambridge University

Press, Cambridge U.K. New York, 1998.[94] Olivié Henk J. A new class of balanced search trees: Half balanced binary

search trees. RAIRO Informatique Théorique, 16(1): 51–71, 1982.[95] O’NeillMelissa E. and Burton F. Warren. A new method for functional

arrays. J. Funct. Program., 7(5): 487–513, 1997.[96] Ottmann Thomas and Wood Derick. 1-2 brother trees or avl trees

revisited. Comput. J., 23(3): 248–255, 1980.[97] Polya G. Comment poser et résoudre un problème. Éditions Jacques

Gabay, 1965. Seconde édition, Nouveau tirage 2007.[98] Ramachandran Sridhar, Rajasekar K., and Pandu Rangan C. Pro-

babilistic data structures for priority queues (extended abstract). InSWAT, volume 1432 of Lecture Notes in Computer Science, pages 143–154, 1998.

[99] Samet Hanan. Deletion in two-dimensional quad trees. Commun. ACM,23(12): 703–710, 1980.

[100] Santoro Renaud. Vers des générateurs de nombres aléatoires uniformeset gaussiens à très haut débit. PhD thesis, Enssat (Université de Rennes 1)et Université Laval, Lannion France, Décembre 2009.

[101] Schoenmakers Berry. Data Structures and Amortized Complexity in aFunctional Setting. Doctoral dissertation, Eindhoven University of Tech-nology, Eindhoven, September 1992.

[102] Sedgewick R. Algorithms. Addison-Wesley, 1988.[103] Sedgewick R. and Flajolet P. Introduction à l’analyse d’algorithmes.

International Thomson publishing France, 1996.[104] Sedgewick Robert. Algorithmes en Java. Pearson education, 2004. Troi-

sième édition.[105] Seidel Raimund and Aragon Cecilia R. Randomized search trees. In

Proc. 30th Symp. Foundations of Computer Science (FOCS 1989), Wa-shington, D.C.: IEEE Computer Society Press, pages 540–545, 1989.

[106] Seidel Raimund and Aragon Cecilia R. Randomized search trees. Al-gorithmica, 16(4/5): 464–497, 1996.

[107] Sen S. and Tarjan R.E. Deletion without rebalancing in multiway searchtrees. In Algorithms and Computation, 20th International Symposium, vo-lume 5878 of Lecture Notes in Computer Science, pages 832–841. Springer,2009.

[108] Sen S. and Tarjan Robert E. Deletion without rebalancing in balancedbinary trees. In Proceedings of the Twenty-First Annual ACM-SIAM Sym-

Page 426: Structures de données et méthodes formelles ||

Bibliographie 423

posium on Discrete Algorithms, pages 1490–1499. SIAM, January 2010.[109] Sleator Daniel Dominic and Tarjan Robert Endre. Self-adjusting bi-

nary search trees. J. ACM, 32(3): 652–686, 1985.[110] Sleator Daniel Dominic and Tarjan Robert Endre. Self adjusting heaps.

SIAM J. Comput., 15(1): 52–69, 1986.[111] Stephenson C.J. A method for constructing binary search trees by ma-

king insertions at the root. International Journal of Computer and Infor-mation Sciences, 9(1): 15–29, February 1980.

[112] Tarjan R.E. Data structures and network algorithms. CBMS-NSF Re-gional Conference Series in Applied Mathematics, SIAM, 1983.

[113] Tarjan R.E. Amortized computational complexity. SIAM J. Alg. Disc.Meth., 6(2): 306–318, April 1985.

[114] Vuillemin Jean. A data structure for manipulating priority queues. Com-mun. ACM, 21(4): 309–315, 1978.

[115] Vuillemin Jean. A unifying look at data structures. Commun. ACM,23(4): 229–239, 1980.

[116] Vuillemin Jean. Structures de données. Inria, notes de cours, 1981.[117] Wolper P. Introduction à la calculabilité. Dunod, 2006. Troisième édition.[118] Woo M. Site qui comprend en particulier une généalogie des mises en

œuvre des files de priorité, consulté le 17 février 2010. URL http://www.

cs.cmu.edu/~maverick/Talks/2005-09-21%20A%20Tale.pdf.[119] Wordsworth John. Software Engineering with B. Addison-Wesley, Sep-

tember 1996.[120] Yu Cui. High-dimensional indexing: Transformational approaches to high-

dimensional range and similarity searches. Lecture Notes in ComputerScience, 2341, 2002.

[121] Wikipedia. Entrée wikipedia sur les caractéristiques du langage Java,consulté le 15 septembre 2008. URL http://fr.wikipedia.org/wiki/

Langage_Java.[122] Wikipedia. Entrée wikipedia concernant le nombre d’or, consulté le 24

septembre 2009. URL http://fr.wikipedia.org/wiki/Nombre_d’or.[123] Wikipedia. Entrée wikipedia sur les kd-arbres, consulté le 31 mars 2010.

URL http://en.wikipedia.org/wiki/Kd-tree.

Page 427: Structures de données et méthodes formelles ||

Index

SymbolesΩ, 111Φ, 125Θ, 111bCard, mult, bRan, 102:=, 23◦, ;, 33−, 102��, 101⊥, 21�−, �−, 102�, 21card, 37choice, 28dom, ran, 31�, �, �−, �−, 31�, �, �, �, 36� �, 100�→, 22O, 110max, min, 37N1, 37�−, 33�→, →, ��, �, ��, �, ��, 34P, 27�, !, �, �, , 102��, �, 38, 18

Aabr, 90, 150–168, 170, 177, 187, 190–

213, 245, 247, 252, 258–264,269–271, 273–310

Abrial J.-R., 1, 16, 18, 23, 43, 56, 79,104, 105, 199

adressage dispersé, voir hachageAho A., 113, 175algèbre, 11, 59, 60, 122

Allen B., 258analyse

amortie, voir complexité, amortiedes algorithmes, voir complexité,

107–128antécédent, 19Aragon C.R., 3, 269, 270arborescence, 84arbre

1d-arbre, 2962-3, 191, 215, 3922-3-4, 191, 2152d-arbre, 295–3104-aire, 309aléatoire, 154, 155, 157, 161, 167,

168, 182, 271, 263–271, 303ascendant, voir arbre, inversebinairede recherche, voir abr

binomial, 87, 90, 337cartésien, 33, 269, 270, 309, 398complet, 89, 96déployé, 3, 94, 148, 245–257, 270de Braun, 8, 377, 378–392de Catalan, 154, 155de codage, 359de démonstration, 19de Fibonacci, 360enraciné, voir arbre, libre, 84, 132,

274équilibré, 154, 155, 157, 192–209,

245, 295, 307–310, 374, 378étiqueté, 83–99, 329, 359, 381, 382externe, 77, 96, 96–99, 132, 148,

164, 170, 178–191, 243, 309,391, 392

feuille, voir arbre, externefiliforme, 89, 93, 365, 395

Page 428: Structures de données et méthodes formelles ||

426 Structures de données et méthodes formelles

généalogique, 360guidon, 132h-équilibré, 92, 93, 192–217inverse, 10kd-arbre, 273, 293–310libre, 84multidimensionnel, voir arbre, kd-

arbremultidirectionnel, voir arbre, kd-

arbren-aire, 77, 83, 88–95, 191, 217non étiqueté, voir arbre, étiqueténon ordonné, 77, 78, 83, 85–86,

87, 88, 274, 275p-équilibré, 191, 192, 196, 307parfait, 89, 330–331à gauche, 89, 330

partiellement étiqueté, voir arbre,étiqueté

planaire, 77, 78, 83, 87, 88plein, 89, 93, 96, 132, 194, 307quaternaire, 309récursion, 123randomisé, 148, 151, 270–271recouvrant, 328semi-équilibré, 215totalement étiqueté, voir arbre,

étiquetéarbre-trie, voir trieArnold A., 56, 105, 108, 117, 119Arsac J., 71asymptotique, 75, 99, 108–112, 113,

114, 117, 123, 136, 137, 154,167, 168, 192, 215, 269, 341,374

Avizienis A., 132Avl, 2, 6, 71, 75, 90, 94, 148, 151, 170,

177, 191, 192, 215–217, 241,273, 285, 292, 398

axiome, 19, 28

BB+-arbre, 99, 191, 238, 243, 286B-arbre, 2, 71, 90, 99, 116, 148, 151,

170, 177, 191, 192, 215, 216–243, 245, 286, 392

régulier, 217, 226

strict, 217, 221–223, 232, 233, 237,239, 240, 242

Bayer R., 243Bentley J., 303, 309, 310Berlioux P., 73bijection, voir fonction, bijectiveBitner J.R., 258Bizard Ph., 73Brassard G., 45, 123, 270Bratley P., 45, 123, 270Brett D., 309, 310Brown M.R., 360Burton F.W., 324, 391

Ccalcul

des prédicats, 22–26propositionnel, 21–22

cardinal, 108, 169, 241Challab D.J., 392Chanzy P., 309Chauvet J.-Y., 56Chuang T-R., 391Cohen E., 2, 10, 73collision, voir hachagecomplexité

amortie, 3, 8, 108, 123–128, 129–138, 245–257, 308, 313, 315,322–324, 328, 351–360, 362–374, 380, 398

asymptotique, voir asymptotiquede Kolmogorov, 107spatiale, 214, 269, 286, 287, 308,

309temporelle, 107, 117, 120, 154,

169, 188, 192, 243, 286, 292,308, 315, 346

comportement asymptotique, voirasymptotique

composition, 33, 384, 385compréhension, 27, 30, 41, 59, 61, 148concaténation, 78, 81, 82, 317–319, 321,

377, 394–396, 398conditionnelle, 25, 26, 27, 48, 52–54,

56, 154, 341, 346, 354, 355,357

conjonction, 17, 19, 21, 50

Page 429: Structures de données et méthodes formelles ||

Index 427

conséquent, 19Cormen T., 117, 119, 122, 123, 128,

138, 175couple, 22, 273, 293coupure, 20, 158, 295, 306coût amorti, voir complexité, amortieCsürös M., 194

Ddécalage, 38, 39, 391, 394, 395démonstration, 18–20décomposition, 74, 187, 188, 213, 358Derniame J.-C., 105Devroye L., 309diamètre, 92Dielissen V.J., 10, 75, 188, 191, 192,

391, 393Dietz P.F., 391Dijkstra E.W., 2, 16, 37, 73, 199, 380disjonction, 54domaine, 31, 34, 35, 80, 108, 109, 116,

314, 339, 377, 378, 380, 397Ducrin A., 71DuPrie K., 309

Eégalité, 15, 26–27, 28, 29Enbody R.J., 292équation

caractéristique, 119évaluation, 35, 50, 73expression, 18, 22–40, 47–57

gardée, 25, 25, 52–54préconditionnée, 48, 49, 50–53

FFeijen W.H.J., 2, 16, 37, 73Fibonacci L., 132, 360fichier, 79, 107, 238, 328

séquentiel, 79séquentiel indexé, 99, 238

filebinomiale, 132, 328, 331, 331–368,

392, 398d’attente, voir file, simple

de priorité, 3, 4, 8, 83, 87, 100, 132,245, 257, 327, 327–374

gloutonne, 132, 398simple, 4, 8, 10, 12, 78, 313, 313–

324Finance J.-P., 105Finkel R., 309, 310Flajolet P., 123Flegg A., 309, 310flexibilité, voir tableau, flexibilitéfonction

bijective, 17, 34, 60, 64d’abstraction, 10, 47, 64, 130, 140,

151, 172, 179, 196, 227, 259,298, 363

de hachage, 170, 171, 172, 174,175, 269, 271

de potentiel, 125, 125–138, 252,253, 257, 308, 322, 323, 351,368, 369, 374

injective, 17, 34, 39, 67, 140, 196,219, 258, 261, 268

partielle, 34, 49surjective, 34, 49, 140, 149, 171,

176, 196, 335, 363totale, 17, 34, 38, 39, 49

forêt-trie, voir trieformule, 22Foster C.C., 215Fraenkel A.B., 132Frappier M., 56Friedman J.H., 309Froidevaux C., 105, 108, 117, 119,

155, 175

GGaudelM.-C., 105, 108, 117, 119, 155,

175Gibbons J., 5Graham R.L., 108, 117, 156graphe, 7, 84, 92, 128, 328Gries D., 2, 73, 104, 105, 324Guessarian I., 56, 105, 108, 117, 119Guttag J.V., 105Guyomard M., 192

Page 430: Structures de données et méthodes formelles ||

428 Structures de données et méthodes formelles

HHabrias H., 56hachage, 2, 3, 7, 116, 148, 168, 169,

169–177, 269, 271, 309dynamique, 273, 287, 287–292externe, 169–170

hashing, voir hachagehauteur, voir rayon, 85Hinze R., 292Hoare C.A.R., 11, 16, 72, 75Hofstadter D., 20homomorphisme, 59, 60, 64, 151Hood R., 324Hoogerwoord R., 5, 10, 188, 257,

359, 392Horning J.J., 105Huffman A., 359

Iimage, 31, 33implication, 21, 54inclusion, 102induction, 18, 43, 63, 71–75

structurelle, 64, 133injection, voir fonction, injectiveintersection, 29, 30, 43, 102intervalle, 37, 39inverse, 31, 34

JJones C.B., 15

KKaldewaij A., 10, 73, 75, 138, 188,

191, 192, 391, 393Kaplan H., 7, 398King D.J., 360Kleinberg J., 359Knuth D.E., ix, 7, 79, 108, 117, 155,

156, 168, 175, 215, 243, 270,286, 292, 310, 374

Krivine J.-L., 57

LLalement R., 57, 105

lambda abstraction, 35langage de programmation, voir pro-

grammationlangage des prédicats, voir calcul, des

prédicatslangage propositionnel, voir calcul,

propositionnelLarson P.-Å., 176, 292Leiserson Ch., 117, 119, 122, 123,

128, 138, 175liste, 4–10, 43, 73, 74, 78, 77–91, 97–

100, 129–143, 154, 170, 177,215, 270, 273–275, 285, 313–324, 332–334, 341, 351, 355,392, 398

circulaire, 10doublement chaînée, 10

Livercy C., 73logarithme, 60, 96, 193, 241, 252, 253,

256

Mméthode de hachage, voir hachage ;

fonction, de hachageManber U., 71, 108, 117, 119Martínez C., 270maximier, voir minimierMcCreight E., 243, 309Melville M., 324Mersenne M., 132méthode du potentiel, voir complexité,

amortieminimier, 89, 258–270, 329, 377

binaire, 329, 330, 336binomial, 328, 331, 332, 332, 333–

339, 345de position, 191filiforme, 366gauchiste, 374oblique, 3, 245, 328, 362, 361–374parfait, 331parfait binaire, 328, 330

modélisation, 16, 40, 100, 123, 199Monin J.-F., 56, 105Morris F.L., 15Morrison D.R., 308, 309Munro I., 258

Page 431: Structures de données et méthodes formelles ||

Index 429

Mussat L., 56Myers E.W., 392

Nnégation, 21, 27, 282Nguyen D., 309Nievergelt J., 215non déterminisme, 18, 25, 29, 268, 269,

285notation asymptotique, voir asympto-

tiquenumération, 132

OO’Neill M.E., 391Okasaki C., 7, 11, 124, 132, 257, 324,

375, 392, 398Olivié H.J., 215opération, 11, 47–56Ottmann T., 216

Ppaire ordonnée, voir couplePandu Rangan C., 374Patashnik O., 108, 117, 156permutation, 109, 154, 155, 168, 182,

244, 269pile, 4, 315, 378plpc, 273, 274poids, 85, 93, 94point fixe, 43, 77, 79, 80, 91, 105Polya G., 45preuve, 18–20produit cartésien, 27, 80, 91, 97, 101,

149, 293, 294programmation, 4, 8, 9, 11, 61, 75, 114,

377, 380dynamique, 74, 188fonctionnelle, 5, 6, 9–11, 54, 177impérative, 2, 5, 6, 10, 11, 26, 71,

192, 214propriété caractéristique, 66, 68

Qquad tree, 309–310

quadrant, 309, 310quantificateur, 18, 23, 28, 38, 81, 183

existentiel, 30universel, 22, 23, 30

Rrègle d’inférence, 19, 20, 21, 23, 24, 26–

28, 48radix, 273raffinement, 4, 6, 11, 61, 63, 75, 99, 140raisonnement, 18–20Rajasekar K., 374rayon, 92, 92, 93, 94, 96, 154, 192–214,

217–241, 328, 331–360, 382recherche dichotomique, 150récurrence

complète, 44simple, 44

récursivité, 10, 73, 75Reingold E.M., 215Reiser M., ixrelation

binaire, 17, 31, 31–34, 108, 293–298, 309, 310

d’ordre, 35, 147, 216, 327Rivest R., 117, 119, 122, 123, 128, 138,

175rotation, 91–95, 151, 161–166, 192,

197–215, 221–225, 242, 245,258, 262, 265–267, 295

Roura S., 270

SSamet H., 310Schoenmakers B., 10, 73, 124, 126,

138, 257, 369, 374Sedgewick R., 123, 155, 175Seidel R., 3, 269, 270Sen S., 215, 243séquent, 18, 19, 20skew heap, voir minimier, obliqueSleator D.D., 124, 128, 257, 373, 374Soria M., 105, 108, 117, 119, 155, 175sous-arbre, voir arbrespécification, 1–11, 15–18, 25, 47, 59–

76, 107, 109

Page 432: Structures de données et méthodes formelles ||

430 Structures de données et méthodes formelles

splay tree, voir arbre, déployéSridhar R., 374Stein C., 117, 119, 122, 123, 128, 138,

175Stephenson C.J., 168substitution, 23, 25, 48surcharge, 33, 34, 383surjection, voir fonction, surjectivesystème de numération, voir numéra-

tion

Ttable de hachage, voir hachagetableau, 4, 6–9, 15, 17, 18, 38, 39, 53,

56, 74, 75, 83, 85, 88, 109,114–117, 172, 177, 217, 219,220, 226, 229–232, 285, 292,295, 308, 309, 313, 331, 360

flexibilité, 4, 8, 83, 99, 377, 380faible, 377, 378–382, 384–386,391–393

forte, 188, 191, 270, 315, 377,380, 391, 394, 395–399

taille, voir poidsTardos É., 359Tarjan R.E., 124, 128, 215, 243, 257,

373, 374, 398tas, 328–331technique de hachage, voir hachageterminaison, 48, 176théorie des ensembles, 2, 7, 9, 16, 18,

27–36, 43, 56, 57tournoi, voir minimiertranslation, 38, 39treap, 168, 177, 258–271

randomisé, 268–271trie, 86, 176, 275, 273–292, 359

Patricia, 286–287

Uunion, 29, 102

Vvecteur caractéristique, 148Vuillemin J., 161, 167, 168, 191, 269,

270, 309, 360, 392, 398

WWirth N., ixWolper P., 114Woo M., 360Wood D., 216Wordsworth J.B., 56

YYu C., 309

ZZamora-Cura C., 309Zografou P., 309

Page 433: Structures de données et méthodes formelles ||

Dans la même collectionHermes Science Publications

Projet et innovation, méthode HYBRID pour les projets innovants, par G. Poulain, 2000, 358 pages.

UMTS et partage de l’espace hertzien, par L. Genty, 2001, 309 pages.

Introduction aux méthodes formelles, par J.-F. Monin, 2001, 351 pages.

Objets communicants, sous la direction de C. Kintzig, G. Poulain, G. Privat, P.-N. Favennec, 2002, 396 pages.

Les réseaux de télécommunications, par R. Parfait, 2002, 524 pages.

Trafi c et performances des réseaux de télécoms, par G. Fiche, G. Hébuterne, 2003, 592 pages.

Le téléphone public, par F. Carmagnat, 2003, 310 pages.

Les cristaux photoniques, sous la direction de J.-M. Lourtioz, 2003, 310 pages.

Management des connaissances en entreprise, sous la direction de I. Boughzalaet J.-L. Ermine, 2004, 304 pages.

Les agents intelligents pour un nouveau commerce électronique, par C. Paraschiv, 2004, 235 pages.

De Bluetooth à Wi-Fi, par H. Labiod et H. Afi fi , 2004, 368 pages.

Les techniques multi-antennes pour les réseaux sans fi l, par P. Guguen et G. El Zein, 2004, 238 pages.

Les net-compagnies, sous la direction de T. Bouron, 2004, 200 pages.

Optique sans fil – propagation et communication, par O. Bouchet, H. Sizun, C. Boisrobert, F. de Fornel et P.-N. Favennec, 2004, 227 pages.

Interactions humaines dans les réseaux, par L. Lancieri, 2005, 224 pages.

La gestion des fréquences, par J.-M. Chaduc, 2005, 368 pages.

La nanophotonique, par H. Rigneault et al., 2005, 352 pages.

Le travail et les technologies de l’information, sous la direction d’E. Kessous et J.-L. Metzger, 2005, 320 pages.

Les innovations dans les télécoms mobiles, par E. Samuelides-Milesi, 2005, 264 pages.

CyberMonde, sous la direction de B. Choquet et D. Stern, 2005, 192 pages.

Page 434: Structures de données et méthodes formelles ||

432 Structures de données et méthodes formelles

Communications et territoires, par APAST, coordination de P.-N Favennec, 2006, 398 pages.

Administration électronique, par S. Assar et I. Boughzala, 2007, 336 pages.

Management des connaissances en entreprise (2e édition), sous la direction de I. Boughzala et J.-L. Ermine, 2007, 364 pages.

Communications Ultra Large Bande : le canal de propagation radioélectrique, par P. Pagani, T. Talam, P. Pajusco et B. Uguen, 2007, 246 pages.

Mathématiques pour les télécoms, par G. Fiche et G. Hébuterne, 2007, 532 pages.

Compatibilité électromagnétique : des concepts de base aux applications, par P. Degauque et A. Zeddam.

Volume 1. – 2007, 482 pages. Volume 2. – 2007, 360 pages.

Ingénierie de la collaboration : théories, technologies et pratiques, par I. Boughzala, 2007, 310 pages.

Physique des matériaux pour l’électronique, par A. Moliton, 2007, 436 pages.

Electronique et photo-électronique des matériaux et composants, par A. Moliton Volume 1.- 2008, 304 pages. Volume 2.- 2009, 360 pages

Inégalités numériques : clivages sociaux et modes d’appropriation des TIC, par F. Granjon, B. Lelong et J.-L. Metzger, 2009, 254 pages

Les réseaux domiciliaires et IPTV, par J.-G. Remy et Ch. Letamendia, 2009, 263 pages

Compression du signal – application aux signaux audio, par N. Moreau, 2009, 229 pages

Télécoms pour l’ingénierie du risque, par T. Tanzi et P. Perrot, 2009, 234 pages

Les antennes Ultra Large Bande, sous la direction de X. Begaud, 2010, 310 pages

De la radio logicielle à la radio intelligente, sous la direction de J. Palicot, 2010, 412 pages.

Les chambres réverbérantes en électromagnétisme, par B. Démoulin et P. Besnier, 2010, 422 pages.

Evolution des innovations dans les télécoms- histoire, techniques, acteurs et enjeux, par C. Rigault, 2010, 226 pages.

Le laser et ses applications 50 ans après son invention, sous la direction de P. Besnard et de P.-N. favennec, 2010, 377 pages.

Dunod

Electromagnétisme classique dans la matière, par Ch. Vassallo, 1980, 272 pages (épuisé).

Télécommunications : Objectif 2000, sous la direction de A. Glowinski, 1981, 300 pages (épuisé).

Page 435: Structures de données et méthodes formelles ||

Dans la même collection 433

Principes des communications numériques, par A.-J. Viterbi et J.-K. Omura. Traduit de l’anglais par G. Batail, 1982, 232 pages (épuisé).

Propagation des ondes radioélectriques dans l’environnement terrestre, par L. Boithias, 1984, 328 pages (épuisé).

Systèmes de télécommunications : bases de transmission, par P.-G. Fontolliet, 1984, 528 pages (épuisé).

Eléments de communications numériques. Transmission sur fréquence porteuse, par J.-C. Bic, D. Duponteil et J.C.Imbeaux (épuisé).

Tome 1. – 1986, 384 pages. Tome 2. – 1986, 328 pages.

Téléinformatique. transport et traitement de l’information dans les réseaux et systèmes téléinformatiques et télématiques, par C. Macchi, J.-F. Guilbert et al., 1987, 934 pages.

Les systèmes de télévision en ondes métriques et décimétriques, par L. Goussot, 1987, 376 pages (épuisé).

Programmation mathématique. théorie et algorithmes, par M. Minoux (épuisé). Tome 1. – 1987, 328 pages. Tome 2. – 1989, 272 pages.

Exploration informatique et statistique des données, par M. Jambu, 1989, 528 pages (épuisé).

Télématique : techniques, normes, services, coordonné par B. Marti, 1990, 776 pages.

Compatibilité électromagnétique : bruits et perturbations radioélectriques, sous la direction de P. Degauque et J. Hamelin, 1990, 688 pages.

Les faisceaux hertziens analogiques et numériques, par E. Fernandez et M. Mathieu, 1991, 648 pages.

Les télécommunications par fi bres optiques, par I et M. Joindot et douze co-auteurs, 1996, 768 pages.

Eyrolles

De la logique câblée aux microprocesseurs, par J.-M. Bernard et J. Hugon (épuisé). Tome 1. – Circuits combinatoires et séquentiels fondamentaux, avec la

collaboration de R. le Corvec, 1983, 232 pages. Tome 2. – Applications directes des circuits fondamentaux, 1983, 135 pages. Tome 3. – Méthodes de conception des systèmes, 1986, 164 pages. Tome 4. – Application des méthodes de synthèse, 1987, 272 pages.

La commutation électronique, par Grinsec (épuisé). Tome 1. – Structure des systèmes spatiaux et temporels, 1984, 456 pages. Tome 2. – Logiciel. Mise en œuvre des systèmes, 1984, 512 pages.

Optique et télécommunications. transmission et traitement optiques de l’information, par A. Cozannet, J. Fleuret, H. Maître et M. Rousseau, 1983, 512 pages (épuisé).

Page 436: Structures de données et méthodes formelles ||

434 Structures de données et méthodes formelles

Radarmétéorologie : télédétection active de l’atmosphère, par H. Sauvageot, 1982, 312 pages.

Probabilités, signaux, bruits, par J. Dupraz, 1983, 384 pages (épuisé).

Méthodes structurelles pour la reconnaissance des formes, par L. Miclet, 1984, 208 pages.

Introduction aux réseaux de fi les d’attente, par E. Gelenbe et G. Pujolle, 1985, 208 pages (épuisé).

Applications des transistors à effet de champ en arséniure de gallium, coordonné par R. Soares, J. Obregon et J. Graffeuil, 1984, 532 pages.

Pratique des circuits logiques, par J.-M. Bernard et J. Hugon, 1990, 480 pages (épuisé).

Théorie des guides d’ondes électromagnétiques, par Ch. Vassallo. Tome 1. – 1985, 504 pages. Tome 2. – 1985, 700 pages.

Conception des circuits intégrés MOS. Eléments de base, perspectives, par M. Cand, E. Demoulin, J.-L. Lardy et P. Senn, 1986, 472 pages.

Théorie des réseaux et systèmes linéaires, par M. Feldmann, 1987, 424 pages (épuisé).

Conception structurée des systèmes logiques, par J.-M. Bernard, 1987, 2e tirage, 400 pages.

Prévision de la demande de télécommunications. Méthodes et modèles, par N. Curien et M. Gensollen, 1989, 488 pages.

Systèmes de radiocommunications avec les mobiles, par J.-G. Rémy, J. Cueugniet et C. Siben, 1992, 2e édition, 668 pages.

Innovation, déréglementation et concurrence dans les télécommunications, par L. Benzoni et J. Hausman, 1993, 344 pages.

Les télécommunications : technologies, réseaux, services, par L.-J. Libois, 1994, 216 pages (épuisé).

Innovation et recherche en télécommunications. Progrès techniques et enjeux économiques, par M. Feneyrol et A. Guérard, 1994, 328 pages (épuisé).

Les ondes évanescentes en optique et en optoélectronique, par F. de Fornel, 1997, 312 pages.

Codesign, conception conjointe logiciel-matériel, par C.T.I. Comete, 1998, 204 pages.

Introduction au Data Mining. Analyse intelligente des données, par M. Jambu, 1998, 114 pages.

Méthodes de base de l’analyse des données, par M. Jambu, 1999, 412 pages et un CD-Rom.

Des télécoms à l’Internet : économie d’une mutation, par E. Turpin, 2000, 459 pages.

Ingénierie des connaissances – évolutions récentes et nouveaux défi s, par J. Charlet, M. Zacklad, G. Kassel et D. Bourigault, 2000, 610 pages (épuisé).

Emission photonique en milieu confi né, par A. Rahmani et F. de Fornel, 2000, 190 pages.

Page 437: Structures de données et méthodes formelles ||

Dans la même collection 435

Apprentissage artifi ciel, concepts et algorithmes, par A. Cornuéjols et L. Miclet, 2002, 590 pages.

Masson

Stéréophonie. Cours de relief sonore théorique et appliqué, par R. Condamines, 1978, 320 pages.

Les Réseaux pensants. Télécommunications et société, sous la direction de A. Giraud, J.-L. Missika et D. Wolton, 1978, 296 pages (épuisé).

Fonctions aléatoires, par A. Blanc-Lapierre et B. Picinbono, 1981, 440 pages.

Psychoacoustique. L’oreille recepteur d’information, par E. Zwicker et R. Feldtkeller. Traduit de l’allemand par C. Sorin, 1981, 248 pages.

Décisions en traitement du signal, par P.-Y. Arquès, 1982, 288 pages (épuisé).

Télécommunications spatiales, par des ingénieurs du CNES et du CNET (épuisé). Tome 1. – Bases théoriques, 1982, 432 pages. Tome 2. – Secteur spatial, 1983, 400 pages. Tome 3. – Secteur terrien. Systèmes de télécommunications par satellites, 1983,

468 pages.

Genèse et croissance des télécommunications, par L.-J. Libois, 1983, 432 pages (épuisé).

Le Vidéotex. Contribution aux débats sur la télématique, coordonné par Cl. Ancelin et M. Marchand, 1984, 256 pages.

Ecoulement du trafi c dans les autocommutateurs, par G. Hébuterne, 1985, 264 pages.

L’Europe des Postes et Télécommunications, par CI. Labarrère, 1985, 256 pages.

Traitement du signal par ondes élastiques de surface, par M. Feldmann et J. Hénaff, 1986, 400 pages (épuisé).

Théorie de l’information ou analyse diacritique des systèmes, par J. Oswald 1986, 488 pages.

Les vidéodisques, par G. Broussaud, 1986, 216 pages.

Les paradis informationnels : du minitel aux services de communication du futur, par M. Marchand et le SPES, 1987, 256 pages.

Systèmes et réseaux de télécommunication en régime stochastique, par G. Doyon, 1989, 704 pages.

Principes de traitement des signaux radar et sonar, par R. Le Chevalier, 1989, 280 pages.

Circuits intégrés en arséniure de gallium. Physique, technologie et règles de conception, par R. Castagné, J.-P. Duchemin, M. Gloanec et G. Rumelhard, 1989, 608 pages.

Analyse des signaux et fi ltrage numérique adaptatif, par M. Bellanger, 1989, 416 pages (épuisé).

Page 438: Structures de données et méthodes formelles ||

436 Structures de données et méthodes formelles

La parole et son traitement automatique, par Calliope, 1989, 736 pages.

Les fi ltres numériques. Analyse et synthèse des fi ltres unidimensionnels, par R. Boite et H. Leich, 1990, 3e édition, 432 pages.

Les modems pour transmission de données, par M. Stein, 1991, 384 pages.

La mesure de la fréquence des oscillateurs, par Chronos, 1992, 368 pages.

Traitements des signaux pour les systèmes sonar, par M. Bouvet, 1992, 504 pages.

Codes correcteurs d’erreurs. Une introduction au codage algébrique, par G. Cohen, Ph. Godlewski, J.-L. Dornstetter, 1992, 272 pages.

Complexité algorithmique et problèmes de communications, par J.-P. Barthélémy, G. Cohen et A. Lobstein. Préface de M. Minoux, 1992, 256 pages.

Gestion de réseaux : concepts et outils, par Arpège, 1992, 272 pages.

Les normes de gestion de réseau à l’ISO, par C. Lecerf et D. Chomel, 1993, 272 pages.

L’implantation ionique pour la microélectronique et l’optique, par P-N. Favennec, 1993, 532 pages.

Technique de compression des signaux, par N. Moreau, 1994, 288 pages.

Le RNIS. Techniques et atouts, par G. Dicenet, 1995, 3e édition, 312 pages.

Théorie structurale de la communication et société, par A.-A. Moles, 1995, 3e tirage, 296 pages.

Traitement numérique du signal : théorie et pratique, par M. Bellanger, 1995, 5e édition, 480 pages.

Télécommunication : réalités et virtualités : un avenir pour le XXe siècle, par M. Feneyrol, 1996, 256 pages.

Comprendre les méthodes formelles. Panorama et outils logiques, par J.-F. Monin, 1996, 320 pages (épuisé).

La programmation réactive : application aux systèmes communicants, par F. Boussinot, 1996, 280 pages.

Ingénierie des systèmes à microprocesseurs : application au traitement du signal et de l’image, par E. Martin et J.-L. Philippe, 1996, 320 pages.

Le régime juridique communautaire des services de télécommunications, par A. Blandin-Obernesser, 1996, 216 pages.

Paysage des réseaux de télécommunications, par R. Parfait, 1997, 376 pages (épuisé).

Le complexe de Babel. Crise ou maîtrise de l’information ?, par Jean Voge, 1997, 192 pages.

La télévision haute défi nition (TVHD), par A. Boukelif, 1997, 233 pages.

Documentation française

Les télécommunications françaises. Quel statut pour quelle entreprise ?, par G. Bonnetblanc, 1985, 240 pages.

Page 439: Structures de données et méthodes formelles ||

Dans la même collection 437

La communication au quotidien. De la tradition et du changement à l’aube de la vidéocommunication, par J. Jouët, avec la collaboration de N. Celle, 1985, 240 pages.

L’ordre communicationnel. Les nouvelles technologies de la communication : enjeux et stratégies, par F. du Castel, P. Chambat et P. Musso, 1989, 352 pages.

Histoire d’enfance. Les réseaux câblés audiovisuels en France, par J.-M. Charon, J.-P. Simon, avec la participation de B. Miège, 1989, 240 pages.

La communication plurielle : l’interaction dans les téléconférences, coordonné par P. Périn et M. Gensollen, 1992, 304 pages.

Métaphore et multimédia : concepts et applications, par G. Poulain, 1996, 240 pages.

Histoire comparée de stratégies de développement des télécommunications, par A.-M. Delaunay Macullan, 1997, 166 pages.

Presses polytechniqueset universitaires romandes

ADA avec le sourire, par J.-M. Bergé, L.-O. Donzelle, V. Olive et J. Rouillard, 1989, 400 pages.

Systèmes microprogrammés Une introduction au magiciel, par D. Mange, 1990, 384 pages.

Réseaux de neurones récursifs pour mémoires associatives, par Y. Kamp et M. Hasler, 1990, 244 pages.

VHDL, du langage à la modélisation, par R. Airiau, J.-M. Bergé, V. Olive et J. Rouillard, 1990, 576 pages (épuisé).

Traitement de l’information, sous la direction de M. Kunt. Volume 1. – Techniques modernes de traitement numérique des signaux, 1991,

440 pages. Volume 2. – Traitement numérique des images, 1993, 584 pages. Volume 3. – Reconnaissance des formes et analyse des scènes, 2000, 306 pages.

Effets non linéaires dans les fi ltres numériques, par R. Boite, M. Hasler et H. Dedieu, 1997, 226 pages.

VHDL, langage, modélisation, synthèse, par R. Airiau, J.-M. Bergé, V. Olive et J. Rouillard, 1998, 568 pages.

Les objets réactifs en Java, par F. Boussinot, 2000, 188 pages.

Codage, cryptologie et applications, par B. Martin, 2004, 350 pages.

Processus stochastiques pour l’ingénieur, par Bassel Solaiman, 2006, 240 pages.

Paiements électroniques sécurisés, par M. H. Sherif, 2007, 600 pages.

Page 440: Structures de données et méthodes formelles ||

438 Structures de données et méthodes formelles

Springer

ASN.1 – communication entre systèmes hétérogènes, par O. Dubuisson, 1999, 546 pages.

Droit et sécurité des télécommunications, par C. Guerrier et M.-C. Monget, 2000, 458 pages.

SDH, normes, réseaux et services, par T. Ben Meriem, 2000, 633 pages.

Traitement du signal aléatoire, par T. Chonavel, 2000, 296 pages.

Les fondements de la théorie des signaux numériques, par R. L. Oswald, 2000, 272 pages.

Le champ proche optique, par D. Courjon et C. Bainier, 2001, 344 pages.

Communications audiovisuelles, par E. Rivier, 2002.

La propagation des ondes radioélectriques, par H. Sizun, 2002, 360 pages.

Optoélectronique moléculaire et polymère : des concepts aux composants, par A. Moliton, 2003, 426 pages.

Electronique et optoélectronique organiques, par A. Moliton, 2011, 568 pages.