Arbres binaires de recherche optimaux et quasi-optimaux

Dimension: px
Commencer à balayer dès la page:

Download "Arbres binaires de recherche optimaux et quasi-optimaux"

Transcription

1 Université Libre de Bruxelles Faculté des Sciences Département d Informatique Arbres binaires de recherche optimaux et quasi-optimaux Mémoire présenté par Gabriel Kalyon en vue de l obtention du grade de Licencié en Informatique. Année académique

2 Table des matières 1 Introduction 5 I Fondements et définitions 7 2 Arbres binaires et complexité Arbres binaires Définitions Profondeur d un nœud Hauteur d un nœud Rotations Arbres binaires de recherche Modèle Classes d arbres binaires de recherche Performances asymptotiques Notation O(.) Notation Ω(.) Notation Θ(.) Lien entre les notations asymptotiques Complexité Complexité au pire cas Complexité moyenne Complexité amortie Conclusion Propriétés des arbres binaires de recherche Relations entre les propriétés Static finger Optimalité statique Working set Dynamic finger

3 3.6 Unifiée Optimalité dynamique Conclusion II Arbres binaires de recherche particuliers 26 4 Arbres Binaires de Recherche Optimaux Généralités Algorithme exhaustif Algorithme de Knuth Conclusion Arbres binaires de recherche équilibrés Définition Arbres rouges-noirs Définition Recherche Insertion Successeur Prédécesseur Analyse des performances Conclusion Arbres binaires de recherche auto-ajustables Définition Splay trees Splaying Recherche Insertion Suppression Analyse des performances Comparaisons Conclusion III Optimalité dynamique 46 7 Bornes inférieures sur le coût des arbres binaires de recherche Modèle La borne inférieure de couverture de rectangle Applications de la borne inférieure de couverture de rectangle 53 2

4 7.3.1 La borne inférieure d entrelacement La seconde borne de Wilber Conclusion Tango Structures de données Algorithme de l arbre de référence Arbres auxiliaires Définition Concaténation Éclatement Cutting Joining Algorithme Tango Analyse des performances Conclusion Multi-splay tree Structures de données Algorithmes Algorithme de l arbre de référence Algorithme multi-splay tree Analyse des performances Fonction potentiel Access Lemma Généralisé Multi-Splay Access Lemma Propriétés Conclusion Optimalité de recherche dynamique Définition Intérêt Structure Conclusion Expérimentations Jeux de tests Distribution aléatoire Distribution working set Conclusion

5 12 Conclusion Annexe Implémentation Multi-splay trees Splay trees Arbres rouges-noirs Jeux de tests

6 Chapitre 1 Introduction Lorsque nous recherchons un élément dans un ensemble, nous pouvons effectuer deux types de recherche : une recherche linéaire et une recherche dichotomique. La recherche linéaire consiste à examiner un à un les éléments de l ensemble, ce qui ne donne pas des performances intéressantes. La recherche dichotomique consiste à éliminer à chaque étape la moitié des éléments de l ensemble. Cette méthode donne des résultats intéressants, car la recherche se fait en temps logarithmique et non plus en temps linéaire. Les arbres binaires de recherche sont une application de la recherche dichotomique. Ce type de structure organise les éléments sous forme d arbre pour tenter d éliminer à chaque étape de la recherche le plus d éléments possibles (dans le meilleur des cas la moitié des éléments sont éliminés) de manière à localiser le plus rapidement possible un élément. Depuis que ce type de structure a été développé dans les années 1960, il y a eu énormément de travaux réalisés sur le sujet. En général, le but de ces travaux était d essayer de développer une structure qui atteigne l optimalité dynamique, c est-à-dire qui donne le meilleur coût de recherche et cela quelle que soit la séquence d éléments à rechercher. Ce mémoire consiste en un travail de recherche bibliographique et le but est de présenter les principaux travaux réalisés dans le domaine des arbres binaires de recherche et de l optimalité dynamique, ainsi que les principales étapes franchies dans ces domaines. Cela va en général consister à présenter des structures et à analyser leurs performances. La présentation de ces résultats se fera de manière plus détaillée et plus didactique que dans les articles dans lesquels ils sont présentés. Le second objectif de ce mémoire est d implémenter quelques structures de données pour vérifier si en pratique nous obtenons des résultats aussi intéressants qu en théorie. En effet, il se peut que pour des structures trop complexes les résultats obtenus en pratique soient moins bons que ceux auxquels nous aurions pu nous attendre à avoir 5

7 par la théorie. Ceci s explique notamment par le fait que dans les analyses des coûts d une structure, nous omettrons les constantes multiplicatives et les termes d ordre inférieur. Dans les chapitres 2 et 3, nous allons définir un certain nombre de notions. En fait, dans le chapitre 2, nous allons définir des notions de base dans le domaine des arbres binaires de recherche et dans le chapitre 3, nous allons définir des propriétés permettant de caractériser le coût d exécution d une séquence d accès dans un arbre binaire de recherche. Parmi ces propriétés, nous pouvons notamment citer l optimalité statique et l optimalité dynamique. Dans le chapitre 4, nous allons étudier les arbres binaires de recherche optimaux. Cette structure se base sur une connaissance préalable de la distribution des clés à accéder pour atteindre l optimalité statique. Dans les chapitres 5 et 6, nous allons présenter deux catégories d arbres binaires de recherche : les arbres binaires de recherche équilibrés et les arbres binaires de recherche auto-ajustables. Chacune de ces catégories sera illustrée par une structure de données : les arbres rouges-noirs pour la première et les splay trees pour la seconde. Nous détaillerons les algorithmes de ces structures et nous analyserons leurs performances. Dans le chapitre 7, nous présenterons trois bornes inférieures sur le coût d exécution d une séquence d accès dans un arbre binaire de recherche. Une de ces trois bornes est la borne inférieure d entrelacement. Celle-ci est à la base de la structure Tango étudiée dans le chapitre 8. Cette structure présente un grand intérêt, parce qu elle approche l optimalité dynamique à un facteur log(log n) près. Dans le chapitre 9, nous étudierons la structure des multi-splay trees, qui approche également l optimalité dynamique à un facteur log(log n) près. Cette structure présente comme principal intérêt d être plus facile à implémenter que Tango. À l heure actuelle, aucune structure de données n atteint l optimalité dynamique, mais nous présenterons dans le chapitre 10 un cas particulier où cette propriété est atteinte. Nous montrerons dans ce chapitre, que nous pouvons atteindre l optimalité dynamique en changeant le modèle de coût et en permettant à la structure d effectuer un nombre quelconque d opérations de réorganisation entre chaque accès sans que cela soit comptabilisé dans le coût d exécution. Pour analyser les performances en pratique des structures étudiées, nous en avons implémenté certaines pour y exécuter des jeux de tests. Dans le chapitre 11, nous fournirons les résultats des jeux de tests exécutés, ainsi que les conclusions que nous pouvons en tirer. L implémentation des structures, accompagnée d explications, est fournie en annexe. 6

8 Première partie Fondements et définitions 7

9 Chapitre 2 Arbres binaires et complexité Dans ce chapitre, nous allons définir toute une série de notions de base dans le domaine des arbres binaires de recherche et dans le domaine de la complexité. Ces rappels seront utiles au lecteur de manière à poser ces notions, qui seront sans cesse utilisées. 2.1 Arbres binaires Dans cette section, nous allons donner la définition d un arbre binaire, ainsi que de la terminologie associée à ce type de structure Définitions Cette section est basée sur les notes d un cours dispensé par Olivier Markowitch [Mar02]. Un arbre est une structure de données permettant de stocker un ensemble d éléments et il consiste en une collection de nœuds et d arêtes (on utilisera aussi le terme arc pour désigner une arête). Un nœud permet de stocker un élément de cet ensemble et une arête (arc) est un lien entre deux nœuds. L organisation de l arbre est telle que deux nœuds quelconques de l arbre sont reliés entre eux par un chemin unique. Un chemin est une suite de nœuds distincts dans laquelle deux nœuds successifs sont reliés par une arête. Un nœud peut posséder des fils. Un nœud y est le fils d une nœud x si y se situe en-dessous de x dans l arbre et s il est relié à ce nœud par une arête. Un nœud x possède également un père ; il s agit du nœud ayant x comme fils. Les nœuds qui n ont pas de fils sont appelés des feuilles. Le nœud au sommet de l arbre est appelé la racine et il ne possède pas de père. 8

10 Un arbre binaire est un arbre, où chaque nœud possède au plus deux fils appelés fils gauche et fils droit. Les ancêtres d un nœud x sont les nœuds qui appartiennent au chemin reliant la racine de l arbre à x. Les descendants d un nœud x sont les nœuds qui ont x comme ancêtre. Le sous-arbre d un nœud x dans un arbre A est la partie de A contenant x, ainsi que ses descendants. Le sous-arbre gauche d un nœud x est le sousarbre du fils gauche de x. Le sous-arbre droit d un nœud x est le sous-arbre du fils droit de x. Un sous-arbre est vide s il ne contient pas d éléments ; par exemple si x n a pas de fils droit, alors le sous-arbre droit de x est vide Profondeur d un nœud Cette section est basée sur les notes d un cours dispensé par Olivier Markowitch [Mar02]. La profondeur d un nœud x, notée d(x), est le nombre d arcs sur le chemin allant de la racine de l arbre au nœud x plus 1. De manière plus formelle : 1. d(x) = 1 si x est la racine de l arbre 2. d(x) = 1 + d(parent) sinon où parent est le nœud père de x Hauteur d un nœud Cette section est basée sur les notes d un cours dispensé par Olivier Markowitch [Mar02]. La hauteur d un nœud x, notée h(x), est le nombre d arcs sur le chemin allant de x à la feuille la plus profonde du sous-arbre de x. De manière plus formelle : 1. h(x) = 0 si x est feuille 2. h(x) = 1 + maxh(fg),h(fd) sinon où fg et fd sont, respectivement, les fils gauche et droit de x Rotations Il existe trois types de rotations possibles sur les arbres binaires : 1. une rotation simple 2. une rotation double 3. une rotation zig-zig 9

11 Fig. 2.1 Rotation simple entre x et y Rotation simple Cette opération a été décrite pour la première fois dans l article d Adel son-vel skii et Landis [AVL62]. Une rotation simple entre un nœud x et un nœud y (avec d(x) >d(y), où d(x) est la profondeur de x et d(y) est la profondeur de y) consiste à permuter la profondeur de x et de y comme décrit à la figure 2.1. Une rotation simple est dite droite si x est le fils gauche de y et elle dite gauche si x est le fils droit de y. La rotation à la figure 2.1 correspond à une rotation droite. La rotation gauche est déduite de manière symétrique par rapport à la rotation droite Rotation double Une rotation double entre un nœud x, un nœud y et un nœud z (avec d(x) >d(y) >d(z)) consiste à effectuer une rotation simple entre x et y, puis une rotation simple entre x et z (cfr figure 2.2). Pour pouvoir effectuer une rotation double, il faut que x soit un fils droit (respectivement fils gauche) et y soit un fils gauche (respectivement fils droit). 10

12 Fig. 2.2 Rotation double entre x, y et z Rotation zig-zig Cette opération a été décrite pour la première fois dans l article de Sleator et Tarjan [ST85]. Une rotation zig-zig entre un nœud x, un nœud y et un nœud z (avec d(x) >d(y) >d(z)) consiste à permuter la profondeur de x et de z comme décrit à la figure 2.3. Pour pouvoir effectuer une rotation zig-zig, il faut que x et y soient tous deux des fils gauches ou des fils droits. 2.2 Arbres binaires de recherche Le point principal dans cette section consiste à définir le modèle des arbres binaires de recherche, qui sera étudié. Il faut noter, qu il existe plusieurs modèles d arbres binaires de recherche. En général, ces variantes sont équivalentes (à un facteur constant près) en terme de performances au modèle décrit ci-dessous. 11

13 2.2.1 Modèle Fig. 2.3 Rotation zig-zig entre x, y et z. Nous considérons le modèle défini par Demaine, Harmon, Iacono et Patrascu [DHIP04]. Ils ont défini ce modèle en se basant sur celui de Wilber [Wil89], qui correspond également à celui utilisé par Sleator et Tarjan [ST85]. Un ABR(Arbre Binaire de Recherche) est un arbre binaire qui maintient un ensemble de clés selon une règle précise : pour chaque nœud x de l arbre, la clé de x est plus grande que toutes les clés contenues dans le sous-arbre gauche de x et elle est plus petite que toutes les clés contenues dans le sousarbre droit de x. Dans cette définition, nous considérons qu un ABR ne supporte qu une seule opération : la recherche d un élément. Cette recherche se fait sur un ensemble statique de n clés. Nous considérons seulement des recherches réussies, appelées accès. Nous supposons également, sans nuire à la généralité, que chaque clé d un ABR prend une valeur unique dans l ensemble 1, 2,..., n. Un ABR est utilisé pour servir une séquence d accès, qui consiste en une suite de clés X = x 1,x 2,..., x m. L algorithme d accès de l ABR permet, en fait, de servir chaque accès x i de cette séquence. Pour accéder à un nœud x i, l algorithme d accès ne peut utiliser qu un seul pointeur P durant le parcours de l arbre. Au début de l accès, ce pointeur est initialisé à la racine de l arbre. 12

14 L algorithme d accès peut, ensuite, réaliser les opérations de coût unitaire suivantes : 1. déplacer le pointeur P vers son fils gauche 2. déplacer le pointeur P vers son fils droit 3. déplacer le pointeur P vers son père 4. effectuer une rotation simple entre le pointeur P et son père L algorithme d accès réalise une séquence des opérations ci-dessus jusqu à ce que le pointeur P atteigne le nœud x i. Le coût d accès au nœud x i est le nombre d opérations de coût unitaire réalisées pour l atteindre. Dès lors, le coût exigé par un ABR pour exécuter une séquence X = x 1,x 2,..., x m vaut m i=1 cout(x i). Nous désignerons ce modèle par le terme modèle dynamique. Comme autre modèle pour les arbres binaires de recherche, nous pouvons citer le modèle standard. Ce modèle est défini dans les articles [DSW05] et [BCK03] et il sera abordé dans le chapitre Classes d arbres binaires de recherche Il existe deux grandes classes d ABR, basées sur la manière de choisir l opération de coût unitaire suivante à réaliser lors d un accès x i : 1. les ABR online 2. les ABR offline ABR online Un ABR online [DHIP04] est une structure de données ABR dans laquelle chaque nœud peut contenir des données supplémentaires. Lors de chaque opération de coût unitaire, les données contenues dans le nœud pointé par le pointeur P peuvent être modifiées. Les données contenues dans les nœuds permettent, en général, de garder de l information sur les clés déjà accédées, de manière à améliorer le coût d accès aux clés devant encore être accédées. Lors d un accès, l algorithme d accès choisit l opération de coût unitaire suivante à réaliser en fonction de la clé à accéder et des informations supplémentaires contenues dans le nœud pointé par le pointeur P. La quantité d informations supplémentaires contenues dans un nœud doit être la plus petite possible de manière à avoir une incidence négligeable sur le temps d exécution du programme. En effet, si cette quantité est trop grande, la mise à jour de ces informations après une opération risque de coûter cher. 13

15 Comme exemples d ABR online, nous pouvons citer : les arbres rougesnoirs (qui nécessitent un bit de couleur par nœud), les arbres AVL (qui nécessitent un compteur par nœud) et les splay trees (qui ne nécessitent pas d informations supplémentaires) ABR offline Un ABR offline est une structure de données ABR, qui a une connaissance préalable de la séquence X à exécuter. En fait, il s agit d une structure utopique, qui avant même de servir X, connaît déjà les nœuds qui devront être accédés dans cette séquence. De par cette connaissance, une telle structure n a pas besoin de garder des informations supplémentaires dans ses nœuds. Lors d un accès x i, le choix de l opération de coût unitaire suivante à réaliser est basé sur la connaissance de toute la séquence X. La différence entre un ABR online et un ABR offline est que, pour choisir l opération de coût unitaire suivante à réaliser lors d un accès x i, ce dernier peut se baser sur les accès qui suivent x i dans la séquence X. 2.3 Performances asymptotiques Cette section est basée sur l ouvrage de Flajolet et Sedgewick [FS98]. Pour caractériser l efficacité d un algorithme, nous étudions ses performances asymptotiques. Ceci consiste à étudier la façon dont varie le temps d exécution d un algorithme quand la taille de l entrée tend vers l infini. Plusieurs raisons justifient l usage des méthodes asymptotiques : 1. les performances asymptotiques d un algorithme sont plus faciles à calculer que son temps d exécution exact. 2. calculer le temps d exécution exact d un algorithme est en général inutile. En effet, pour des entrées suffisamment grandes, les effets des constantes multiplicatives et des termes d ordre inférieur dans le temps d exécution exact sont négligeables. 3. les méthodes asymptotiques fournissent de bons critères de comparaison entre les algorithmes. En effet, un algorithme, qui est asymptotiquement meilleur qu un autre, est plus efficace que ce dernier pour des entrées suffisamment longues. Ci-dessous suivent trois notations asymptotiques permettant de décrire le temps d exécution asymptotique d un algorithme. 14

16 2.3.1 Notation O(.) Soit N la taille de l entrée d un algorithme. Nous disons que le temps d exécution T (N) d un algorithme est en O(g(N)) (dit grand o de g de N ) s il existe des constantes positives c 1 et n 0 telles que : n n 0, 0 T (n) c 1.g(n) (2.1) Nous constatons, que pour n suffisamment grand, T (n) est borné supérieurement par c 1 g(n). Intuitivement, la notation O(.) sert à majorer la fonction T (N) Notation Ω(.) Soit N la taille de l entrée d un algorithme. Nous disons que le temps d exécution T (N) d un algorithme est en Ω(g(N)) (dit grand omega de g de N ) s il existe des constantes positives c 1 et n 0 telles que : n n 0, 0 c 1.g(n) T (n) (2.2) Nous constatons, que pour n suffisamment grand, T (n) est borné inférieurement par c 1 g(n). Intuitivement, la notation Ω(.) sert à minorer la fonction T (N) Notation Θ(.) Soit N la taille de l entrée d un algorithme. Nous disons que le temps d exécution T (N) d un algorithme est en Θ(g(N)) (dit grand theta de g de N ) s il existe des constantes positives c 1, c 2 et n 0 telles que : n n 0, 0 c 1.g(n) T (n) c 2.g(n) (2.3) Nous constatons, que pour n suffisamment grand, T (n) est borné inférieurement par c 1 g(n) et supérieurement par c 2 g(n). Intuitivement, la notation Θ(.) fournit une valeur approchée de la fonction T (N) Lien entre les notations asymptotiques Une fois les trois définitions ci-dessus présentées, il est assez aisé d établir un lien entre elles. Ce lien est explicité par le théorème suivant. Théorème 1. Pour deux fonctions quelconques g(n) et f(n), nous avons que f(n) = Θ(g(n)) si et seulement si f(n) = O(g(n)) et f(n) = Ω(g(n)). 15

17 Ce théorème peut facilement être démontré en prouvant d abord l implication du théorème dans un sens, puis en prouvant son implication dans l autre sens et cela en se basant à chaque fois sur la définition de O(.), Θ(.) et Ω(.) 2.4 Complexité Cette section est basée sur l ouvrage de Jean Cardinal [Car04] et l article de Tarjan [Tar85]. Il existe principalement trois manières d analyser la complexité d une structure : 1. effectuer une analyse au pire cas 2. effectuer une analyse amortie 3. effectuer une analyse du cas moyen Dans cette section, nous allons définir ces trois analyses et développer de manière plus précise l analyse amortie Complexité au pire cas L analyse au pire cas consiste à caractériser la complexité d une opération dans le pire des cas. Ce pire cas peut se produire de manière répétée ou non. Si ce pire cas peut se produire de manière répétée, la complexité au pire cas donne une bonne indication des performances en pratique de la structure. Par contre, si ce pire cas ne peut pas se produire souvent, elle ne donne pas une indication concrète sur les performances en pratique. Ceci peut être illustré par l exemple suivant : la complexité au pire cas de l algorithme de Knuth-Morris-Pratt (pour la recherche de motifs) est bien meilleure que la complexité au pire cas de l algorithme de Boyer-Moore, alors qu en pratique ce deuxième algorithme est plus efficace que le premier Complexité moyenne L analyse de la complexité moyenne est en général délicate. La complexité moyenne est calculée sur la base d une distribution de probabilités sur l ensemble des entrées de l algorithme, pour laquelle des hypothèses ont été posées. La source de l aléatoire vient alors des entrées. Cette complexité donne des informations assez significatives concernant les performances en pratique si les pire cas sont rares. 16

18 Il existe une seconde manière de calculer une complexité moyenne, dans laquelle la source de l aléatoire ne vient pas des entrées, mais de l algorithme qui fait des choix aléatoires. La complexité est calculée sur ces choix et on parle alors de complexité moyenne randomisée Complexité amortie Définition La complexité amortie est la complexité au pire cas d une séquence de M opérations divisée par M. La complexité amortie donne des informations significatives concernant les performances en pratique d une structure, tout en se basant sur les performances au pire cas. Cette analyse apparaît, donc, comme un bon intermédiaire entre la complexité moyenne et la complexité au pire cas. Elle permet, mieux que les deux analyses précédentes, de concevoir des structures efficaces en pratique. Il existe plusieurs méthodes pour effectuer une analyse amortie d une structure. La méthode qui sera développée dans le point suivant est la méthode du potentiel Méthode du potentiel La méthode du potentiel nécessite de définir une fonction potentiel. Cette fonction peut être comparée à un compte bancaire. Celui-ci ne peut pas descendre en dessous d une certaine valeur (par exemple 0). Lorsqu un achat nécessite un coût moindre que prévu, l argent restant est remis dans le compte et celui-ci augmente. Par contre, lorsque le coût d un achat est supérieur à celui prévu, il faut aller puiser dans le compte pour payer le reste et celui-ci diminue donc. Cette analogie permet de donner une première idée de ce qu est une fonction potentiel. Une définition plus précise est donnée ci-dessous. La fonction potentiel est une valeur qui est bornée inférieurement par une constante. Cette borne dépend de la structure, mais vaut en général 0. La fonction potentiel va augmenter, lorsque le temps réel pour effectuer une opération est inférieur à son temps amorti. Et elle va diminuer, si le temps réel pour effectuer une opération est supérieur à son temps amorti. En d autres termes, lorsque le coût effectif d une opération est inférieur à son coût amorti, la fonction potentiel sauvegarde la différence entre ces deux coûts, et lorsque le coût d une opération est supérieur à son coût amorti, la fonction potentiel puise dans sa réserve pour compenser ce surcoût. 17

19 Pour prouver une complexité amortie C A, il faut établir l équation suivante, qui utilise une fonction potentiel P : C A = C E + P, (2.4) où C E est la complexité effective de l opération et P est la variation de la fonction potentiel entre le début et la fin de l opération. Pour établir l équation ci-dessus, il faut prouver, qu à la ième ( 1 i M) opération d une séquence de M opérations, l égalité suivante est vérifiée : C A = C E (i)+ P (i), (2.5) où C E (i) est le coût effectif de la ième opération et P (i) est la variation de potentiel à la ième étape, c est-à-dire la différence entre le potentiel après la ième étape (= P (i)) et le potentiel avant la ième étape (= P (i 1)). Cette équation peut être réécrite de la manière suivante : 2.5 Conclusion C A = C E (i)+p (i) P (i 1) (2.6) Dans ce chapitre, nous avons d abord défini la notion d arbre binaire, ainsi que la terminologie associée à ce type de structure. Ensuite, nous avons défini le modèle dynamique des arbres binaires de recherche. Et finalement, nous avons présenté plusieurs outils (les performances asymptotiques et les différents types de complexité) permettant de caractériser les performances d une structure ABR et permettant de comparer les performances de telles structures. 18

20 Chapitre 3 Propriétés des arbres binaires de recherche Dans ce chapitre, nous allons présenter plusieurs propriétés caractérisant le coût d exécution d une séquence d accès dans des ABR. Ces propriétés sont également valables pour certaines structures qui ne sont pas des ABR. 3.1 Relations entre les propriétés Nous allons décrire dans ce chapitre six propriétés : 1. Static Finger 2. Optimalité Statique 3. Working Set 4. Dynamic Finger 5. Unifiée 6. Optimalité Dynamique La figure 3.1 illustre la relation d implication entre ces propriétés. La propriété static finger est la plus faible de toutes, car elle est une conséquence de toutes les autres propriétés. De plus, les propriétés working set et dynamic finger sont indépendantes. Les définitions des propriétés ci-dessus sont basées sur deux articles de Iacono [Iac01] et [Iac05]. 3.2 Static finger Considérons un ensemble de n clés 1, 2,..., n, une séquence d accès X = x 1,x 2,..., x m et un nœud spécifique f, appelé le finger, appartenant à 19

21 Fig. 3.1 Relation d implication entre les propriétés. l ensemble 1, 2,..., n. Une structure a la propriété static finger si le coût total pour exécuter la séquence X vaut : ( m ) O log (1 + x i f ) (3.1) i=1 L expression x i f est la distance dans l ordre symétrique entre le finger f et le nœud x i. En d autres termes, la distance x i f est le nombre d éléments situés entre x i et f dans la séquence triée des nœuds plus 1. Une fois fixé, le finger reste le même durant toute l exécution de la séquence X. Les Finger Search Trees [BLM + 03] possèdent cette propriété, mais cette structure ne répond pas à la définition du modèle dynamique des ABR (cfr point 2.2.1), car son opération de recherche peut débuter à partir d une feuille quelconque de l arbre. Les splay trees [ST85] possèdent également cette propriété. De l équation (3.1), nous constatons que plus la distance entre le finger f et le nœud x i est petite, plus le coût sera petit et inversement. Par conséquent, pour une structure ayant la propriété static finger, le coût total pour exécuter une séquence X sera déterminé par la distance dans l ordre symétrique entre le finger f et chaque nœud de la séquence X à exécuter. 20

22 3.3 Optimalité statique Considérons un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Une structure a la propriété d optimalité statique, si elle exécute X avec un coût de : O ( n i=1 ( ) ) m f (i) log, (3.2) f (i) où f (i) est le nombre d accès à i dans la séquence X. Supposons que nous ayons une variable aléatoire discrète qui puisse prendre n valeurs ( 1, 2,..., n ), l entropie de cette variable est la quantité : H = n p i log (p i )= i=1 n i=1 ( ) 1 p i log, (3.3) p i où p i est la probabilité que la variable aléatoire soit égale à i. Prenons l équation (3.2) et réécrivons-la de la manière suivante : ( n ( ) ) f(i) m O m m log (3.4) f(i) i=1 En posant p i = f(i)/m, nous obtenons : ( n ( ) ) 1 O m p i log = O(m H) (3.5) p i i=1 Une structure, qui atteint l optimalité statique, exécute donc la séquence X avec un coût égal à O(m H). De plus, elle exécute un accès avec un coût amorti O(H). Les Arbres Binaires de Recherche Optimaux [Knu73] et les splay trees [ST85] sont deux structures ABR ayant cette propriété d optimalité statique. Ces deux structures feront l objet d explications plus détaillées, respectivement, dans les chapitres 4 et Working set Considérons un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Soit l(i, x)égal à j si x j est le dernier accès à x dans la séquence x 1,x 2,..., x i 1. Si x n est pas accédé dans cette séquence, alors l(i, x) vaut 1. Nous définissons w(i, x) comme étant le nombre d éléments distincts accédés dans 21

23 la séquence x l(i,x)+1,x l(i,x)+2,..., x i. Dès lors, w(i, x i ) est le nombre d éléments distincts accédés dans la séquence x l(i,xi )+1,x l(i,xi )+2,..., x i. Il s agit donc du nombre d éléments distincts accédés entre l accès x i et le précédent accès à cet élément. Notons w(i, x i ) par w(x i ). Une structure a la propriété working set, si elle exécute une séquence d accès X avec un coût : ( m ) O log (w (x i )) (3.6) i=1 De cette propriété, nous déduisons que plus il y a d éléments différents accédés entre deux accès successifs d un nœud x i, plus le coût d accès à ce nœud x i sera élevé et inversement. De plus, nous constatons que, si les accès d une séquence X ne se font que sur un sous-ensemble de k éléments parmi les n, la complexité d un accès à une clé x i de cette séquence sera d au plus O(log k), car w(x i ) ne pourra jamais être supérieur à k. Par conséquent, pour une structure ayant la propriété working set, le coût total pour exécuter une séquence X dépend de deux critères : 1. le nombre de clés différentes dans la séquence X. 2. le nombre d éléments différents accédés entre deux accès successifs d une même clé dans la séquence X. Plus la première quantité sera petite, plus elle aura d importance dans le coût d exécution de la séquence X. En fait, cette propriété est basée sur la localité temporelle : plus la localité temporelle entre deux accès successifs d une même clé est petite (c est-à-dire que le temps écoulé entre ces deux accès est petit), plus le coût d accès à ce nœud est petit et inversement. La Working Set Data Structure proposée par Iacono [Iac01] atteint un pire cas de O(log(w(x i ))) pour un accès x i. Cependant, cette structure ne répond pas à la définition du modèle dynamique des ABR, car elle utilise des pointeurs et des files additionnels. Les splay trees [ST85] possèdent également cette propriété. 3.5 Dynamic finger Considérons un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Une structure a la propriété dynamic finger si le coût total pour exécuter la séquence X vaut : 22

24 O ( m 1 i=1 log (1 + x i+1 x i ) ) (3.7) Cette propriété est analogue à la propriété static finger. La différence étant que pour cette dernière, le finger f est fixe, tandis que pour la propriété dynamic finger, le finger est le dernier élément accédé. Les Level-Linked Trees [BT80] possèdent cette propriété, mais cette structure ne répond pas à la définition du modèle dynamique des ABR, car elle utilise des pointeurs additionnels. Les level-linked trees atteignent un pire cas de O(log (1 + x i+1 x i )) pour un accès. Les splay trees [ST85] possèdent également la propriété dynamic finger. De l équation (3.7), nous déduisons que l accès à un nœud est d autant plus rapide que la distance entre l élément auquel on doit accéder et le dernier élément auquel on a accédé est petite. En fait, cette propriété est basée sur la localité spatiale : plus la distance entre deux accès adjacents est petite, plus le coût d accès au nœud est petit et inversement. Par conséquent, pour une structure ayant la propriété dynamic finger, le coût total pour exécuter une séquence X sera déterminé par la distance entre les accès adjacents de la séquence. Plus la distance entre les accès adjacents de la séquence sera grande, plus le coût pour exécuter X sera grand et inversement. 3.6 Unifiée Considérons un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Une structure a la propriété unifiée si elle exécute X avec un coût : ( m ) O min (log (w(i, j)+ x i j + 1)) (3.8) j X i=1 L Unified Structure [Iac01] possède cette propriété, mais elle ne répond pas à la définition du modèle dynamique des ABR. Les splay trees [ST85] sont conjecturés avoir la propriété unifiée. À l heure actuelle, il n existe aucune structure ABR qui atteigne cette borne. Une structure ayant cette propriété exécutera une séquence avec un coût faible si les accès sont proches en terme de distance à des éléments accédés récemment et inversement. Cette propriété est donc basée sur la localité temporelle et la localité spatiale des accès. 23

25 La propriété unifiée implique la propriété working set et la propriété dynamic finger. L intérêt de la propriété unifiée est d unifier les propriétés working set et dynamic finger ; ces deux propriétés étant indépendantes, car aucune des deux n implique l autre. 3.7 Optimalité dynamique Considérons une séquence quelconque d accès X = x 1,x 2,..., x m. Certains ABR peuvent l exécuter de manière optimale. Notons par OP T (X) ce coût minimal pour exécuter X. Ce coût OP T (X) est le coût de l ABR offline le plus rapide qui puisse exécuter X. En effet, dans le modèle ABR offline, il n y a aucune contrainte dans l algorithme d accès sur la manière de choisir la prochaine opération de coût unitaire à réaliser. Et en particulier, ce choix peut dépendre des futurs accès à servir dans la séquence. Une structure de données ABR a la propriété d optimalité dynamique, si elle exécute une quelconque séquence d accès X avec un coût O(OP T (X)). On dit qu une structure de données A est α compétitive (ou a un taux de compétitivité de α) si pour toute séquence X : COUT A (X) α OP T (X), (3.9) où COUT A (X) est le coût nécessaire à la structure A pour exécuter X. La conjecture d optimalité dynamique, énoncée par Sleator et Tarjan [ST85], affirme que les splay trees sont O(1) compétitif s. Cependant, aucune démonstration n est venue étayer cette conjecture. Jusqu il y a peu, le meilleur taux de compétitivité était le taux trivial de O(log(n)), atteint par exemple par les arbres rouges-noirs. Ce n est qu en 2004, que ce taux a pu être amélioré par une structure de données appelée Tango [DHIP04]. Cette structure atteint un taux de compétitivité de O(log(log n)). Par après, une autre structure de données, les Multi-Splay Trees ([SW04] et [DSW06]), a été développée sur base de Tango pour atteindre également un taux de compétitivité de O(log(log n)). Ces deux structures seront détaillées dans les chapitres 8 et 9. La propriété d optimalité dynamique a une signification profonde : connaître le futur ne permet d améliorer le temps d exécution d une séquence d accès que d un facteur constant. En effet, si nous parvenons à développer un ABR online, qui atteint l optimalité dynamique, cela signifierait que nous sommes parvenus à créer une structure, qui en se basant sur le passé de la séquence d accès X à exécuter, donne des résultats équivalents, à un facteur constant près, à la meilleure structure de données offline, qui se base sur la 24

26 connaissance du futur pour exécuter de manière optimale la séquence d accès X. 3.8 Conclusion Dans ce chapitre, nous avons défini toute une série de propriétés permettant de caractériser le coût d exécution d une séquence d accès dans un ABR. La propriété la plus forte étant bien évidemment l optimalité dynamique. De plus, nous avons présenté la relation d implication entre ces propriétés de manière à spécifier celles qui sont les plus fortes et celles qui sont les plus faibles. 25

27 Deuxième partie Arbres binaires de recherche particuliers 26

28 Chapitre 4 Arbres Binaires de Recherche Optimaux La rédaction de ce chapitre est basée sur l ouvrage de Knuth [Knu73]. La structure des ABRO (= Arbres Binaires de Recherche Optimaux) a été développée par Knuth [Knu73]. Le but de cette structure est d atteindre l optimalité statique et elle nécessite pour cela de connaître la distribution des clés à accéder. Pour rappel, une structure a la propriété d optimalité statique (cfr point 3.3), si elle exécute une séquence d accès X = x 1,x 2,..., x m sur un arbre de n clés 1, 2,..., n avec un coût de : O ( n i=1 ( ) ) m f (i) log, (4.1) f (i) où f (i) est le nombre d accès à i dans la séquence X. 4.1 Généralités Pour construire l ABRO d un ensemble de nœuds P = p 1,p 2,..., p n, nous disposons, en plus de ces nœuds, de leur fréquence relative d accès. Pour tenir compte des recherches infructueuses, nous avons également besoin d un ensemble de nœuds externes Q = q 0,q 1,q 2,..., q n. Ces nœuds externes représentent les pointeurs nuls des nœuds de l arbre. Chaque nœud de Q représente un intervalle de nœuds pour lesquels la recherche est infructueuse : q 0 représente l intervalle (,p 1 ), q i représente l intervalle (p i,p i+1 )( 0 < i<n) et q n représente l intervalle (p n, ). Les nœuds de Q sont accompagnés de leur fréquence relative d accès. 27

29 Fig. 4.1 Arbre dont le coût de recherche est de 2.2 Le coût d une recherche dans l arbre T construit sur les clés de P est donné par la quantité : c(t )= ( 1 j n f(p j ) profondeur(p j ) ) + ( 0 j n f(q j ) (profondeur(q j ) 1) où f(p j ) est la fréquence relative d accès au nœud p j et où f(q j ) est la fréquence relative d accès au nœud externe q j, c est-à-dire la probabilité que la clé recherchée appartienne à l intervalle (q j,q j+1 ). La notion de profondeur est définie au point Considérons l arbre T de la figure 4.1 et l assignation de fréquences suivante : f(p 1 ) = 0.15, f(p 2 ) = 0.1, f(p 3 ) = 0.25, f(q 0 ) = 0.05, f(q 1 ) = 0.2, f(q 2 )=0.15, f(q 3 )=0.1. Le coût d une recherche dans l arbre T est le suivant : ), c(t ) = (0.15) 3 + (0.1) 2 + (0.25) 1 + (0.05) 3 +(0.2) 3 + (0.15) 2 + (0.1) 1 = 2.2 Pour déterminer l ABRO de P, il suffit de trouver l arbre T, dont le coût de recherche c(t ) est le minimum parmi les coûts de recherche de tous les arbres possibles. À noter qu il peut exister plusieurs arbres, dont le coût de recherche est minimal. 28

30 4.2 Algorithme exhaustif Pour déterminer l ABRO de l ensemble P de nœuds, il suffit de construire tous les arbres possibles sur P, de calculer leur coût de recherche et de retenir celui dont le coût est minimal. Cependant, la complexité d un tel algorithme est exponentielle. En effet, avec n nœuds il est possible de construire C n+1 (= le (n + 1)ème nombre de Catalan) arbres binaires de recherche. Or, C n+1 = ( 2n n ) (n + 1) 4 n π 1/2 n 3/2 Clairement un tel algorithme pour construire l ABRO est à exclure. 4.3 Algorithme de Knuth L algorithme de Knuth est un algorithme de programmation dynamique. Il se base sur la propriété suivante : tous les sous-arbres d un ABRO sont optimaux. En effet, une amélioration du coût de recherche d un quelconque sous-arbre d un ABRO mène à une amélioration du coût de recherche de l ABRO. L idée est de considérer le problème de manière récursive (cfr figure 4.2). Un ABRO T est constitué d une racine p k, d un sous-arbre gauche (qui est un ABRO) et d un sous-arbre droit (qui est un ABRO). On construit de manière récursive le sous-arbre gauche et le sous-arbre droit de p k avant de construire T. Pour construire l ABRO avec l algorithme de programmation dynamique, nous avons besoin de trois tables : 1. la table C, où C(i, j) ( 0 i j n) est le coût de l ABRO sur les nœuds p i+1,..., p j,q i,..., q j. 2. la table r, où r(i, j) ( 0 i j n) est l indice k de la racine p k de l ABRO sur les nœuds p i+1,..., p j,q i,..., q j. 3. la table W, où W (i, j) =f(p i+1 )+...+ f(p j )+f(q i )+...+ f(q j ) ( 0 i j n). Le remplissage de la table C commence à la ligne 0 et se termine à la ligne n. Il est basé sur la formule suivante : 29

31 Fig. 4.2 ABRO d un point de vue récursif 0 si i j C(i, j) = W (i, j) + min i<k j si i<j (4.2) L idée de cette formule est de déterminer pour chaque indice k le coût de l arbre construit avec p k comme racine, un ABRO de coût C(i, k 1) comme sous-arbre gauche et un ABRO de coût C(k, j) comme sous-arbre droit ; il faut retenir celui qui minimise la quantité C(i, k 1) + C(k, j). Une fois k déterminé (si plusieurs indices donnent un coût minimal, il faut en choisir un arbitrairement), il faut stocker cet indice dans r(i, j). Il faut noter que dans le calcul de C(i, j), il faut rajouter le terme W (i, j). En effet, lorsque le sousarbre gauche de coût C(i, k 1) et le sous-arbre droit de coût C(k, j) sont rattachés à la racine p k, la profondeur de chacun des nœuds dans ces sousarbres augmente de 1. Ceci implique qu il faut rajouter dans le coût C(i, j) la fréquence de chacun de ces nœuds. Comme il faut également rajouter la fréquence de p k, cela revient finalement à rajouter W (i, j) au coût C(i, j). Il est possible d optimiser la formule 4.2 en se basant sur l inégalité suivante démontrée par Knuth dans [Knu73] : r(i, j 1) r(i, j) r(i +1,j) (4.3) 30

32 La formule devient alors : 0 si i j C(i, j) = W (i, j) + min (C(i, k 1) + C(k, j)) si i<j r(i,j 1) r(i,j) r(i+1,j) (4.4) La construction de l ABRO en utilisant la formule 4.4 nécessite un coût en O(n 2 ) (si n est la taille de l arbre), alors que la construction avec la formule 4.2 nécessite un coût en O(n 3 ) [Knu73]. De plus, le coût d une recherche dans un tel arbre se fait en O(H) [Knu73] (où H est l entropie). 4.4 Conclusion Dans cette section, nous avons présenté un algorithme de programmation dynamique, qui construit avec un coût en O(n 2 ) une structure qui atteint l optimalité dynamique. Cette structure est statique et elle requière la connaissance de la fréquence des nœuds. En 1979, Bitner [Bit79] a présenté et analysé les Arbres Monotones Dynamiques. Cette structure est un ABR dynamique (un ABR qui permet les insertions et les suppressions), qui essaie d approximer l ABRO. 31

33 Chapitre 5 Arbres binaires de recherche équilibrés Dans ce chapitre, nous allons d abord définir la notion d arbre binaire de recherche équilibré. Ensuite, nous allons illustrer ce concept par la présentation des arbres rouges-noirs. Le choix de cette structure plutôt qu une autre se justifie par le fait qu elle fait partie des plus connues et des plus efficaces de sa catégorie. 5.1 Définition Un arbre binaire de recherche équilibré est un ABR, qui maintient des informations supplémentaires dans ses nœuds, de manière à ce qu il reste équilibré. Le but de cet équilibrage est qu à tout moment, la hauteur de l arbre soit logarithmique, à un facteur constant près, en le nombre d éléments dans l arbre. Ceci permet d avoir des opérations sur la structure en temps logarithmique en le nombre d éléments dans l arbre. 5.2 Arbres rouges-noirs Dans la littérature, il existe deux manières de présenter les arbres rougesnoirs : soit de les décrire comme une implémentation des arbres (une description de cette structure-ci est présentée dans l ouvrage [Sed04]), soit de les décrire comme une structure vérifiant un certain nombre de conditions, qui permettent d équilibrer l arbre. Les deux méthodes sont bien évidemment équivalentes. La première méthode est plus intéressante, car elle permet de comprendre le sens des propriétés imposées aux arbres rouges-noirs. Elle permet, de plus, de comprendre aisément les algorithmes d insertion et de 32

34 suppression des arbres rouges-noirs, ainsi que leur preuve de correction. La deuxième méthode permet de présenter la structure de manière plus brève. Nous utiliserons la deuxième méthode pour présenter la structure. Cette description est basée sur les ouvrages de Jean Cardinal [Car04] et de Sedgewick [Sed04] Définition Les arbres rouges-noirs ont deux types d arcs : les arcs rouges et les arcs noirs. Un seul bit par nœud x est nécessaire comme information supplémentaire. Ce bit indique si l arc pointant vers ce nœud x est rouge ou noir. Un arbre, pour répondre à la définition d arbres rouges-noirs, doit vérifier les propriétés suivantes : 1. dans un chemin de la racine à une feuille, il n y a jamais deux arcs rouges successifs 2. le nombre d arcs noirs dans un chemin de la racine à un sous-arbre vide est le même quel que soit le chemin 3. le bit de couleur de la racine est noir Ces conditions permettent d équilibrer l arbre, comme il le sera démontré plus loin dans ce chapitre, de manière à ce que les opérations sur les arbres rouges-noirs se fassent en temps logarithmique au pire cas en le nombre d éléments dans l arbre Recherche L algorithme de recherche pour les arbres rouges-noirs est identique à l algorithme d accès des ABR défini pour le modèle dynamique (cfr point 2.2.1) Insertion L algorithme d insertion pour les arbres rouges-noirs est le suivant. En commençant le traitement à la racine, il faut effectuer les opérations suivantes : 1. Désignons par x le nœud courant. Si x a deux arcs sortants rouges, il faut traiter ce nœud de la manière suivante : (a) colorier les deux arcs sortants de x en noir (b) colorier l arc liant x à p (où p est le père de x) en rouge 33

35 (c) si l arc liant p à g (où g est le père de p ) est rouge, il faut effectuer une rotation. Cette rotation est simple (rotation entre p et g) si x et p sont tous deux des fils gauches ou s ils sont tous deux des fils droits ; elle est double sinon. Après cet éventuel traitement, il faut déplacer le pointeur courant sur le fils gauche ou le fils droit de x suivant que la clé à insérer soit, respectivement, plus petite ou plus grande que x. Cette première étape est à itérer tant que le nœud courant ne pointe pas sur un sous-arbre vide. 2. À ce niveau, le pointeur courant pointe sur un sous-arbre vide. Il ne suffit, dès lors, qu à insérer le nouveau nœud dans ce sous-arbre vide en coloriant son bit de couleur en rouge. Après cela, si l arc liant p (où p est le père du nœud inséré) à g (où g est le père de p) est rouge, il faut effectuer une rotation. Cette rotation est simple (rotation entre p et g) si le nœud inséré et p sont tous deux des fils gauches ou s ils sont tous deux des fils droits ; elle est double sinon. Les notions de rotation simple et de rotation double sont définies au point Certains lecteurs pourraient être sceptiques quant à la correction de cet algorithme, mais si nous considérons les arbres rouges-noirs comme une implémentation des arbres 2-3-4, alors cette preuve peut facilement être établie. Les utilisateurs intéressés par cela peuvent consulter la référence [Car04] ou [Sed04] Successeur L opération successeur pour un nœud x donne l élément, qui suit x dans l ordre symétrique. L algorithme suivant permet de déterminer le successeur de x. Supposons que le pointeur courant pointe sur le nœud x (si ce n est pas le cas, il suffit de réaliser une recherche sur cet élément). Ensuite, deux cas sont à envisager, selon que x ait un fils droit ou non : 1. Si x a un fils droit, noté y, il faut se positionner sur le fils droit de x et suivre le chemin des fils gauches à partir de y. Le successeur de x est alors le dernier nœud rencontré sur ce chemin. 2. Si x n a pas de fils droit, il faut remonter dans l arbre, tant que x appartient au sous-arbre droit du nœud courant. Le successeur de x est, alors, le premier nœud dans cette remontée, qui contient x dans son sous-arbre gauche. S il n existe pas de tel nœud, alors x n a pas de successeur. 34

36 5.2.5 Prédécesseur L opération prédécesseur pour un nœud x donne l élément, qui précède x dans l ordre symétrique. L algorithme suivant permet de déterminer le prédécesseur de x. Supposons que le pointeur courant pointe sur le nœud x (si ce n est pas le cas, il suffit de réaliser une recherche sur cet élément). Ensuite, deux cas sont à envisager, selon que x ait un fils gauche ou non : 1. Si x a un fils gauche, noté y, il faut se positionner sur le fils gauche de x et suivre le chemin des fils droits à partir de y. Le prédécesseur de x est alors le dernier nœud rencontré sur ce chemin. 2. Si x n a pas de fils gauche, il faut remonter dans l arbre, tant que x appartient au sous-arbre gauche du nœud courant. Le prédécesseur de x est, alors, le premier nœud dans cette remontée, qui contient x dans son sous-arbre droit. S il n existe pas de tel nœud, alors x n a pas de prédécesseur Analyse des performances Les deux démonstrations présentées dans cette partie sont basées sur l ouvrage de Sedgewick [Sed04] Lemme 1. Soient un arbre rouge-noir et un nœud x appartenant à cet arbre. Le sous-arbre A de x contient au moins 2 bh(x) 1 nœuds (bh(x) est la hauteur noire de x, c est-à-dire le nombre de nœuds ayant un bit noir entre x (inclus) et la feuille la plus profonde de x moins 1. On impose que bh(x) 0). Démonstration : la hauteur de x : La démonstration de ce lemme se fait par récurrence sur 1. Initialisation de la récurrence : Si la hauteur de x vaut 0, alors bh(x) vaut 0. Dès lors, le sous-arbre A de x doit contenir au moins 2 bh(x) 1= = 0 nœud. Or, si x a une hauteur de 0, cela signifie que le sousarbre A consiste en la seule feuille x. Le sous-arbre A contient, donc, un élément et le lemme est, alors, vérifié. 2. Pas de récurrence : Supposons que le lemme soit vrai pour une hauteur h 1 et montrons qu il l est aussi pour une hauteur h. Supposons que le nœud x ait une hauteur h et une hauteur noire bh(x). Considérons le pire cas, où x a deux enfants ; en effet, on augmente ainsi le nombre d éléments dans le sous-arbre de x. Chaque enfant de x a une hauteur noire qui vaut bh(x) ou bh(x) 1, selon que son bit de 35

37 couleur soit respectivement rouge ou noir. Étant donné que la hauteur de chacun de ces enfants vaut h 1, on peut appliquer l hypothèse de récurrence sur ces nœuds, et ainsi déduire que le sous-arbre de chacun de ces éléments contient au moins 2 bh(x) 1 1 nœuds. Finalement, le sous-arbre de x doit contenir au minimum (2 bh(x) 1 1) + (2 bh(x) 1 1) + 1 = 2 bh(x) 1 nœuds, ce qui prouve bien le lemme. Théorème 2. Un arbre rouge-noir T ayant n nœuds a une hauteur au plus égale à 2 lg(n + 1) + 2. Démonstration : Supposons que la hauteur de l arbre rouge-noir T vaut h. Étant donné que dans un chemin allant de la racine à un sous-arbre vide il ne peut y avoir deux arcs rouges successifs et que le bit de la racine est noir, il doit y avoir au moins h/2 nœuds ayant un bit noir sur ce chemin. Dès lors, bh(y) (où y est la racine de T ) vaut au moins h/2 1. Par le lemme 1, nous déduisons que T contient au moins 2 bh(y) 1 = 2 h/2 1 1 nœuds. Sachant que T contient exactement n nœuds, nous en déduisons l inégalité suivante : n 2 h/2 1 1 n +1 2 h/2 1 En prenant le logarithme des deux membres, nous obtenons : log(n + 1) h 2 1 log(n + 1) + 1 h 2 2 log(n + 1) + 2 h Ainsi, par cette propriété, nous constatons que la hauteur d un arbre rouge-noir à n nœuds vaut O(log n), ce qui implique que les opérations de recherche, d insertion, de successeur et de prédécesseur se font en O(logn) au pire cas. 5.3 Conclusion Dans ce chapitre, nous avons détaillé la structure des arbres rouges-noirs et analysé ses performances. Celle-ci fournit des performances intéressantes 36

38 pour une opération : un coût au pire cas de O(log n). Cependant, cette structure n atteint pas l optimalité dynamique, car elle est O(log n) compétitive. Un inconvénient de cette structure est qu elle n est pas capable de s adapter à la séquence d accès à traiter. Si par exemple une séquence d accès consiste à accéder plusieurs fois à un même nœud et que celui-ci se trouve au bas de l arbre, la structure effectuera chacun des accès à ce nœud avec un coût au pire cas de O(log n), alors qu en le remontant à la racine, elle aurait pu améliorer les accès à ce nœud. 37

39 Chapitre 6 Arbres binaires de recherche auto-ajustables Dans ce chapitre, nous allons d abord définir la notion d arbre binaire de recherche auto-ajustable. Ensuite, nous allons illustrer ce concept par la présentation des splay trees. Et nous terminerons par une comparaison entre les arbres rouges-noirs et les splay trees. 6.1 Définition Un arbre binaire de recherche auto-ajustable est un ABR sur lequel nous appliquons une règle après chaque opération dans le but d équilibrer l arbre. En général, le but de cette règle n est pas d avoir, à tout moment, une hauteur pour l arbre qui soit logarithmique en le nombre d éléments. Par contre, nous nous attendons à ce que, pour une séquence suffisamment longue, la règle équilibre l arbre de manière à avoir une complexité amortie (cfr point 2.4.3) logarithmique en la taille de l arbre. 6.2 Splay trees Cette partie contient une présentation des splay trees avec ses principales opérations et l analyse de ses performances. Le choix de cette structure autoajustable, plutôt qu une autre, se justifie par le fait que cette structure est sans conteste l une des plus intéressantes et l une des plus impressionnantes, qui ait jamais été développée. Elle possède un éventail de propriétés très large, bien qu elle soit définie sur une idée assez simple. La présentation de cette structure est basée sur l ouvrage de Jean Cardinal [Car04] et sur l article de Sleator et Tarjan [ST85]. 38

40 6.2.1 Splaying L opération de splaying sur un nœud x consiste à le remonter à la racine par une série de rotations. Trois types de rotations peuvent être employés : 1. la rotation simple (cfr point 2.1.4) : nous l appliquons si le nœud à splayer n a pas de grand-père. 2. la rotation zig-zag : nous l appliquons si le nœud à splayer est un fils gauche (respectivement fils droit) et que son père est un fils droit (respectivement fils gauche). Cette rotation est en fait une rotation double (cfr point 2.1.4). 3. la rotation zig-zig (cfr point 2.1.4) : nous l appliquons si le nœud à splayer est un fils gauche (respectivement fils droit) et que son père est un fils gauche (respectivement fils droit) Recherche L algorithme de recherche dans un splay tree est identique à l algorithme d accès des ABR défini pour le modèle dynamique (cfr point 2.2.1), hormis qu après avoir atteint le nœud désiré, il faut effectuer un splaying sur ce nœud Insertion L algorithme d insertion pour les splay trees est le suivant. En commençant le traitement à la racine, il faut effectuer les opérations suivantes : 1. Désignons par x le nœud courant. Il faut déplacer le pointeur courant sur le fils gauche ou le fils droit de x suivant que la clé à insérer soit, respectivement, plus petite ou plus grande que x. Cette première étape est à itérer tant que le nœud courant ne pointe pas sur un sous-arbre vide. 2. À ce niveau, le pointeur courant pointe sur un sous-arbre vide. Il ne suffit, dès lors, qu à insérer le nouveau nœud dans ce sous-arbre vide et à effectuer un splaying sur ce nœud Suppression L algorithme de suppression pour les splay trees est le suivant : 1. Rechercher l élément à supprimer en utilisant l algorithme de recherche. 39

41 2. Lorsque l élément est repéré, il faut le splayer. Par ce splaying, cet élément devient la racine de l arbre. 3. Enlever la racine de l arbre. Cette suppression a pour conséquence de créer deux sous-arbres T g et T d (T g est le sous-arbre gauche de la racine enlevée et T d est son sous-arbre droit). 4. Rechercher le plus grand élément de T g. Pour cela, il faut partir de la racine de l arbre et suivre le chemin des fils droits. Le dernier nœud rencontré sur ce chemin est l élément maximal de T g. 5. Réaliser un splaying du plus grand élément de T g. Cet élément devient alors la racine de T g et a un sous-arbre droit vide, car il est le plus grand élément de T g. 6. Fusionner T g et T d en accrochant T d comme sous-arbre droit de la racine de T g Analyse des performances L analyse des performances des splay trees se fera par une analyse amortie. Cette analyse nécessite donc d introduire une fonction potentiel (cfr point 2.4.3). Le choix de cette fonction est crucial, car de cette fonction dépendent les résultats que nous obtiendrons. Si nous utilisons une mauvaise fonction potentiel, nous ne parviendrons pas à démontrer les résultats escomptés. La fonction potentiel utilisée dans cette analyse est celle introduite par Sleator et Tarjan [ST85]. Elle est décrite dans le paragraphe ci-dessous. Supposons que chaque nœud x d un arbre T ait un poids w (x) ; il s agit d une valeur arbitraire positive, mais fixée. La taille s(x) d un nœud x est la somme des poids de tous les nœuds appartenant au sous-arbre de x (w (x) est inclus dans cette somme). Le rang r(x) d un nœud x est le logarithme en base 2 de sa taille. Finalement, le potentiel d un arbre T est la somme des rangs de tous ses nœuds. En résumé : w (x) R +, x T s(x) = j T x w (j), où T x est le sous-arbre de x. r(x) = log(s(x)), par log nous entendons logarithme en base 2. P (T )= x T r(x) En se basant sur cette fonction potentiel, nous pouvons démontrer le lemme suivant, qui est la propriété de base permettant de caractériser les performances amorties des splay trees. Nous nous limiterons pour chaque 40

42 propriété à l idée de la démonstration Access Lemma Le coût amorti nécessaire pour effectuer un splaying sur un nœud x dans un arbre de racine t est d au plus 3(r(t) - r(x)) + 1. La démonstration de ce lemme est décrite, notamment, dans l ouvrage de Weiss [Wei99]. L idée de la démonstration, est de calculer le coût d une rotation simple, d une rotation zig-zig et d une rotation zig-zag en se basant sur la fonction potentiel définie ci-dessus et utilisant l équation fondamentale pour définir une complexité amortie (C A = C E + P, cfr point 2.4.3). Le splaying étant une séquence de rotations simple, zig-zig et zig-zag, son coût peut alors être calculé à partir du coût de ces rotations. En partant de cette propriété, il est alors possible de démontrer toute une série de propriétés sur les splay trees en assignant des poids aux nœuds de l arbre. Les propriétés, ainsi déduites, sont présentées ci-dessous Théorème d équilibre Dans un arbre de taille n, le coût total de m opérations vaut O(m log n). La complexité amortie d une opération vaut alors O(log n). Pour démontrer ce théorème, il suffit d utiliser l Access Lemma et d assigner un poids de 1/n à chaque nœud de l arbre. Le théorème d équilibre est, donc, atteint en imposant une distribution uniforme sur les clés. Nous constatons, donc, que si la distribution sur les clés est uniforme, les splay trees ont un coût de recherche amorti égal au coût de recherche au pire cas d arbres équilibrés comme les arbres AVL et les arbres rouges-noirs et cela sans utiliser la moindre information de rééquilibrage Théorème d optimalité statique La notion d optimalité statique est définie au point 3.3 et est rappelée ci-dessous. Soient un arbre de taille n et une séquence d accès X = x 1,x 2,..., x m. Le temps d accès total de cette séquence de m opérations vaut : O ( n i=1 ( ) ) m f(i) log, (6.1) f(i) 41

43 où f(i) est la fréquence d accès du nœud i. Dès lors, f(i)/m est sa fréquence relative. Pour démontrer ce théorème, il suffit d utiliser l Access Lemma et d assigner à chaque nœud sa fréquence relative. En d autres termes, pour un nœud x i, son poids w (x i ) vaut f(x i )/m. Les ABRO [Knu73] (cfr chapitre 4) atteignent la propriété d optimalité statique, mais ils requièrent pour cela de connaître préalablement la fréquence de chaque nœud. Les splay trees atteignent l optimalité statique sans cette connaissance préalable de la fréquence de chaque nœud Théorème du static finger La notion de static finger est définie au point 3.2 et est rappelée ci-dessous. Soient un arbre de taille n, un nœud spécifique f appelé le finger et une séquence d accès X = x 1,x 2,..., x m. Le coût pour traiter cette séquence de m accès vaut : ( m ) O log(1 + x i f ), (6.2) i=1 où x i f est la distance dans l ordre symétrique entre le finger f et le nœud x i. Donc, x i f est le nombre d éléments situés entre x i et f dans la séquence triée des nœuds de l arbre. Pour démontrer ce théorème, il suffit d utiliser l Access Lemma et d assigner à chaque nœud x i de l arbre un poids w 1 (x i )égal à (1+ x i. f ) 2 Il est important de noter que le finger f est un nœud quelconque de l arbre, mais une fois choisi, ce finger doit rester le même durant toute l exécution de la séquence d accès. Ce qui est le plus remarquable est que les splay trees atteignent la propriété static finger pour un quelconque finger possible. En effet, il suffit d utiliser ce finger dans l assignation des poids aux nœuds Théorème du working set La notion de working set est définie au point 3.4 et est rappelée ci-dessous. Soient un arbre de taille n et une séquence d accès X = x 1,x 2,..., x m. Le coût pour traiter cette séquence de m accès vaut : ( m ) O log(w(x i )), (6.3) i=1 42

44 où w(x i ) est le nombre d éléments distincts entre l accès x i et le précédent accès à cet élément. L assignation des poids pour ce théorème est plus compliquée, car il faut modifier le poids des nœuds durant l exécution de la séquence Théorème du dynamic finger La notion de dynamic finger est définie au point 3.5 et est rappelée cidessous. Soient un arbre de taille n et une séquence X = x 1,x 2,..., x m. Le coût pour traiter cette séquence de m accès vaut : ( m 1 ) O log ( x j+1 x j + 1) (6.4) j=1 En 1985, époque de la publication de l article de Sleator et Tarjan [ST85], ce théorème n avait pas pu être démontré. Ce n est qu en 1995, que Cole [Col00] y est parvenu, mais la démonstration de ce théorème reste très complexe. Le splay tree est la seule structure ayant cette propriété et répondant à la définition du modèle dynamique des ABR (cfr point 2.2.1), mais la démonstration de cette propriété est complexe. Un problème intéressant (proposé par Stefan Langerman) serait d élaborer une structure relativement simple et ayant la propriété dynamic finger avec une démonstration de cette propriété plus simple que celle des splay trees Théorème du scanning Soient un arbre de taille n et une séquence d accès X =1, 2,..., n. Le coût pour traiter ces n accès vaut : O(n) (6.5) Ce théorème est en fait un corollaire du théorème dynamic finger. En effet, comme les nœuds sont accédés par ordre croissant sur les clés, nous avons que x j+1 x j = 1 ( j [1,n 1]). Et par conséquent, la complexité pour traiter X vaut O(n). 43

45 Conjecture d unifiée La notion d unifiée est définie au point 3.6 et est rappelée ci-dessous. Soient un arbre de taille n et une séquence d accès X = x 1,x 2,..., x m. Le coût pour traiter cette séquence de m accès vaut : ) O ( m i=1 min (log (w(i, j)+ x i j + 1)) j X (6.6) Cette propriété n a pas encore pu être démontrée pour les splay trees et elle reste donc une conjecture Conjecture d optimalité dynamique La notion d optimalité dynamique est définie au point 3.7 et est rappelée ci-dessous. Soient un arbre de taille n et une séquence d accès X. Le coût pour exécuter cette séquence vaut : O(OP T (X)) (6.7) Si cette conjecture est démontrée, cela signifierait que les splay trees peuvent exécuter n importe quelle séquence d accès avec un coût optimal et cela, par une simple règle de réarrangement et sans garder la moindre information supplémentaire. Ce serait comme si les splay trees étaient capables de prévoir la séquence à exécuter, de manière à pouvoir s y adapter et l exécuter de manière optimale. Cette propriété n est malheureusement pas encore démontrée pour les splay trees. Et à l heure actuelle, cette structure est l une des rares à encore pouvoir prétendre atteindre l optimalité dynamique. 6.3 Comparaisons Nous allons comparer les arbres rouges-noirs et les splay trees. Ces comparaisons sont en général valables pour les ABR équilibrés et les ABR autoajustables. Pour le temps d exécution au pire cas, les arbres rouges-noirs présentent des performances plus intéressantes que les splay trees. Les splay trees fournissent des performances intéressantes sur de longues séquences d accès, alors 44

46 que les arbres rouges-noirs ont pour but de fournir des résultats intéressants sur une seule opération. L inconvénient des splay trees est que les opérations de réorganisation peuvent être nombreuses, et ainsi coûter cher. Quant aux arbres rouges-noirs, les opérations de rééquilibrage restent limitées, et ne nuisent donc pas aux performances. Au niveau de l espace mémoire, les arbres rouges-noirs nécessitent de stocker un bit de couleur, alors que les splay trees n ont pas besoin d informations supplémentaires. Les arbres rouges-noirs nécessitent donc plus d espace mémoire, mais ce surplus reste limité (n bits pour un arbre de taille n). En ce qui concerne les propriétés atteintes par les structures, nous avons que les splay trees ont un éventail très large de propriétés, ce qui n est pas du tout le cas pour les arbres rouges-noirs. Nous remarquons, notamment grâce à ces propriétés, que les splay trees ont la capacité de s adapter à une séquence d accès. Ceci est dû au fait que les splay trees gardent près de la racine les nœuds fréquemment accédés. Les arbres rouges-noirs n ont pas cette capacité de s adapter à une séquence d accès, ce qui peut influer sur le temps d exécution de la séquence. Supposons par exemple, qu une séquence d accès consiste à accéder plusieurs fois à un même nœud x situé dans le bas de l arbre. Les arbres rouges-noirs effectueront chacun des accès à x avec un coût O(log n), alors que pour les splay trees, le premier accès à x se fera avec un coût égal à la profondeur de x et les accès suivants à x se feront en temps constant. 6.4 Conclusion Si la distribution sur les clés est uniforme (théorème d équilibre), la recherche pour les splay trees se fait avec une complexité amortie en O(log n). Mais pour une distribution qui n est pas uniforme (théorème d optimalité statique, théorème du static finger et théorème du working set), les résultats obtenus pour la recherche sont meilleurs que celui obtenu pour la distribution uniforme. On peut comprendre cela de manière intuitive. Si la distribution n est pas uniforme, certains éléments seront accédés plus souvent que d autres. Les éléments souvent accédés auront tendance à se situer en haut de l arbre, alors que les éléments moins fréquemment accédés se situeront dans le bas de l arbre. Et comme les éléments du haut sont plus souvent accédés, on aura plus d accès à faible coût, ce qui aura pour conséquence d améliorer le coût total de l exécution de la séquence d accès. 45

47 Troisième partie Optimalité dynamique 46

48 Chapitre 7 Bornes inférieures sur le coût des arbres binaires de recherche Ce chapitre est consacré au problème de borner inférieurement le coût d exécution d une séquence d accès par un ABR. L intérêt d avoir de telles bornes est double. D une part, il est possible de développer de nouvelles structures à partir d une borne inférieure (cela a par exemple été le cas pour la structure Tango que nous étudierons dans le chapitre 8). D autre part, il serait possible de prouver l optimalité dynamique grâce à une borne inférieure. En effet, si nous parvenons à démontrer que, pour un ABR, le coût d exécution d une quelconque séquence d accès est égal à la borne inférieure, alors nous en déduirons immédiatement que la structure est optimale dynamiquement. Dans ce chapitre, nous allons présenter trois bornes inférieures sur le temps d exécution d une séquence d accès : La Borne Inférieure de Couverture de Rectangle, La Borne Inférieure d Entrelacement et La Seconde Borne de Wilber. Les deux dernières bornes seront en fait dérivées de la première. Ce chapitre est basé sur l article de Derryberry, Sleator et Wang [DSW05], sur l article de Wilber [Wil89] et sur l article de Demaine, Harmon, Iacono et Patrascu [DHIP04]. 7.1 Modèle Pour prouver la borne inférieure de couverture de rectangle, nous devons passer au modèle standard. La différence entre ce modèle et le modèle dynamique (cfr point 2.2.1) est que le nœud à accéder doit d abord être ramené à la racine par une série de rotations. Ensuite, seulement, l accès au nœud se fait à la racine. Après l accès au nœud, l algorithme peut effectuer des rotations pour améliorer le coût des futurs accès. 47

49 Le coût d accès est défini comme le nombre de rotations plus 1. Comme une rotation est inversible, le coût dans le modèle standard vaut au plus deux fois celui dans le modèle dynamique. Par conséquent, si nous parvenons à déterminer une borne inférieure sur le coût d exécution d une séquence d accès dans le modèle standard, alors il suffit de prendre cette borne et de la diviser par deux pour obtenir une borne dans le modèle dynamique. 7.2 La borne inférieure de couverture de rectangle Considérons une séquence d accès comme un ensemble de points dans l espace à deux dimensions, où la coordonnée x correspond au temps et la coordonnée y correspond à l espace des clés. Pour une séquence X = x 1,x 2,..., x m, chaque accès x i correspond au point (i, x i ). Notons P l ensemble des points générés à partir de X. Une boîte est un rectangle, dont deux coins opposés sont des points de P. Nous considérons deux types de boîtes : les boîtes hautes et les boîtes basses. Une boîte est haute si ses coins inférieur gauche et supérieur droit sont dans P. Et une boîte est basse si ses coins supérieur gauche et inférieur droit sont dans P. Chaque boîte contient un diviseur, qui consiste en une ligne horizontale traversant la boîte d une extrémité à l autre. L ordonnée du diviseur est choisie de manière arbitraire, mais elle doit cependant être différente de l ordonnée de tous les points de P et elle doit être comprise entre l ordonnée minimale et l ordonnée maximale de la boîte. Deux boîtes sont dites en conflit si elles sont toutes deux des boîtes hautes ou des boîtes basses et si leur intersection contient une partie ou l entièreté des deux diviseurs. Pour illustrer ces définitions, considérons le schéma de la figure 7.1 représentant les points correspondant à la séquence X = 3(x 1 ), 5(x 2 ), 1(x 3 ), 7(x 4 ), 10(x 5 ), 2(x 6 ). Trois boîtes sont illustrées sur ce schéma (les diviseurs sont représentés en pointillés). Les boîtes A et B sont hautes, tandis que la boîte C est basse. De plus, les boîtes A et B sont en conflit, alors que les boîtes B et C ne le sont pas. Avant d énoncer et de démontrer la borne inférieure de couverture de rectangle, nous prouvons le lemme qui suit. Nous notons par LCA(x, y) l ancêtre commun le plus bas des nœuds x et y. Les démonstrations du lemme 2 et du théorème qui suit ce lemme sont basées sur l article [DSW05]. La contribution personnelle dans ces deux démonstrations a consisté à aller plus dans le 48

50 Fig. 7.1 Représentation graphique de la séquence X =3, 5, 1, 7, 10, 2. 49

51 détail en éclaircissant certains points de la démonstration. Lemme 2. Soient a et b deux nœuds distincts dans un ABR T avec a<b. Soient p et c deux nœuds de T avec p parent de c. Si une rotation est effectuée sur les nœuds c et p et qu elle implique que LCA(a, b) change, alors les quatre propriétés suivantes sont vérifiées : 1. a c b 2. a p b 3. LCA(a, b) =p avant la rotation 4. LCA(a, b) =c après la rotation Démonstration : Considérons une permutation Π des clés de T, où ces clés sont triées par ordre croissant de profondeur. Les cas d égalité pour des nœuds ayant la même profondeur sont gérés arbitrairement. On impose une contrainte : les nœuds p et c doivent être adjacents (p précède alors c, car il a une profondeur plus petite que celle de c). Comme les nœuds sont triés par ordre croissant de profondeur, l arbre obtenu en insérant de manière successive les clés de Π à partir d un arbre vide est T. Notons que LCA(a, b) est le nœud le moins profond ayant une valeur comprise entre a et b, car tous les autres nœuds ayant une valeur comprise entre a et b appartiennent au sous-arbre de LCA(a, b). Par conséquent, LCA(a, b) est le premier nœud dans Π ayant une valeur comprise entre a et b. Si nous permutons les nœuds p et c dans Π, l arbre obtenu à partir de cette séquence est celui que nous obtenons en effectuant une rotation sur c et p dans T, et cela parce que la permutation de p et c dans Π implique que le nœud c est inséré avant p. La séquence Π est donc une autre manière de représenter une rotation sur p et c, ainsi que LCA(a, b). Supposons que nous réalisons une rotation sur p et c, et que cela ait comme conséquence que LCA(a, b) change. Cela signifie, qu au niveau de Π, le fait de permuter p et c implique que le premier nœud dans Π ayant une valeur entre a et b change. Nous en déduisons alors que les nœuds p et c appartiennent à l intervalle [a, b], car sinon la permutation de p et c dans Π n aurait pas modifié le premier élément de Π appartenant à[a, b]. De plus, comme le premier élément de Π appartenant à[a, b] est modifié par la permutation de p et c, nous en déduisons que LCA(a, b) était égal à p avant la rotation et que LCA(a, b) vaut c après la rotation. 50

52 Théorème 3 (Théorème de la borne inférieure de couverture de rectangle). Soient une séquence d accès X = x 1,x 2,..., x m et un ensemble P de points correspondant à X. Soit B un ensemble de boîtes pour P, qui prises deux à deux, ne sont pas en conflit. Le nombre de rotations nécessaires à un ABR (répondant à la définition du modèle standard) pour traiter X vaut au moins B. Démonstration : Nous allons associer à chaque boîte B k de B une rotation R k réalisée par l ABR pour traiter X. À deux boîtes ne sera pas associée la même rotation, ce qui permettra de déduire que le nombre de rotations effectuées par l ABR pour traiter X vaut au moins le nombre de boîtes dans B. Considérons une boîte haute B k. Disons que le point (i, x i ) est son coin inférieur gauche et que le point (j, x j ) est son coin supérieur droit. Après l accès x i, nous avons que ce nœud devient la racine de l arbre. De même, après l accès x j, nous avons que ce nœud-ci devient la racine de l arbre. L intervalle de temps couvert par la boîte vaut [i, j]. Au début de cet intervalle, LCA(x i,x j ) vaut x i, car ce nœud est la racine de l arbre et à la fin de l intervalle, LCA(x i,x j ) vaut x j, car ce nœud-ci est la racine de l arbre. Par conséquent, durant l intervalle [i, j], nous avons que LCA(x i,x j ) a dû passer d une valeur inférieure au diviseur de B k à une valeur supérieure au diviseur de B k. La rotation R k associée à B k est la première, qui implique que LCA(x i,x j ) traverse le diviseur de B k de bas en haut. Par le lemme 2, si LCA(x i,x j ) change à cause d une rotation, alors cette rotation est appliquée sur deux éléments p et c appartenant à l intervalle [x i,x j ]. Les points correspondant à ces deux clés ont donc une ordonnée comprise entre x i et x j. La rotation R k est représentée par une ligne verticale traversant le diviseur de la boîte B k (cfr figure 7.2). Une rotation R k ne peut pas être associée à deux boîtes hautes différentes. En effet, supposons que R k soit associée à deux boîtes différentes B l et B k. Dès lors, R k doit traverser le diviseur de B l et de B k. L intersection de B l et de B k doit contenir R k et par conséquent les diviseurs de B l et de B k. Or, cela implique que B l et B k soient en conflit, ce qui est impossible car ces deux boîtes appartiennent à B et ne sont par définition pas en conflit. De manière analogue, nous pouvons montrer qu une rotation R k ne peut pas être associée à deux boîtes basses différentes. Une rotation R k ne peut pas être associée à une boîte basse et à une boîte haute. Nous prouvons ceci en montrant que la rotation associée à une boîte haute est une rotation gauche et la rotation associée à une boîte basse est une rotation droite. En effet, considérons la boîte haute B k et la rotation R k 51

53 Fig. 7.2 Rotation R k représentée par une flèche. 52

54 p c c p Fig. 7.3 Avant la rotation on a que p est le parent de c et que p < c qui y est associée et qui porte sur p et c (avec p parent de c). Comme cette rotation entre p et c implique que LCA(x i,x j ) passe d une valeur inférieure au diviseur de B k à une valeur supérieure au diviseur de B k, alors nous avons que p < c par le lemme 2, car LCA(x i,x j ) = p avant la rotation R k et LCA(x i,x j )=c après cette rotation. Et comme p est le père de c, alors la rotation entre p et c est une rotation gauche (cfr figure 7.3). Nous pouvons montrer de manière analogue que la rotation associée à une boîte basse est une rotation droite. En conclusion, nous avons montré qu une rotation ne peut pas être associée à deux boîtes différentes, ce qui prouve bien la borne inférieure de couverture de rectangle. 7.3 Applications de la borne inférieure de couverture de rectangle Dans cette section, nous allons dériver deux bornes à partir de la borne inférieure de couverture de rectangle : 1. la borne inférieure d entrelacement. Cette borne a été développée par Demaine, Harmon, Iacono et Patrascu [DHIP04]. 2. la seconde borne de Wilber. Cette borne a été développée par Wilber [Wil89] Les démonstrations dans cette section sont basées sur l article [DSW05]. La contribution personnelle a consisté à détailler les démonstrations en y éclaircissant certains points. 53

55 7.3.1 La borne inférieure d entrelacement Soient un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. La région gauche d un nœud x i correspond à x i plus son sousarbre gauche et la région droite de x i correspond à son sous-arbre droit. Nous définissons ci-dessous la borne inférieure d entrelacement en expliquant la manière de la calculer. Le calcul de la borne inférieure d entrelacement nécessite de maintenir un arbre parfait P sur les clés 1, 2,..., n. Pour calculer l entrelacement IB(X, y) d un nœud y, il faut étiqueter chaque accès x i de X par left si x i appartient à la région gauche de y ou par right si x i appartient à la région droite de y ; si x i n appartient à aucune des deux régions, il faut l exclure de la séquence étiquetée. IB(X, y) correspond alors au nombre d alternances entre les labels left et right dans la séquence étiquetée créée. La borne inférieure d entrelacement IB(X) de la séquence X correspond à la somme des entrelacements IB(X, y) de chaque nœud y dans P. Nous avons donc : IB(X) = y P IB(X, y) (7.1) Théorème 4 (Théorème de la borne inférieure d entrelacement). Soient un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Dans le modèle standard, nous avons la borne inférieure suivante sur le coût optimal OPT(X) de l algorithme offline pour traiter X : OP T (X) IB(X)+m (7.2) Démonstration : Pour prouver ce théorème, il faut montrer que nous pouvons placer une boîte haute pour chaque alternance left-right et une boîte basse pour chaque alternance right-left, de sorte que les boîtes prises deux à deux ne sont pas en conflit. Comme les boîtes hautes et les boîtes basses ne peuvent pas être en conflit, il suffit de démontrer que deux boîtes hautes ne peuvent pas être en conflit et que deux boîtes basses ne peuvent pas être en conflit. Supposons que pour un nœud v, il y ait une alternance left-right dans la séquence étiquetée au temps r. La boîte haute, correspondant à cette alternance, est construite de la manière suivante. Soit x l le dernier accès ayant lieu dans le sous-arbre gauche de v strictement avant le temps r. Disons que cet accès ait eu lieu au temps l (l < r). Et soit x r l accès ayant provoqué l alternance left-right au temps r. Nous créons la boîte correspondant à cette alternance avec (l, x l ) comme coin inférieur gauche, (r, x r ) comme coin 54

56 supérieur droit et v ε comme diviseur (avec ε très petit). Nous dénotons cette boîte par le triplet ((l, x l ), (r, x r ),v ε). Considérons deux boîtes hautes : B = ((l, x l ), (r, x r ),v ε) et B = ((l,x l ), (r,x r ),v ε). Quatre cas sont à envisager : 1. si v = v, alors les boîtes B et B ne peuvent pas se chevaucher, car les intervalles [l, r] et [l,r ] sont soit disjoints, soit adjacents. Et donc, les boîtes ne peuvent pas être en conflit. 2. si v n est pas un ancêtre de v et si v n est pas un ancêtre de v, alors l espace des clés [x l,x r ] correspondant à l espace des ordonnées de la boîte B et l espace de clés [x l,x r ] correspondant à l espace des ordonnées de la boîte B sont disjoints. Ces deux boîtes ne peuvent donc pas être en conflit. 3. si v est un ancêtre de v et si v < v, alors v appartient au sous-arbre gauche de v. Et donc, tous les éléments dans l espace des clés [x l,x r ] de B sont strictement plus petits que v. De plus, comme B est une boîte haute, nous avons que x l <x r. Tout ceci nous permet de déduire que x l <x r v 1 <v ε. Ainsi, B ne peut pas contenir le diviseur de B et les boîtes B et B ne peuvent donc pas être en conflit. 4. si v est un ancêtre de v et si v > v, alors v appartient au sous-arbre droit de v. Et donc, tous les éléments dans l espace des clés [x l,x r ] de B sont strictement plus grands que v. De plus, comme B est une boîte haute, nous avons que x l <x r. Tout ceci nous permet de déduire que x r >x l v +1>v ε. Ainsi, B ne peut pas contenir le diviseur de B et les boîtes B et B ne peuvent donc pas être en conflit. Les cas où v est un ancêtre de v sont similaires au cas 3 et 4. Et les cas où B et B sont des boîtes basses sont analogues aux quatre cas ci-dessus. Nous avons donc prouvé que dans tous les cas possibles B et B ne peuvent pas être en conflit. Par conséquent, nous avons prouvé que IB(X) est une borne inférieure sur le nombre de rotations nécessaires à un algorithme pour traiter une séquence X = x 1,x 2,..., x m. Comme le coût d un algorithme pour traiter la séquence X vaut le nombre de rotations effectuées plus m (un coût de 1 est nécessaire pour accéder au nœud ramené à la racine), alors nous pouvons rajouter m à la borne inférieure IB(X). Finalement, nous avons que : OP T (X) IB(X)+m (7.3) Corollaire 1. Soient un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Dans le modèle dynamique, nous avons la borne 55

57 inférieure suivante sur le coût optimal OPT(X) de l algorithme offline pour traiter X : OP T (X) 1 (IB(X)+m) (7.4) La seconde borne de Wilber Soient un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. De manière informelle, nous pouvons définir cette borne de la manière suivante. Pour chaque accès x i de X, nous commençons la traversée de la séquence à partir de x i 1 en reculant jusqu à x 1. Nous gardons à chaque étape une trace des deux accès les plus proches de x i ; l un devant être plus petit que x i et l autre plus grand que x i. La seconde borne de Wilber pour un accès x i est le nombre de fois qu un record de proximité s est produit sur un côté différent du dernier record. La seconde borne de Wilber pour la séquence X est égale à la somme des secondes bornes de Wilber de chaque accès de X. De manière formelle, pour déterminer la seconde borne de Wilber pour l accès x i, il faut trouver la sous-séquence de taille maximale constituée d accès traversants x c1,..., x ck(i)+1 (K(i) est alors égal à la seconde borne de Wilber pour l accès x i ) (si nous prenons deux accès adjacents de cette séquence, alors ils représentent une amélioration du record de proximité, mais sur des côtés différents par rapport à x i ) et une sous-séquence d accès intérieurs x b1,..., x bk(i) telles que : 1. Pour s assurer que les accès traversants et les accès intérieurs reculent dans le temps, il faut que : c j+1 <b j c j c 1 = i 1 (7.5) 2. Pour s assurer que deux accès traversants successifs se trouvent sur deux côtés différents de x i, il faut que j [1,K(i)] : 3. b j est défini comme suit j [1,K(i)] : (x cj+1 x i ) (x cj x i ) 0 (7.6) S j = k (c j+1 < k < i) ((x cj x i ) (x k x i ) > 0) b j = min k S j x k x i Si le minimum est atteint pour plusieurs k S j, alors par convention, nous prenons celui dont la valeur est la plus petite. Cette définition de 56

58 b j assure que x bj est l élément de l ensemble M (M est l ensemble des éléments de X qui ont un indice dans l intervalle (c j+1,i)) qui est le plus proche de x i et qui se trouve du même côté que x cj. 4. Pour s assurer que x cj+2 ( j [1,K(i) 1]) est un nouveau record, il faut que : x cj+2 x i < x bj x i (7.7) Tous les éléments qui appartiennent à l ensemble M (M est l ensemble des éléments de X qui ont un indice dans l intervalle (c j+1,i)) et qui sont du même côté que x cj+2 (par rapport à x i ) sont plus éloignés de x i que l est x cj+2. La seconde borne de Wilber pour la séquence X est égale à: m K(i) (7.8) i=1 Pour illustrer cette définition, prenons la séquence X = 7(x 1 ), 15(x 2 ), 1(x 3 ), 2(x 4 ), 5(x 5 ), 20(x 6 ), 23(x 7 ), 10(x 8 ). La seconde borne de Wilber pour l accès 10 vaut 3, car il s agit du nombre de fois qu un record de proximité est amélioré sur un côté différent par rapport à 10 (cfr figure 7.4). Calculons cette borne en utilisant la définition formelle. Nous calculons donc la valeur de K(8). Pour cela, prenons les valeurs suivantes pour les indices des accès traversants : 1. c 1 = 7 (donc x c1 = 23) 2. c 2 = 5 (donc x c2 = 5) 3. c 3 = 2 (donc x c3 = 15) 4. c 4 = 1 (donc x c4 = x ck(8)+1 = 7) Nous pouvons alors calculer la valeur de S j (pour j =1, 2, 3 et 4) définie à la propriété 3 pour en déduire que : 1. b 1 = 6 (donc x b1 = 20), car S 1 = 6, 7 2. b 2 = 5 (donc x b2 = 5), car S 2 = 3, 4, 5 3. b 3 = 2 (donc x b3 = 15), car S 3 = 2, 6, 7 Les sous-séquences d accès traversants 23, 5, 15, 7 et d accès internes 20, 5, 15 vérifient les quatre propriétés et sont maximales. Nous avons donc que la seconde borne de Wilber pour l accès 10 vaut 3, car K(8) = 3. 57

59 Fig. 7.4 La seconde borne de Wilber pour l accès 10 vaut 3. 58

60 Théorème 5 (Théorème de la seconde borne de Wilber). Soient un ensemble de n clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. Le nombre de rotations nécessaires dans le modèle standard pour traiter la séquence X vaut au moins m i=1 K(i). Et donc, OP T (X) m + m K(i) (7.9) Ce théorème n est pas démontré ici, mais une démonstration est disponible dans l article [DSW05]. i=1 7.4 Conclusion Dans ce chapitre, nous avons présenté trois bornes inférieures sur le temps d exécution d une séquence d accès. La première borne, la borne inférieure de couverture de rectangle, nous a permis d en dériver deux autres : la borne inférieure d entrelacement et la seconde borne de Wilber. La borne inférieure d entrelacement sera utilisée pour élaborer une structure ABR dans le chapitre suivant. Cette borne est en fait une simplification de la Première Borne de Wilber [Wil89]. Et la seconde borne de Wilber est utilisée dans un concept particulier appelé Key-Independent Optimality [Iac05]. Un problème [DSW05] concernant la borne inférieure de couverture de rectangle est de savoir si cette borne est égale à l optimalité dynamique (à un facteur constant près). Un autre problème [DSW05] concernant cette borne est de savoir si elle peut être calculée en temps polynomial, car la valeur de cette borne est égale à B, c est-à-dire au nombre de boîtes qui prises deux à deux ne sont pas en conflit, mais ce nombre dépend de la manière dont on place les diviseurs des boîtes. 59

61 Chapitre 8 Tango Tango est une structure de données, qui atteint un taux de compétitivité de O(log(log n)). Il s agit de la première structure de données, qui a amélioré le taux de compétitivité trivial de O(log n). Elle a été élaborée en 2004 par Demaine, Harmon, Iacono et Patrascu [DHIP04] et constitue une très grande avancée dans le domaine de l optimalité dynamique. Dans ce chapitre, nous commencerons par présenter Tango selon une première approche, qui ne vérifie pas la définition du modèle dynamique des ABR (cfr point 2.2.1). Cette approche est nécessaire pour comprendre les fondements du véritable algorithme. Ensuite, nous montrerons comment réaliser cet algorithme avec une structure ABR. Et pour finir, nous analyserons les performances de Tango. 8.1 Structures de données Les sections présentant l algorithme Tango sont basées sur l article [DHIP04]. Cet article présente les grandes lignes de l algorithme. La contribution personnelle a été de présenter cet algorithme en détaillant tous les sous-algorithmes qui le constituent. Supposons que nous ayons un ensemble 1, 2,..., n de n clés et une séquence X = x 1,x 2,..., x m. Nous notons par T i l état de Tango après avoir effectué les accès x 1,x 2,..., x i. À côté de cette structure, nous maintenons également un arbre parfait P, appelé arbre de référence, construit sur les mêmes clés que celles de T. Chaque nœud de l arbre P contient une information supplémentaire : son fils préféré. Le fils préféré d un nœud x est son fils gauche si le dernier accès dans le sous-arbre de x dans P a eu lieu dans le sous-arbre gauche de x ou s il consistait à atteindre x. Le fils préféré de x est son fils droit si le 60

62 dernier accès dans le sous-arbre de x dans P a eu lieu dans le sous-arbre droit de x. Dans le cas où aucun accès n a eu lieu dans le sous-arbre de x, alors x n a pas de fils préféré. L arbre P est fixe durant toute l exécution de la séquence X ; seul le fils préféré des nœuds peut changer. Ainsi, l état P i de l arbre P au temps i (l état de P après avoir exécuté les accès x 1,x 2,..., x i ) est seulement déterminé par la séquence d accès. 8.2 Algorithme de l arbre de référence L état T i de Tango est déterminé à partir de l état P i en appliquant l algorithme suivant : 1. Suivre le fils préféré de la racine, puis le fils préféré de ce fils, et ainsi de suite jusqu à atteindre une feuille. Nous obtenons, alors, un chemin allant de la racine à une feuille, qu on appelle le chemin préféré. 2. Compresser ce chemin en un arbre auxiliaire R. À ce stade-ci, nous pouvons nous contenter d admettre qu un arbre auxiliaire est un arbre rouge-noir. Des informations supplémentaires seront fournies plus loin dans ce chapitre sur les arbres auxiliaires. 3. Supprimer ce chemin préféré de P i. Cela a pour conséquence de partitionner cet arbre en plusieurs pièces. 4. Procéder de manière récursive sur chacune de ces pièces. Nous obtenons, alors, un arbre auxiliaire pour chaque pièce. Il ne reste dès lors qu à accrocher chacun de ces arbres obtenus à l arbre auxiliaire R, tout en respectant l ordre ABR sur les nœuds de l arbre. Pour rappel, l ordre ABR signifie que, pour chaque nœud x de l arbre, les éléments dans le sous-arbre gauche de x sont plus petits que x et les éléments dans le sous-arbre droit de x sont plus grands que x. Nous déduisons de cette construction, que l arbre T i est un arbre d arbres auxiliaires, dans lequel l ordre ABR est vérifié. Nous allons illustrer l algorithme présenté ci-dessus avec un exemple. Supposons que nous ayons l arbre P i de la figure 8.1 et que nous désirons construire l arbre T i. Le chemin préféré de l arbre de la figure 8.1 est constitué des nœuds 3, 1 et 2. Il faut, alors, compresser ce chemin en un arbre auxiliaire. L article [DHIP04] ne précise pas comment compresser ce chemin. Nous allons, alors, choisir de réaliser cette compression en insérant, à l aide de l algorithme d insertion des arbres rouges-noirs (cfr point 5.2.3), de manière successive les nœuds du chemin préféré en partant d un arbre vide et en commençant les 61

63 3 = fils non préféré = fils préféré Fig. 8.1 Arbre P i. insertions avec le nœud racine. Ainsi, pour compresser le chemin préféré de la figure 8.1, il suffit d effectuer l opération d insertion sur les nœuds 3, 1 et 2. Le résultat de ces opérations donne l arbre auxiliaire de la figure 8.2, que nous désignons par R i Maintenant, que le chemin préféré de P i est compressé, il faut le supprimer de l arbre P i. Ceci partitionne P i en deux pièces (Pi 1 et Pi 2 ) présentées à la figure 8.3. Et il ne reste qu à effectuer les mêmes opérations sur chaque pièce. Nous traitons, d abord, la pièce Pi 1 constituée du nœud 0. Sa transformation en arbre auxiliaire est triviale et consiste en le nœud 0. Nous désignons cet arbre auxiliaire par Ri 1. Nous traitons, maintenant, la dernière pièce Pi 2 constituée des nœuds 4, 5 et 6. Le chemin préféré de cet arbre est constitué des nœuds 5 et 6. La compression de ce chemin, notée R 3, est donnée à la figure 8.4. Après cette compression, il faut retirer le chemin préféré de Pi 2, ce qui donne une unique pièce consistant en le nœud 4. La transformation de cette pièce en arbre auxiliaire est triviale. Nous désignons par R 4 cet arbre auxiliaire. Maintenant, il faut rassembler chaque arbre auxiliaire obtenu. On commence par placer R 4 comme fils gauche de la racine de R 3, pour obtenir l arbre auxiliaire relatif à Pi 2. L agencement de R 3 et R 4 est réalisé de la sorte, de manière à respecter l ordre ABR. Ce nouvel arbre auxiliaire est représenté à la figure 8.5 et est noté Ri 2. À présent, il ne reste plus qu à attacher Ri 1 et R2 i à R i pour obtenir l arbre auxiliaire T i correspondant à P i. L arbre Ri 1 est placé comme fils gauche du 62

64 2 = arc rouge = arc noir = l isroot bit est activé 1 3 = l isroot bit est désactivé Fig. 8.2 Arbre R i correspondant à la compression du chemin préféré 3, 1, Fig. 8.3 À gauche, l arbre P 1 i et à droite, l arbre P 2 i. 63

65 5 6 Fig. 8.4 Arbre R 3 correspondant à la compression du chemin préféré 5, Fig. 8.5 Arbre R 2 i obtenu en attachant R 4 à R 3. 64

66 Fig. 8.6 Arbre T i obtenu en attachant R 1 i et R 2 i à R i. nœud 1 de R i et l arbre Ri 2 est placé comme fils droit du nœud 3 de R i, de manière à vérifier l ordre ABR. L arbre résultant T i est présenté à la figure 8.6 et correspond à la transformation de P i par l algorithme Tango. Il existe deux principaux inconvénients avec cette première approche de Tango : 1. la transformation de P i en T i est fort coûteuse en temps d exécution, ce qui nuit aux performances de l algorithme. 2. cette approche ne vérifie pas la définition du modèle ABR, car deux arbres sont utilisés par l algorithme. Cependant, cette première approche permet d avoir une idée globale des principes de l algorithme Tango et aidera à la compréhension du véritable 65

67 algorithme. 8.3 Arbres auxiliaires Avant de présenter l algorithme Tango, nous avons besoin de définir les arbres auxiliaires, ainsi que quatre opérations supportées par cette structure : 1. la concaténation (cet algorithme provient de l article [Sah05]) 2. l éclatement (cet algorithme provient de l article [Sah05]) 3. le cutting (cet algorithme provient de l article [DHIP04]) 4. le joining (cet algorithme provient de l article [DHIP04]) Les deux premières opérations sont définies pour être utilisées par les deux dernières Définition Un arbre auxiliaire est une structure, qui contient un sous-chemin d un chemin allant de la racine à une feuille de P (les nœuds de ce sous-chemin sont reliés par des arêtes fils préféré dans P ). Les nœuds d un arbre auxiliaire sont organisés en fonction de la valeur de leur clé. Chaque nœud x d un arbre auxiliaire contient des informations supplémentaires : 1. la profondeur du nœud x dans l arbre parfait P. Cette donnée est fixe durant toute l exécution d une séquence et est comprise dans l intervalle [0, log(n + 1)). Cette information sera désignée par le terme prof. 2. la profondeur maximale dans P des nœuds appartenant au sous-arbre de x dans T. Cette information sera désignée par le terme profondeur- Max. 3. la profondeur minimale dans P des nœuds appartenant au sous-arbre de x dans T. Cette information sera désignée par le terme profondeurmin. 4. un bit, nommé isroot, pour indiquer si x est la racine de l arbre auxiliaire, auquel il appartient. Tango étant un arbre d arbres auxiliaires, il arrivera, donc, qu une feuille d un arbre auxiliaire ait comme fils la racine d un autre arbre auxiliaire. L isroot bit permet, donc, d indiquer s il y a eu un passage d un arbre auxiliaire à un autre. Il est important de noter qu un arbre auxiliaire est implémenté comme un arbre rouge-noir. 66

68 8.3.2 Concaténation Cette opération porte sur un arbre D tel que la racine est x, le sous-arbre gauche A de x est un arbre rouge-noir et le sous-arbre droit B de x est un arbre rouge-noir ; l arbre D n étant pas nécessairement un arbre rouge-noir. Le but de la concaténation est de construire à partir de A, B et x un arbre rouge-noir. Pour réaliser cette opération de manière efficace, il est nécessaire que chaque nœud x de l arbre stocke une information supplémentaire : sa hauteur noire bh(x) (pour rappel bh(x) est le nombre de nœuds ayant un bit noir entre x (inclus) et la feuille la plus profonde de x moins 1). L opération de concaténation se réalise par l algorithme suivant : 1. Si la hauteur noire de la racine de A est égale à la hauteur noire de la racine de B, nous construisons l arbre rouge-noir C avec x comme racine, A comme sous-arbre gauche de x et B comme sous-arbre droit de x. On colorie les arcs liant x à A et x à B en noir. La hauteur noire de x est alors définie comme la hauteur noire de la racine de A plus Si la hauteur noire de la racine de A est plus grande que la hauteur noire de la racine de B, il faut suivre le chemin des fils droits de A jusqu au premier nœud y ayant une hauteur noire égale à celle de la racine de B. Il faut remarquer que la hauteur noire du père p de y doit être égale à bh(b) 1 (où bh(b) correspond à la hauteur noire de la racine de B), car sinon il aurait été le premier nœud sur le chemin des fils droits à avoir une hauteur noire égale à bh(b). Désignons par Y le sous-arbre de y. Nous retirons Y de l arbre A pour placer le nœud x à la place de Y. Pour que le nœud x ait une hauteur noire égale à bh(b) 1, nous colorions l arc entre x et p en rouge. Si l arc entre g (le père de p) et p est rouge, alors il faut effectuer une rotation simple entre g et p. Cette rotation laisse x sans fils, car il n en avait pas avant la rotation entre g et p (cfr figure 8.7). Ensuite, il faut attacher Y comme fils gauche de x en coloriant l arc en noir et l arbre B comme fils droit de x en coloriant l arc en noir. 3. Si la hauteur noire de la racine de A est plus petite que la hauteur noire de la racine de B, nous procédons de manière symétrique au cas 2 sur l arbre B Éclatement L opération d éclatement porte sur un arbre auxiliaire C et sur un nœud x de cet arbre. Elle réorganise C, de manière à ramener x à la racine de 67

69 Fig. 8.7 Rotation simple sur les nœuds g et p. l arbre avec comme sous-arbre gauche de x un arbre rouge-noir, noté A, et comme sous-arbre droit de x un arbre rouge-noir, noté B. Pour réaliser l éclatement, il faut d abord construire les arbres A et B à partir de C avec l algorithme suivant. Au début les arbres A et B sont vides. 1. Rechercher le nœud x dans C. Lorsque x est localisé, il faut rajouter dans A le sous-arbre gauche de x et dans B le sous-arbre droit de x. 2. Ensuite, il faut remonter le chemin de x à la racine et réaliser l étape, qui suit, jusqu à ce que la racine soit atteinte. 3. Soit p le nœud courant. Deux cas doivent être envisagés, selon que x se situe dans le sous-arbre gauche ou dans le sous-arbre droit de p : (a) si x est dans le sous-arbre gauche de p, alors le sous-arbre droit de p contient des nœuds ayant des valeurs plus grandes que celle de x. Ces nœuds doivent, donc, se situer dans l arbre B. Dès lors, nous effectuons une concaténation avec B, p et le sous-arbre droit de p. Cette concaténation donne un arbre rouge-noir, qui devient B. (b) si x est dans le sous-arbre droit de p, alors le sous-arbre gauche de p contient des nœuds ayant des valeurs plus petites que celle de x. Ces nœuds doivent, donc, se situer dans l arbre A. Dès lors, nous effectuons une concaténation avec A, p et le sous-arbre gauche de p. Cette concaténation donne un arbre rouge-noir, qui devient A. 68

70 4. Lorsque tous les éléments sur le chemin de la remontée sont traités, nous obtenons que A forme un arbre rouge-noir avec des éléments ayant des valeurs plus petites que celle de x et que B forme un arbre rouge-noir avec des éléments ayant des valeurs plus grandes que celle de x. Une fois A et B créés, il suffit d attacher A comme sous-arbre gauche de x avec un arc noir et B comme sous-arbre droit de x avec un arc noir. Bien que cela ne soit pas trivialement vérifiable, la complexité de cette opération est logarithmique en le nombre d éléments dans l arbre [Sah05] Cutting Le cutting à une profondeur d sur un arbre auxiliaire coupe cet arbre en deux arbres auxiliaires. L un stockant les nœuds, dont l information prof est plus petite que d. L autre stockant les nœuds, dont l information prof est plus grande que d. Un arbre auxiliaire A stocke un sous-chemin C d un chemin allant de la racine à une feuille de P. Par conséquent, l opération de cutting à une profondeur d sur l arbre A consiste, au niveau de l arbre P,à scinder C en deux parties. La première partie part du début du chemin C jusqu au nœud de profondeur d 1 et la seconde partie part du nœud de profondeur d jusqu à la fin du chemin C. Ces deux parties correspondent aux deux arbres auxiliaires créés par le cutting. Les nœuds d un arbre auxiliaire A, qui ont une information prof plus grande que d, forment un intervalle I dans l espace des clés de cet arbre. Ceci est dû au fait que les nœuds de cet arbre auxiliaire appartiennent à un même sous-chemin d un chemin allant de la racine à une feuille dans P. L opération de cutting se base sur cette propriété. Pour réaliser un cutting à une profondeur d, il faut d abord déterminer les éléments minimal et maximal de l intervalle I. Il faut, donc, trouver l élément minimal de A ayant une profondeur plus grande que d (ou égale à d) et l élément maximal de A ayant une profondeur plus grande que d (ou égale à d). Nous désignerons, respectivement, ces éléments par l et r. Le nœud l est l élément de l arbre A le plus à gauche et ayant une profondeur plus grande que d. Déterminer l peut se faire par l algorithme suivant : 1. Commencer le traitement à la racine de A. 2. Analyser l information prof du nœud courant x : (a) Si l information prof est supérieure à d, alors il faut analyser l information profondeurmax du fils gauche de x : 69

71 i. Si l information profondeurmax du fils gauche de x est plus grande que d, alors il existe dans le sous-arbre du fils gauche de x un nœud plus petit que le nœud courant x et ayant une information prof plus grande que d. Dès lors, il faut se déplacer sur le fils gauche de x et recommencer l étape 2. ii. Si l information profondeurmax du fils gauche de x est strictement plus petite que d, alors il n existe pas de nœud plus petit que x et ayant une information prof plus grande que d. Le nœud x correspond, alors, à l et l algorithme est arrêté. (b) Si l information prof est strictement plus petite que d, alors il faut analyser l information profondeurmax des fils de x : i. Si l information profondeurmax du fils gauche de x est plus grande que d, alors il faut se déplacer sur le fils gauche de x, car le nœud l se situe dans le sous-arbre gauche de x. ii. Si l information profondeurmax du fils droit de x est plus grande que d, alors il faut se positionner sur le fils droit de x, car le nœud l se situe dans le sous-arbre droit de x. iii. Si l information profondeurmax du fils gauche et du fils droit de x est plus grande que d, alors il faut se positionner sur le fils gauche de x, plutôt que le fils droit. En effet, comme le sous-arbre gauche de x contient des clés plus petites que celles du sous-arbre droit de x, on est certain que l se situe dans le sous-arbre gauche de x, et non pas dans le sous-arbre droit de x. Cet algorithme n est correct que s il existe un nœud l dans l arbre auxiliaire A. Pour traiter le cas, où il n existe pas un tel nœud dans A, il suffit d examiner l information profondeurmax de la racine de A. Si cette information est strictement plus petite que d, alors il n existe pas de nœud l dans A. Par contre, si elle est plus grande que d, le nœud l existe et l algorithme ci-dessus peut être appliqué. Quant au nœud r, il s agit de l élément de A le plus à droite et ayant une profondeur plus grande que d. Déterminer r se fait de manière symétrique à l algorithme pour déterminer l. Une fois l et r déterminés, il faut déterminer le prédécesseur l de l et le successeur r de r en appliquant, respectivement, les algorithmes prédécesseur (cfr point 5.2.5) et successeur (cfr point 5.2.4) des arbres rouges-noirs. Étant donné que les nœuds qui ont une information prof supérieure à d forment un intervalle I dans l espace des clés de A, nous allons utiliser 70

72 cette propriété pour effectuer le cutting. En effet, l intervalle I correspond à [l, r] ou de manière équivalente à(l,r ). Il ne reste, dès lors, qu à isoler les éléments de cet intervalle dans un sous-arbre, de manière à pouvoir, ensuite, les séparer du reste de l arbre. L algorithme, qui suit, se base sur ce principe pour effectuer le cutting (voir figure 8.8) : 1. Effectuer un éclatement sur A en l. De par cette opération, l devient la racine de l arbre, ce qui a pour conséquence que les éléments du sous-arbre gauche de l ont des clés appartenant à l intervalle (,l ) et que les éléments du sous-arbre droit de l ont des clés appartenant à l intervalle (l, ). Notons par B et C, respectivement, le sous-arbre gauche de l et le sous-arbre droit de l. 2. Effectuer sur C un éclatement en r. Cette opération fait de r la racine du sous-arbre C. Dès lors, le sous-arbre gauche de r, noté D, contient des clés appartenant à l intervalle (l,r ) et le sous-arbre droit de r, noté E, contient des clés dans l intervalle (r, ). Ainsi, par les deux éclatements sur l et r, on est parvenu à isoler les nœuds, dont l information prof est supérieure à d, dans un sous-arbre de A. Ce sous-arbre étant D. 3. Activer l isroot bit de la racine D. Cette opération sépare, de manière effective, le sous-arbre D du reste de l arbre A et fait de D un arbre auxiliaire. La partie restante de A, obtenue après avoir enlevé D, sera dorénavant désignée par A. Une opération d éclatement ou de concaténation sur A ne portera que sur les nœuds de cet arbre auxiliaire ; elle n affectera pas les nœuds de l arbre auxiliaire D. À cette étape-ci, D contient les nœuds de A, dont l information prof est supérieure à d et A contient les nœuds de A, dont l information prof est inférieure à d. Cependant, le fait d avoir ainsi séparé de r son sous-arbre gauche D a pour conséquence, que le sous-arbre de r n est plus forcément un arbre rouge-noir, ce qui implique que l arbre A,également, n en est plus forcément un. Les deux opérations, qui suivent, ont pour but de transformer A en un arbre rouge-noir, et par la même occasion en un arbre auxiliaire. 4. Effectuer une concaténation sur r. Le nœud r n ayant pas de sousarbre gauche, l opération de concaténation forme un arbre rouge-noir à partir du nœud r et des nœuds dans le sous-arbre droit de r. Notons par C cet arbre rouge-noir, ainsi, créé. 5. Effectuer une concaténation sur l. Cette opération crée un arbre rougenoir à partir de tous les nœuds de A. Ainsi, par ces deux concaténations successives, l arbre A aété réordonné, de manière à devenir un arbre 71

73 répondant à la définition d arbre auxiliaire. Il est important de noter que deux concaténations sont nécessaires pour transformer A en un arbre auxiliaire. En effet, on pourrait penser à effectuer qu une seule concaténation (portant sur l ), de manière à transformer A en un arbre auxiliaire. Mais cette solution aurait été erronée, car la concaténation sur un nœud nécessite que le sous-arbre gauche et le sous-arbre droit de ce nœud soient des arbres rouges-noirs. Or, le sous-arbre droit de l, c est-à-dire le sous-arbre de r, n est plus forcément un arbre rouge-noir, après que son sous-arbre gauche D lui ait été retiré. D où la nécessité, d abord, de transformer le sous-arbre de r en arbre rouge-noir, avant de réaliser la même opération sur le sous-arbre de l. Deux cas particuliers sont à gérer : 1. le nœud l n existe pas (l n a pas de prédécesseur dans son arbre auxiliaire) : il ne faut alors réaliser des étapes ci-dessus que les étapes 2, 3 et le nœud r n existe pas (r n a pas de successeur dans son arbre auxiliaire) : il ne faut alors réaliser des étapes ci-dessus que les étapes 1, 3 et Joining L opération de joining porte sur deux arbres auxiliaires A et B, et consiste à les réunir pour n en former qu un seul. Une précondition à cette opération consiste, au niveau de l arbre parfait P, à ce que les deux chemins, qui correspondent aux arbres A et B, forment un sous-chemin continu C 1 d un chemin allant de la racine à une feuille de P s ils sont réunis. Par conséquent, le joining sur A et B consiste à réunir les chemins, qu ils stockent, pour former le chemin C 1, qui sera stocké dans un nouvel arbre auxiliaire C. Du fait, que le chemin A 1, stocké par A, est adjacent au chemin B 1, stocké par B, nous en déduisons deux propriétés : 1. un des deux arbres A et B est tel que l information prof de chacun de ses nœuds est plus grande que celle de tous les nœuds de l autre arbre. 2. l espace des clés de l arbre, ayant les informations prof plus grandes, forme un intervalle dans l espace des clés de l arbre ayant les informations prof plus petites. Une seconde précondition est nécessaire pour cette opération : l arbre, ayant les informations prof plus grandes, est attaché à un nœud du second arbre. L algorithme du joining se base sur tout ceci et est décrit ci-dessous. 72

74 Fig. 8.8 Réalisation d un cutting avec des éclatements et des concaténations. 73

75 D abord, il faut déterminer lequel des arbres A et B stocke les nœuds ayant les informations prof plus grandes. Pour cela, il suffit de comparer l information prof de la racine de A et de la racine de B, et de déterminer laquelle est la plus grande. Supposons, quitte à renommer les arbres, que B stocke les nœuds ayant les informations prof plus grandes. Ensuite, il faut rechercher les nœuds l et r (posons l <r ) de A entre lesquels l espace de clés de B est compris. La recherche de ces éléments se fait par l algorithme suivant : 1. Rechercher dans A la clé de la racine de B. Étant donné que la racine de B est le fils d un nœud p de A, cette opération permet d atteindre ce nœud p. 2. Si la racine de B est le fils gauche de p, alors ce nœud-ci correspond à r et comme l est le prédécesseur de r dans A, ce nœud l peut être déterminé en appliquant l algorithme prédécesseur (cfr point 5.2.5) sur r. Ainsi, nous sommes parvenus à identifier l et r dans ce premier cas. 3. Par contre, si la racine de B est le fils droit de p, alors ce nœud-ci correspond à l et comme r est le successeur de l dans A, ce nœud r peut être déterminé en appliquant l algorithme successeur (cfr point 5.2.4) sur l. Ainsi, nous sommes parvenus à identifier l et r dans ce second cas. Une fois l et r déterminés, il faut appliquer l algorithme, qui suit, de manière à réaliser le joining (voir figure 8.9) : 1. Effectuer sur A un éclatement en l. Ceci ramène l à la racine de l arbre. Notons par, respectivement, A et C le sous-arbre gauche et le sous-arbre droit de l. Les clés de A appartiennent à l intervalle (,l ) et les clés de C appartiennent à l intervalle (l, ) 2. Effectuer sur C un éclatement en r. Par cette opération, r devient la racine du sous-arbre C. Comme les nœuds l et r sont adjacents, alors r est le plus petit élément de C. Dès lors, étant ramené à la racine de C par le second éclatement, r contient dans son sous-arbre droit, noté E, tous les éléments de C. Comme r ne contient aucun élément de C dans son sous-arbre gauche, on est, alors, certain de n avoir dans le sous-arbre gauche de r que l arbre auxiliaire B. 3. Désactiver l isroot bit de la racine de B. Cette opération réunit de manière effective l arbre A et l arbre B. L arbre résultant de cette réunification sera désigné par Z. Le fait de rajouter, ainsi, l arbre B a pour conséquence que le sous-arbre de r n est plus forcément un arbre rouge-noir, ce qui implique que Z, également, n en est plus forcément 74

76 un. Les deux opérations, qui suivent, ont pour but de résoudre ce problème. 4. Effectuer une concaténation sur r. Cette opération de concaténation réarrange le sous-arbre de r, de manière à le transformer en un arbre rouge-noir. Notons par C l arbre résultant de cette concaténation. 5. Effectuer une concaténation sur l. Cette opération réarrange l arbre Z pour le transformer en un arbre rouge-noir. Ainsi, Z est un arbre auxiliaire, qui contient les éléments de A et B. Il s agit, donc, de l arbre résultant du joining de A et B. 8.4 Algorithme Tango Dans la première approche, l état T i de l arbre Tango T est construit à partir de l état P i de l arbre parfait P. Cependant, cette manière de procéder posait plusieurs inconvénients. L algorithme Tango se base sur les fondements de la première approche, mais il construit différemment l arbre T i, de sorte à résoudre les problèmes de la première approche. En fait, l état T i est construit à partir de l état T i 1 et du prochain accès x i de la séquence X. Il faut remarquer que l accès au nœud x i, au niveau de l arbre parfait P, change nécessairement les fils préférés, de manière à avoir un chemin préféré allant de la racine de P à x i et ne change pas d autres fils préférés. Par convention, nous décidons que pour un nœud accédé son fils gauche doit devenir son fils préféré. Par conséquent, les seuls nœuds, dont les fils préférés peuvent changer à cause de l accès à x i, sont ceux se trouvant sur le chemin menant de la racine de P à x i (ainsi que le fils droit de x i ). Au niveau de l arbre Tango T, il est possible, lors de la recherche de x i, de déterminer les nœuds, dont les fils préférés changent, car un changement de fils préféré (excepté pour le changement de fils préféré de x i ) correspond au passage entre deux arbres auxiliaires (disons de A à B). En effet, comme un arbre auxiliaire stocke un chemin préféré, alors le point de passage entre deux arbres auxiliaires correspond à choisir le fils non préféré d un des nœuds de A, car si on avait choisi son fils préféré, on serait resté dans le même arbre auxiliaire. En se basant sur cette constatation, il est inutile de construire T i à partir de P i. Il suffit de partir de T i 1, de rechercher le nœud x i dans cet arbre et de changer durant cette recherche le fils préféré des nœuds, pour lesquels l accès à x i provoque un changement de fils préféré. L algorithme suivant se base sur cette idée pour construire l état T i à partir de T i 1 et de x i : 1. Commencer la recherche de x i à la racine de T i 1. 75

77 Fig. 8.9 Réalisation d un joining avec des éclatements et des concaténations. 76

78 2. Se déplacer vers le sous-arbre gauche ou le sous-arbre droit du nœud courant x selon que x i soit, respectivement, plus petit ou plus grand que x. Une fois le déplacement effectué, disons sur le nœud y, il faut analyser l isroot bit de ce nœud : (a) Si l isroot bit est désactivé, cela signifie que x et y appartiennent au même arbre auxiliaire. Dès lors, l accès à x i ne modifie pas à ce niveau un fils préféré et aucun traitement additionnel n est alors nécessaire. (b) Si l isroot bit est activé, cela signifie qu on est passé d un arbre auxiliaire à un autre (disons de A à B). Dès lors, l accès à x i modifie le fils préféré d un nœud z de A. Il faut alors effectuer le traitement qui suit pour changer le fils préféré de z. Notons d abord que le nouveau fils préféré de z est le nœud de B ayant la plus petite information prof : i. Effectuer sur l arbre auxiliaire A contenant x un cutting à une profondeur d égale à l information profondeurmin de y, de manière à faire du fils préféré de z son fils non préféré ii. Effectuer un joining entre l arbre auxiliaire A et l arbre auxiliaire B, de manière à ce que z ait son nouveau fils préféré. L étape 2 doit être réitérée tant que le nœud x i n est pas atteint. 3. Lorsque le nœud x i est atteint, il faut encore faire de son fils gauche son fils préféré. Pour cela, il faut effectuer un cutting sur l arbre auxiliaire contenant x i à une profondeur d égale à la profondeur de x i plus 1. Ensuite, il faut rechercher le nœud p. Ce nœud est atteint en recherchant le prédécesseur de x i, mais en s arrêtant sur le premier nœud dont l isroot bit est activé. Ce nœud p est en fait la racine de l arbre auxiliaire contenant le fils gauche de x i dans P. En effet, le prédécesseur de x i appartient au sous-arbre du fils gauche de x i dans P, ce qui implique qu en recherchant dans T le prédécesseur de x i, nous devons obligatoirement passer par l arbre auxiliaire contenant le fils gauche de x i dans P. Et finalement, il faut effectuer un joining entre l arbre auxiliaire contenant x i et l arbre auxiliaire contenant p. 8.5 Analyse des performances Cette section est basée sur l article [DHIP04]. La contribution personnelle a été de détailler les démonstrations des lemmes et des théorèmes énoncés. 77

79 Soient un arbre Tango T construit sur les clés 1, 2,..., n et une séquence d accès X = x 1,x 2,..., x m. L analyse des performances de Tango se base sur la borne inférieure d entrelacement (cfr point 7.3.1) et nous avons besoin de définir la notion qui suit. La borne d entrelacement IB i (X) d un accès x i est la borne inférieure d entrelacement de la séquence x 1,x 2,..., x i,à laquelle on soustrait la borne inférieure d entrelacement de la séquence x 1,x 2,..., x i 1. Par conséquent, IB i (X) est le nombre d alternances left-right et right-left introduites en plus par l accès x i. Durant l analyse des performances de Tango, nous ne tiendrons pas compte des changements de fils préférés qui font du fils gauche de chaque nœud accédé son fils préféré. Pour une séquence de m accès, nous omettrons donc m changements de fils préférés. Cependant, ceci n est pas problématique, car nous pouvons nous rendre compte que ces m changements de fils préférés n influent pas sur les performances de Tango. Lemme 3. Supposons que durant un accès x i, il y ait k nœuds, dont le fils préféré change (de gauche à droite ou de droite à gauche) dans P. Ce nombre k est égal à la borne d entrelacement IB i (X) de l accès x i. Démonstration : Considérons que les éléments x 1,x 2,..., x i 1 aient été accédés et que le prochain élément à accéder soit x i. Pour démontrer ce lemme, il suffit de prouver l équivalence suivante : l accès x i change le fils préféré d un nœud x si et seulement si l accès x i induit une alternance left-right ou right-left supplémentaire dans la séquence étiquetée de x sur les clés x 1,x 2,..., x i par rapport à la séquence étiquetée de x sur les clés x 1,x 2,..., x i 1 (entre d autres termes IB i (X) augmente). Ceci se fait en deux étapes : 1. Lors d un accès x i, le fils préféré du nœud x passe de gauche à droite si et seulement si le dernier accès dans le sous-arbre de x était dans sa région gauche et que x i se situe dans la région droite de x. Ce dernier événement correspond exactement au cas où une alternance left-right supplémentaire est induite par l accès x i dans la séquence étiquetée de x sur les clés x 1,x 2,..., x i par rapport à la séquence étiquetée de x sur les clés x 1,x 2,..., x i Lors d un accès x i, le fils préféré du nœud x passe de droite à gauche si et seulement si le dernier accès dans le sous-arbre de x était dans sa région droite et que x i se situe dans la région gauche de x. Ce dernier événement correspond exactement au cas où une alternance right-left 78

80 supplémentaire est induite par l accès x i dans la séquence étiquetée de x sur les clés x 1,x 2,..., x i par rapport à la séquence étiquetée de x sur les clés x 1,x 2,..., x i 1. Ces deux cas permettent de démontrer l équivalence citée ci-dessus et par conséquent le lemme. Lemme 4. Soit k le nombre de nœuds, dont les fils préférés changent durant un accès x i. Le coût d accès à x i vaut O ((k + 1) (1 + log(log n))). Démonstration : Le coût d accès au nœud x i consiste, d une part, au coût pour rechercher x i dans l arbre, et d autre part, au coût pour réarranger la structure, de manière à la faire passer de l état T i 1 à l état T i. Nous analysons d abord le coût pour rechercher x i. Pour rappel, si durant la recherche de x i, on passe d un arbre auxiliaire à un autre(disons de A à B), cela signifie que l accès x i change le fils préféré d un des nœuds de l arbre auxiliaire A. Étant donné que la recherche de x i induit k changements de fils préférés, cela signifie que k + 1 arbres auxiliaires devront être visités pour la recherche de x i. Un arbre auxiliaire contient au plus log(n) éléments, car il stocke un sous-chemin d un chemin allant de la racine à une feuille dans P. Par conséquent, le coût d une recherche dans un arbre auxiliaire nécessite un coût au pire cas de O(log(log n)). Pour être plus précis, la complexité vaut O (max 1, log(log n)). Ceci permet de tenir compte du cas, où log(log n) est négatif, car la recherche se fait, alors, en temps constant. Dans la notation O(.), l expression O (max 1, log(log n)) est équivalente à O(1 + log(log n)). En effet, dans la notation O(.), en présence d une somme, on prend le terme maximal de cette somme. Finalement, comme la recherche de x i visite k +1 arbres auxiliaires, le coût pour la réaliser vaut O ((k + 1) (1 + log(log n))). Maintenant que le coût de la recherche est analysé, nous nous occupons du coût nécessaire pour transformer T i 1 en T i. Quand nous passons d un arbre auxiliaire à un autre, il faut effectuer un cutting et un joining. Comme ces opérations portent chacune sur au plus log(n) éléments, elles nécessitent chacune un coût de O(1 + log(log n)). Comme nous visitons k + 1 arbres auxiliaires, nous avons alors k passages entre des arbres auxiliaires, ce qui implique d effectuer k cuttings et k joinings pour lesquels nous payons un coût de O(k (1 + log(log n))). En conclusion, le coût de l accès à x i (= recherche de x i + réorganisation de l arbre) vaut O (max (k + 1) (1 + log(log n)),k (1 + log(log n))). En simplifiant ce résultat, nous obtenons finalement O ((k + 1) (1 + log(log n))). 79

81 Corollaire 2. Soient un arbre constitué des clés 1, 2,..., n et une séquence X = x 1,x 2,..., x m. Le coût pour servir X vaut O ((K + m) (1 + log(log n))), où K est le nombre de changements de fils préférés durant l exécution de la séquence X. Théorème 6. Soient un arbre constitué des clés 1, 2,..., n et une séquence X = x 1,x 2,..., x m. Le coût pour servir X avec l algorithme Tango vaut O ((OP T (X)+n) (1 + log(log n))). Démonstration : Pour démontrer ce résultat, nous allons utiliser le corollaire 2. En fait, nous allons compter le nombre de changements de fils préférés durant l exécution de la séquence X pour remplacer le terme K dans le corollaire 2 par ce nombre. Par le lemme 3, nous avons que IB(X) ( car m i=1 IB i(x) =IB(X)) est le nombre de fois qu un fils préféré change de gauche à droite ou de droite à gauche lors de l exécution de la séquence X. Cependant, il y a également au plus n initialisations de fils préférés (une initialisation d un fils préféré consiste à choisir pour un nœud son fils gauche ou son fils droit comme fils préféré, alors qu il n avait pas encore de fils préféré). Par conséquent, le nombre total de changements de fils préférés durant l exécution de la séquence X vaut IB(X) +n. En combinant ceci avec le corollaire 2, nous obtenons que le coût pour servir X vaut : O ((IB(X)+n + m) (1 + log(log n))) (8.1) Dans le chapitre 7, nous avons démontré le résultat, qui suit : OP T (X) 1 (IB(X)+m) (8.2) 2 En utilisant ce résultat, nous déduisons que le coût pour servir X vaut O((2 OP T (X) m+n+m) (1+log(log n))). En simplifiant ce résultat, nous obtenons finalement, que le coût pour servir la séquence X avec l algorithme Tango vaut : O ((OP T (X)+n) (1 + log(log n))) (8.3) Corollaire 3. Lorsque m = Ω(n), le temps d exécution de Tango pour servir la séquence X vaut O(OP T (X) (1 + log(log n))). 80

82 Démonstration : Si la séquence d accès X est constituée de plus de n clés, on a que OP T (X) = Ω(n). Par conséquent, en se basant sur le théorème précédent (théorème 6), on a que le coût pour servir X avec l algorithme Tango vaut : O (OP T (X) (1 + log(log n))) (8.4) Si nous avions tenu compte des changements de fils préférés, qui font du fils gauche de chaque nœud accédé son fils préféré, alors il aurait fallu rajouter le terme m (1 + log(log n)) au résultat de l équation 8.4. Cependant, ce terme peut être négligé, car OP T (X) m. Et donc le fait d omettre ces changements de fils préférés n est pas problématique. Théorème 7. Le coût au pire cas pour la recherche d un nœud x i O ((log n) (1 + log(log n))). vaut Démonstration : Comme l arbre P est un arbre parfait, sa hauteur est égale à log n. Par conséquent, le nombre maximal de nœuds, dont les fils préférés peuvent changer à cause de l accès x i vaut log n. Dès lors, par le lemme 4, le coût au pire cas de l accès x i vaut O ((log n) (1 + log(log n))). 8.6 Conclusion Dans ce chapitre, nous avons présenté une structure, qui atteint un taux de compétitivité de O(log(log n)). Ce taux est atteint au prix d un algorithme assez compliqué et lourd à implémenter. De plus, les nombreuses opérations nécessaires pour réaliser l algorithme pourraient porter préjudice à ses performances en pratique. Notons qu en utilisant la borne inférieure d entrelacement, nous ne pouvons pas améliorer le taux de O(log(log n)). En effet, chaque arbre auxiliaire contient au pire cas O(logn) éléments. Et donc quelle que soit la manière dont sont organisés les arbres auxiliaires, chaque arbre doit avoir une profondeur de Ω(log(log n)), ce qui se traduit par un coût d accès de Ω(log(log n)) dans chaque arbre auxiliaire. 81

83 Chapitre 9 Multi-splay tree Le multi-splay tree est une structure de données qui est basée sur Tango et qui atteint un taux de compétitivité de O(log(log n)). Elle a étéélaborée en 2004 par Sleator et Wang [SW04]. Le principal avantage des multi-splay trees par rapport à Tango est que l algorithme des multi-splay trees est moins compliqué et plus simple à implémenter, ce qui peut favoriser les performances en pratique de la structure, car l implémentation peut être plus facilement optimisée. Dans ce chapitre, nous allons d abord présenter l algorithme des multisplay trees et ensuite, nous allons procéder à l analyse amortie des performances de cette structure. 9.1 Structures de données Les sections présentant l algorithme des multi-splay trees sont basées sur les articles [SW04] et [DSW06]. La contribution personnelle a été de détailler le plus possible l algorithme et d essayer de le présenter de la manière la plus claire possible. Nous disposons comme pour Tango d un arbre de référence P (cfr point 8.1), auquel est lié un arbre T, qui est ici appelé un multi-splay tree. La différence est que le multi-splay tree est un arbre de splay trees et non pas un arbre d arbres rouges-noirs. Chaque nœud x dans T possède plusieurs informations : 1. sa profondeur dans P, dénotée par prof. Cette valeur est constante. 2. la profondeur minimale dans P de tous les nœuds appartenant au splay subtree de x. Le splay subtree de x est l ensemble des nœuds appartenant au même splay tree que x et qui ont x comme ancêtre (à noter que x y est inclus). Cette information est dénotée par mindepth. 82

84 3. l isroot bit qui indique si l arête reliant x à son père est solide ou discontinue. Deux nœuds reliés par une arête solide appartiennent au même splay tree et deux nœuds reliés par une arête discontinue appartiennent à des splay trees différents 9.2 Algorithmes Nous allons d abord expliquer l algorithme du point de vue de l arbre de référence P et, ensuite, nous allons expliquer comment le réaliser au niveau de T Algorithme de l arbre de référence L algorithme d accès à un nœud x i est le suivant : 1. localiser le nœud x i, en commençant la recherche à la racine de P. 2. suivre le chemin allant de x i à la racine, en changeant les fils préférés adéquats, de manière à ce que x i fasse partie du même chemin préféré que celui de la racine de P. Cet algorithme est identique à celui de Tango (cfr point 8.2), hormis que les changements de fils préférés se font en remontant de x i à la racine. Ceci facilite, en fait, l algorithme dans T Algorithme multi-splay tree Pour réaliser l algorithme ci-dessus sans utiliser l arbre de référence, nous allons nous baser sur l accès x i et sur l arbre T i 1 (l arbre T avant l accès x i ) pour le transformer de manière à tenir compte des modifications causées par l accès x i. L idée de l algorithme est donc la même que celle de Tango. Cependant, les changements de fils préférés devront se faire différemment puisque un multi-splay tree est constitué de splay trees et non pas d arbres rouges-noirs. Les changements de fils préférés peuvent être réalisés dans un multi-splay tree de manière plus souple par rapport à Tango, car un splay tree n impose pas de conditions sur sa structure, contrairement aux arbres rouges-noirs (cfr point 5.2.1). L algorithme d accès au nœud x i est le suivant : 1. localiser le nœud x i, en commençant la recherche à la racine de T. 83

85 2. suivre le chemin menant de x i à la racine de T. Pour chaque nœud x, rencontré durant la remontée, il faut analyser son isroot bit. Si ce bit est activé, cela signifie que le passage de x à son père p correspond au passage d un splay tree à un autre. Il faut alors effectuer un switch (un changement de fils préféré). Ce switch doit porter sur le nœud y du splay tree, auquel p appartient, et dont l information prof est égale à l information mindepth de x moins 1. Si nous nous basons sur l arbre parfait P, nous constatons que dans P ce nœud y est l ancêtre des nœuds appartenant au splay tree de x. De ce fait, le splay tree, auquel x appartient, doit être un descendant de y dans T (voir figure 9.1). Et donc, le nœud y doit se situer sur le chemin menant de p à la racine du splay tree de p. Le nœud y peut donc être déterminé en suivant ce chemin. Une fois y trouvé, il faut effectuer un switch sur ce nœud, c est-à-dire changer son fils préféré. Ce changement de fils préféré de y, au niveau de l arbre T, consiste à réunir le splay tree, auquel appartient y et le splay tree auquel appartient x, pour n en faire plus qu un seul splay tree. 3. une fois les switches effectués et la racine atteinte, il faut splayer le nœud x i pour le ramener à la racine de T. Pour cela, on peut utiliser l algorithme usuel de splaying (cfr point 6.2.1), car après tous les switches, x i appartient au même splay tree que celui de la racine de T. Nous allons, maintenant, expliquer comment réaliser l opération de switch. En fait, il y a deux switches à considérer : le switch gauche-droite et le switch droite-gauche, selon qu il faille, respectivement, changer le fils préféré de gauche à droite ou de droite à gauche. Nous allons détailler l algorithme du switch gauche-droite. L autre switch peut être déduit de manière analogue. Considérons un switch sur y. Nous définissons alors quatre ensembles : 1. L, qui est l ensemble des nœuds dans le sous-arbre gauche de y dans P appartenant au même chemin préféré que celui du fils gauche de y. 2. R, qui est l ensemble des nœuds dans le sous-arbre droit de y dans P appartenant au même chemin préféré que celui du fils droit de y. 3. U, qui est l ensemble des nœuds au-dessus de y dans P appartenant au même chemin préféré que celui de y. 4. S = L R y U. Si nous considérons les éléments de S par ordre croissant, nous avons que les clés de L forment un sous-intervalle dans l intervalle des clés de S. Et idem pour R. De plus, il n y a que le nœud y qui se situe entre l intervalle de L et l intervalle de R. 84

86 Fig. 9.1 Le splay tree auquel x appartient doit être un descendant de y. Dans ce cas, le nœud x est plus petit que y. 85

87 Le splay tree A dans T, qui contient y est constitué des nœuds L U y. Après le switch, il doit être constitué des nœuds R U y. Il faut donc retirer L de A et y rajouter R. Cela peut se faire par l algorithme suivant (voir figure 9.2) : 1. splayer le nœud y pour qu il devienne la racine de A. 2. déterminer z. Le nœud z est le plus grand nœud, qui a une information prof plus petite que celle de y et qui est plus petit que y. 3. splayer le nœud z, jusqu à ce qu il devienne le fils gauche de y. Dès lors, le sous-arbre droit de z est constitué de nœuds ayant une valeur dans l intervalle (z, y) et ayant une information prof plus grande que celle de y. En effet, comme z est le plus grand nœud ayant une information prof plus petite que celle de y, nous en déduisons que les nœuds dans le sous-arbre droit de z ont une information prof plus grande que celle de y. Comme l ensemble L est constitué de nœuds ayant une valeur plus petite que celle de y et ayant une information prof plus grande que celle de y, nous en déduisons que le sous-arbre droit de z correspond à L. 4. activer l isroot bit de la racine du sous-arbre droit de z pour le séparer de A. Cette opération retire de manière effective L de A. De cette manière, le fils gauche de y dans P devient son fils non préféré. 5. Déterminer x. Le nœud x est le plus petit nœud, qui a une information prof plus petite que celle de y et qui est plus grand que y. 6. splayer le nœud x, jusqu à ce qu il devienne le fils droit de y. Dès lors, le sous-arbre gauche de x est constitué de nœuds ayant une valeur dans l intervalle (y, x) et ayant une information prof plus grande que celle de y. En effet, comme x est le plus petit nœud ayant une information prof plus petite que celle de y, nous en déduisons que les nœuds dans le sous-arbre gauche de x ont une information prof plus grande que celle de y. Comme l ensemble R est constitué de nœuds ayant une valeur plus grande que celle de y et ayant une profondeur plus grande que celle de y, nous en déduisons que le sous-arbre gauche de x correspond à R. 7. désactiver l isroot bit de la racine du sous-arbre gauche de x, de manière à l incorporer dans A. De cette manière, le fils droit de y dans P devient son fils préféré. La souplesse des multi-splay trees par rapport à Tango est illustrée dans les étapes 3 et 7 de l algorithme ci-dessus. Nous pouvons activer ou désactiver un isroot bit, c est-à-dire retirer un sous-arbre d un splay tree ou attacher un 86

88 Fig. 9.2 Les étapes d un switch gauche-droite sur le nœud y. 87

89 sous-arbre à un splay tree sans devoir réorganiser le splay tree, car après de telles opérations l arbre reste toujours un splay tree. Pour Tango, après de telles opérations il faut réorganiser les arbres rouges-noirs (cfr points et 8.3.5) pour qu ils répondent à nouveau à la définition d arbres rouges-noirs. Deux cas particuliers doivent être considérés : 1. le nœud z n existe pas. Dans ce cas, il n existe pas de nœuds, qui soient plus petits que y et qui aient une information prof plus petite que celle de y. Le sous-arbre gauche de y est alors constitué exclusivement de nœuds ayant une information prof plus grande que celle de y. Il correspond donc à L. 2. le nœud x n existe pas. Dans ce cas, il n existe pas de nœuds, qui soient plus grands que y et qui aient une information prof plus petite que celle de y. Le sous-arbre droit de y est alors constitué exclusivement de nœuds ayant une information prof plus grande que celle de y. Il correspond donc à R. Il ne reste plus qu à détailler les étapes 2 et 5 de l algorithme précédent, c est-à-dire comment déterminer z et x. Nous allons présenter l algorithme pour déterminer z ; celui pour x peut être déduit par symétrie. Pour déterminer z, il faut trouver le plus grand nœud, qui a une information prof plus petite que celle de y et qui est plus petit que y, sachant que y a déjà été ramené à la racine de A (étape 1 de l algorithme précédent). L algorithme est alors le suivant : 1. commencer le traitement sur le fils gauche de y, pour ne considérer que des nœuds plus petits que y. 2. analyser l information prof du nœud courant x : (a) si l information prof de x est plus petite que l information prof de y, alors il faut analyser l information mindepth du fils droit de x : i. si l information mindepth du fils droit de x est plus petite que l information prof de y, alors il existe dans le sous-arbre droit de x un nœud qui est plus grand que x et qui a une information prof plus petite que celle de y. Dès lors, x n est pas z et il faut, par conséquent, se déplacer sur le fils droit de x et recommencer l étape 2. ii. si l information mindepth du fils droit de x est plus grande que l information prof de y, alors il n existe aucun nœud dans le sous-arbre droit de x, qui ait une information prof plus petite que celle de y. Par conséquent, x est le nœud z. 88

90 (b) si l information prof de x est plus grande que l information prof de y, alors il faut analyser l information mindepth des fils de x : i. si l information mindepth du fils droit de x est plus petite que l information prof de y, alors il faut se déplacer sur le fils droit de x et recommencer l étape 2. ii. si l information mindepth du fils gauche de x est plus petite que l information prof de y, alors il faut se déplacer sur le fils gauche de x et recommencer l étape 2. iii. si l information mindepth du fils gauche et du fils droit de x est plus petite que l information prof de y, alors il faut se déplacer sur le fils droit de x plutôt que le fils gauche, car le sous-arbre du fils droit de x a des clés plus grandes que celles du sous-arbre du fils gauche de x. Nous sommes donc certains que z se situera dans le sous-arbre droit de x et non pas dans le sous-arbre gauche de x. Ensuite, il faut recommencer l étape 2. Cet algorithme n est correct que si le nœud z existe dans A. Pour traiter le cas où z n existe pas, il suffit d examiner l information mindepth du fils gauche de y. Si cette information est plus grande que l information prof de y, alors il n existe aucun nœud plus petit que y et ayant une information prof plus petite que celle de y. Dans ce cas, le nœud z n existe donc pas. Par contre, si l information mindepth du fils gauche de y est plus petite que l information prof de y, alors il existe un nœud plus petit que y et ayant une information prof plus petite que celle de y. Dans ce cas, le nœud z existe et l algorithme ci-dessus peut être appliqué. Le dernier point à éclaircir est la manière de déterminer le type de switch (gauche-droite ou droite-gauche) qu il faut appliquer à un nœud pour lequel cette opération doit être réalisée. Supposons que nous passons du splay tree A au splay tree B et qu il faut effectuer un switch sur le nœud y de B. Si la racine de A a une valeur qui est plus grande que celle de y, alors les éléments de A appartiennent au sous-arbre droit de y dans P (car ils sont plus grands que y). Le switch à effectuer est alors un switch gauche-droite. Par contre, si la valeur de la racine de A est plus petite que celle de y, alors il faut effectuer un switch droite-gauche. 9.3 Analyse des performances Dans cette section, nous allons démontrer que les multi-splay trees atteignent un taux de compétitivité de O(log(log n)), ainsi qu une complexité 89

91 amortie de O(logn) pour l opération de recherche. Nous allons également montrer que la complexité au pire cas d une recherche vaut O((log n) 2 ). Cette section est basée sur les articles [SW04] et [DSW06]. La contribution personnelle a été de détailler les démonstrations et de justifier dans les démonstrations des points qui ne l avaient pas été Fonction potentiel La fonction potentiel utilisée pour analyser les multi-splay trees est la suivante. Soit T le multi-splay tree. Nous assignons à chaque nœud x de T un poids arbitraire positif, noté w(x). Pour un nœud x, nous définissons sa taille s(x) comme la somme des poids de tous les nœuds appartenant au splay subtree de x (tous les nœuds appartenant au même splay tree que celui de x et ayant x comme ancêtre). Le rang r(x) d un nœud x vaut log(s(x)). Finalement, nous définissons le potentiel d un arbre T comme la somme des rangs de tous ses nœuds. En résume : w(x) R +, x T s(x) = a T x w(a), où T x est le splay subtree de x r(x) = log(s(x)) P (T )= a T r(a) Il est possible de donner une autre définition équivalente pour le potentiel d un multi-splay tree. Pour cela, il faut considérer la fonction potentiel définie par Sleator et Tarjan [ST85] pour un simple splay tree (cfr point 6.2.5). Comme un multi-splay tree est une collection de splay trees, il suffit de calculer le potentiel de chacun de ces splay trees et de sommer ces potentiels pour obtenir le potentiel de T. En comparant ces deux définitions de potentiel pour T, nous pouvons constater qu elles sont équivalentes Access Lemma Généralisé Soit un nœud x, la complexité pour splayer ce nœud jusqu à un ancêtre a appartenant au même splay tree est d au plus 3(r(a) r(x)) + 1 = O(log(s(a)/s(x))). 90

92 La démonstration de l Access Lemma Généralisé découle immédiatement de la démonstration de l Access Lemma pour les splay trees (cfr point 6.2.5), parce que cette démonstration-ci ne nécessite pas que le nœud à splayer soit remonté à la racine. La différence entre l Access Lemma et l Access Lemma Généralisé est que, pour ce dernier, le splaying peut s arrêter à un quelconque ancêtre a de x Multi-Splay Access Lemma Soit P un arbre de référence de racine t constitué de n nœuds et f 2 un multiplicateur. Considérons une assignation de poids, qui attribue à chaque nœud x de P un poids positif w(x) et qui satisfait les deux conditions suivantes : 1) w(x) max w(v) v d(x,p ) (9.1) 2) f w(x) max t p(x,p ) w(v) (9.2) où p(x, P ) est l ensemble des chemins dans P allant de x à un descendant de x sans enfant et d(x, P ) est l ensemble des descendants de x dans P. La valeur du multiplicateur f n est pas constante. Elle peut dépendre de n (le nombre d éléments dans l arbre). Le fait que la valeur de f puisse être choisie arbitrairement (mais en vérifiant les conditions ci-dessus) est intéressant, car cela nous laisse une marge de manœuvre plus grande pour déterminer des propriétés à partir de l équation 9.3 et d une assignation de poids aux nœuds. Alors le temps d exécution amorti d une séquence X = x 1,x 2,..., x m vaut : (( m ( ) ) w(t) O log + (log f) (IB(X)+m)) (9.3) w(x i ) i=1 Démonstration : La démonstration est composée de trois étapes : 1. calculer le coût d un switch 2. calculer le coût d accès à un élément v t 3. calculer le temps d exécution d une séquence Supposons que pour l accès x j, il y ait k switches qui soient réalisés sur les nœuds Y = y 1,y 2,..., y k. L ordre dans lequel les switches sont effectués est y k,..., y 2,y 1. Notons par t i la racine du splay tree contenant y i avant l accès x j et par t k+1 la racine du splay tree contenant x j. 91

93 y i z x cz cx Fig. 9.3 Relation entre x, y i, z, cx et cz dans l arbre T. Il s agit de la représentation de T après 3 splayings, mais avant l activation de l isroot bit de cz et la désactivation de l isroot bit de cx. Pour calculer le coût d un switch y i, il faut d abord calculer la variation de potentiel dû à ce switch. Le switch y i est composé de deux changements d isroot bit et d au plus trois splayings (sur y i, x et z, où x et z sont les nœuds comme définis pour l algorithme des multi-splay trees au point 9.2.2). Les changements d isroot bit porteront sur le fils droit de z, noté cz, et le fils gauche de x, noté cx. Ces changements d isroot bit n affecteront que le potentiel des nœuds y i, x et z. Si nous notons par r(v) et s(v) le rang et la taille d un nœud v avant les changements d isroot bit et par r (v) et s (v) le rang et la taille du nœud v après les changements d isroot bit, nous constatons les propriétés suivantes (voir figure 9.3) pour les nœuds y i, x et z : 1. s (z) =s(z) s(cz), car l activation de l isroot bit de cz sépare son sous-arbre du reste du splay tree, ce qui diminue la taille de z de s(cz). Cette égalité sera désignée par (A). 2. s (x) =s(x) +s(cx), car la désactivation de l isroot bit de cx rajoute le sous-arbre de cx au splay tree de y i, ce qui augmente la taille de x de s(cx). Cette égalité sera désignée par (B). 3. s (y i )=s(y i )+s(cx) s(cz), car la taille de z diminue de s(cz) et la taille de x augmente de s(cx). Cette égalité sera désignée par (C). 92

94 Pour calculer la variation de potentiel due au switch y i, il est nécessaire de déduire encore deux résultats : 1. s(x) w(y i ) 2. f s(cx)/w(y i ) Le premier résultat est déduit de la manière suivante. Au niveau de P, nous avons que x et y i appartiennent au même chemin préféré, car ils font partie du même splay tree. De plus, nous avons que x a une profondeur plus petite que celle de y i ; ceci est dû à la définition de x dans l algorithme des multi-splay trees (cfr point 9.2.2). De ceci, nous concluons que x est l ancêtre de y i dans P. Comme x est l ancêtre de y i, nous obtenons de la condition 9.1, que w(x) w(y i ). Et comme s(x) w(x), nous obtenons finalement que s(x) w(y i ). Le deuxième résultat est déduit de la manière suivante. Par l algorithme des multi-splay trees, nous avons que les nœuds (en particulier cx ) dans le sous-arbre gauche de x au niveau de T appartiennent au sous-arbre du fils non préféré de y i dans P. Nous avons donc que y i est l ancêtre de cx dans P. Considérons l ensemble C des chemins dans P, qui commencent en y i, qui passent par cx et qui se terminent en une feuille. Nous pouvons utiliser la condition 9.2 pour déduire que, pour un chemin quelconque appartenant à C, la somme des poids des nœuds de ce chemin est plus petite que f w(y i ). Or, dans T le sous-arbre gauche de x, c est-à-dire le splay subtree de cx, contient des nœuds plus grands que y i et ayant des informations prof plus grandes que celle de y i. Ces nœuds forment donc dans P un sous-chemin d un des chemins de l ensemble C. Par conséquent, la somme des poids des nœuds dans le splay subtree de cx, qui vaut s(cx), est plus petite que f w(y i ). Nous avons donc déduit que s(cx) f w(y i ), d où f s(cx)/w(y i ). En se basant sur ces constatations, nous pouvons calculer la variation de potentiel dû au switch y i : 93

95 P = (r (x) r(x)) + (r (y i ) r(y i )) + (r (z) r(z)), car un switch modifie le potentiel des nœuds y i, x et z < (r (x) r(x)) + (r (y i ) r(y i )), car r (z) r(z) < 0 ( ) ( ) s (x) s (y i ) = log + log, car log(a) log(b) = log(a/b) s(x) s(y i ) ( ) ( ) s(x)+s(cx) s(yi )+s(cx) s(cz) = log + log, s(x) s(y i ) par les égalités (A) et (B) ( ) ( ) s(x)+s(cx) s(yi )+s(cx) < log + log s(x) s(y i ) ( = log 1+ s(cx) ) ( + log 1+ s(cx) ) s(x) s(y i ) ( log 1+ s(cx) ) ( + log 1+ s(cx) ), car s(x) w(y i ) w(y i ) s(y i ) ( log 1+ s(cx) ) ( + log 1+ s(cx) ), w(y i ) w(y i ) car s(y i ) w(y i ) par définition de s(y i ) ( = 2 log 1+ s(cx) ) w(y i ) 2 log (1 + f), car f s(cx) w(y i ) = O(log f) Nous avons donc déduit que P < O(log f). Le calcul de la complexité amortie pour le switch de y i se base sur l équation suivante : C Aswitch = C Eswitch + P (cfr point 2.4.3), c est-à-dire que la complexité amortie du switch est égale à la complexité effective du switch plus la variation de potentiel due à l opération. La complexité effective du switch est égale au coût pour splayer y i, x et z. Comme les changements d isroot bit se font en temps constant, leur coût peut être négligé. Avant de calculer la complexité amortie du switch de y i, il est utile de prouver les trois résultats suivants : 1. w(x) w(y i ) (ce résultat sera désigné par (D)) 2. w(z) w(y i ) (ce résultat sera désigné par (E)) 3. w(y i ) s(t i+1 )/f (ce résultat sera désigné par (F )) 94

96 Le premier résultat a déjà été prouvé pour le calcul de P. Le deuxième résultat peut être prouvé de manière similaire. Le troisième résultat est prouvé de la manière suivante. Pour rappel, lors d un accès x j, il y a k switches qui sont effectués sur les nœuds y 1,y 2,..., y k dans l ordre y k,..., y 2,y 1. Et t j représente la racine du splay tree contenant y j. Comme nous effectuons un switch sur y i+1 suivi d un switch sur y i, cela signifie que nous sommes passés du splay tree contenant y i+1 au splay tree contenant y i par une arête discontinue. Au niveau de P, l ensemble des nœuds dans le splay tree de y i+1 forme un chemin t allant du fils non préféré de y i à une feuille. Or, t est un sous-chemin de d(y i,p). En se basant sur cela, nous pouvons utiliser la condition 9.2 pour déduire que f w(y i ) v t w(v). Comme t i+1 est la racine du splay tree de y i+1, nous avons que v t w(v) = s(t i+1 ). Finalement, nous obtenons que f w(y i ) s(t i+1 ), d où w(y i ) s(t i+1 )/f. En se basant sur ce résultat, nous pouvons calculer la complexité amortie d un switch : Cout(switch(y i )) = Cout(splay(y i )) + Cout(splay(x)) + Cout(splay(z)) + P ( ( )) ( ( )) ( ( )) s(ti ) s(ti ) s(ti ) < O log + O log + O log s(y i ) s(x) s(z) + O(log f), où s(t i ) est la taille du splay tree de y ( ( )) ( ( )) ( ( i )) s(ti ) s(ti ) s(ti ) < O log + O log + O log w(y i ) w(x) w(z) + O(log f) ( ( )) ( ( )) ( ( )) s(ti ) s(ti ) s(ti ) O log + O log + O log w(y i ) w(y i ) w(y i ) + O(log f), par les résultats (D) et (E) ( ( )) s(ti ) = O log + O(log f) w(y i ) ( ( )) s(ti ) O log + O(log f), par le résultat (F ) s(t i+1 )/f ( ( )) s(ti ) = O log s(t i+1 ) f + O(log f) ( ( )) s(ti ) = O log + O(log f)+o(log f) s(t i+1 ) ( ( )) s(ti ) = O log + O(log f) s(t i+1 ) 95

97 Pour calculer le coût d accès à un nœud x j, il est nécessaire de prouver les deux résultats suivants : 1. s(t k+1 ) w(x j )(t k+1 est la racine du splay tree contenant x j ) (ce résultat sera désigné par (G)) 2. f w(t) s(t 1 )(t est la racine de P ) (ce résultat sera désigné par (H)) La preuve du premier résultat découle immédiatement du fait que t k+1 est la racine du splay tree contenant x j. Le deuxième résultat est prouvé de la manière suivante. Le nœud t 1, qui est la racine du splay tree contenant y 1, est également la racine de T. Donc, le splay tree de t 1 correspond au chemin C dans P allant de t à une feuille en suivant les fils préférés. Par la condition 9.2, nous avons que f w(t) v C w(v) (car C p(t, P )). Or, v C w(v) = s(t 1), ce qui implique que f w(t) s(t 1 ). L accès au nœud x j consiste à effectuer k switches et à splayer x j. Le coût d accès à x j est alors calculé comme suit : 96

98 Cout(Acces(x j )) = = k i=1 k i=1 = O ( log Cout(switch(y i )) + Cout(splay(x j )) ( ( )) s(ti ) k O log + s(t i+1 ) i=1 ( )) s(t1 ) k + O(log f)+o s(t k+1 ) i=1 ( O(log f)+o log ( log ( s(t1 ) s(x j ) la simplification du premier terme découle du fait que ( )) s(t1 ) s(x j ) )), log(a) + log(b) = log(a B) ( ( )) ( ( )) s(t1 ) s(t1 ) = O log + O(k log f)+o log s(t k+1 ) s(x j ) ( ( )) ( ( )) s(t1 ) s(t1 ) O log + O(k log f)+o log, w(x j ) w(x j ) par le résultat (G) ( ( )) ( ( )) f w(t) f w(t) O log + O(k log f)+o log, w(x j ) s(x j ) par le résultat (H) ( ( )) f w(t) = O log + O(k log f), w(x j ) ( ( )) w(t) = O(log f)+o log + O(k log f), w(x j ) ( ( )) w(t) = O log + O((k + 1) (log f)), w(x j ) Le nombre k de switches effectués lors de l accès x j correspond au nombre de nœuds dans P, dont les fils préférés changent à cause de cet accès. Durant l analyse des performances de Tango, il a été démontré que ce nombre k est égal à la borne d entrelacement IB j (X) de l accès x j (cfr point 8.5). Le coût nécessaire à un multi-splay tree pour exécuter une séquence X = x 1,x 2,..., x m vaut : 97

99 Cout(executer(X)) = = = = = Propriétés m Cout(acces(x i )) i=1 = O m ( ( )) w(t) m O log + O((IB i (X) + 1) (log f)) w(x i=1 i ) i=1 m ( ( )) ( m ) w(t) O log + O (IB i (X) + 1) (log f) w(x i=1 i ) i=1 m ( ( )) ( ) w(t) m O log + O (log f) (IB i (X) + 1) w(x i=1 i ) i=1 m ( ( )) w(t) O log + O ((log f) (IB(X)+m)), w(x i=1 i ) m car IB i (X) =IB(X) i=1 (( m i=1 ( ) ) w(t) log + (log f) (IB(X)+m)) w(x i ) En se basant sur le multi-splay tree access lemma, il est possible de définir trois propriétés sur les multi-splay trees. Théorème 8. Le multi-splay tree est O(log(log n))-compétitif. Démonstration : Soit P un arbre de référence à n nœuds. La profondeur de P vaut (log n) + 1. On pose w(v) = 1 pour tout nœud v de P et on choisit f =2 log n. La condition 9.1 est vérifiée, car le poids maximal d un ensemble quelconque de nœuds vaut 1. La condition 9.2 est vérifiée, car la longueur maximale d un chemin vaut (log n) + 1, ce qui est bien inférieur à f. Avec l assignation de poids choisie, le multi-splay tree access lemma vaut : (( m ( ) ) 1 O log + (log(2 log n)) (IB(X)+m)) (9.4) 1 i=1 98

100 Comme O(log(2 log n) =O((log 2) + (log(log n))) = O(log(log n)), nous obtenons finalement : O((log(log n)) OP T (X)) (9.5) Théorème 9. Un multi-splay tree de n nœuds a une complexité amortie de O(log n) pour un accès. Démonstration : Soient P un arbre de référence à n nœuds et une séquence d accès X = x 1,x 2,..., x m. La profondeur de P vaut (log n) + 1. Soit h(v), la hauteur d un nœud v (la hauteur d une feuille vaut 0 ; cfr point 2.1.3). On pose w(v) =2 h(v) pour tout nœud v de P et on choisit f = 2. Notons que le poids de la racine t de P vaut : w(t) = 2 h(t) =2 (log n)+1 =2 log n 2=n 2=O(n) (9.6) La condition 9.1 est vérifiée, car un descendant a une hauteur plus petite que celle de son ancêtre. La condition 9.2 est vérifiée, car 2 i i 1 j=0 2j. Avec l assignation de poids choisie, le multi-splay tree access lemma vaut : (( m ( ) ) n Cout(executer(X)) O log + (log 2) (IB(X)+m)) w(x i=1 i ) (( m ) ) O log (n) +(IB(X)+m), i=1 car 1 i m : w(x i ) 1 = O(m log n + OP T (X)) = O(m log n), car OP T (X) m log n Théorème 10. Pour une séquence d accès X, le coût nécessaire à un multisplay tree pour traiter X vaut : O(min (log(log n) OP T (X), m log n)) (9.7) 99

101 Démonstration : théorèmes 8 et 9). Ce résultat découle des deux théorèmes précédents (les Nous avons encore deux propriétés concernant les multi-splay trees. Théorème 11. Un multi-splay tree de n nœuds a une complexité au pire cas de O((log n) 2 ) pour un accès x i. Démonstration : Comme la hauteur de l arbre de référence vaut log n, nous avons que le nombre de switches pour un accès x i vaut au pire cas log n. De plus, comme chaque splay tree contient au plus log n éléments, nous avons que la complexité au pire cas pour une opération sur un splay tree vaut log n (car la complexité au pire cas d une opération sur un splay tree est linéaire sur la taille de l arbre). Ainsi, le coût pour effectuer un switch sur un splay tree vaut O(log n) au pire cas, car on effectue 3 splayings pour réaliser cette opération. Par conséquent, le coût pour accéder au nœud x i vaut O((log n) (log n)) = O((log n) 2 ). Théorème 12. Soient un arbre à n nœuds et une séquence X consistant à accéder à ces nœuds dans l ordre symétrique. Le coût pour traiter X vaut : O(n) (9.8) Ce théorème ne sera pas démontré ici, mais une preuve est disponible dans l article [DSW06]. 9.4 Conclusion Nous venons de présenter une structure qui atteint un taux de compétitivité de O(log(logn)), mais qui est plus simple que l algorithme Tango. Nous avons également montré qu un accès se fait avec un coût au pire cas de O((log n) 2 ) et avec un cout amorti de O(log n). Nous avons également constaté que cette structure présente des similarités avec Tango. En fait, le principe fondamental est le même, à savoir qu il faut effectuer des switches après chaque accès pour changer le fils préféré de certains nœuds. Seul diffère la manière d effectuer les switches, car un multi-splay tree est constitué de splay trees et Tango est constitué d arbres rouges-noirs. Nous avons également constaté que cette différence fournit une plus grande souplesse aux multi-splay trees. 100

102 Grâce à cette souplesse, il est possible d étendre cette structure pour qu elle puisse supporter les opérations d insertion et de suppression tout en gardant au taux de compétitivité de O(log(log n)). Comme les multi-splay trees présentent des similitudes avec les splay trees, nous pouvons nous demander si les multi-splay trees possèdent également les propriétés d optimalité statique, de static finger, de working set et de dynamic finger [DSW06]. De par cette similitude, un autre problème, que nous pourrions nous poser, serait de savoir si les splay trees sont O(log(logn)) compétitif s [DSW06]. Nous avons montré que les multi-splay trees et Tango ont un taux de compétitivité de O(log(log n)), mais il se peut que ces deux structures atteignent l optimalité dynamique [DSW06]. Pour prouver cela, il faudrait un borne inférieure sur OP T (X) qui soit meilleure que la borne inférieure d entrelacement, mais le grand problème est que de telles bornes sont rares. Ce manque de bornes inférieures est l un des principaux obstacles pour avoir une structure optimale dynamiquement. 101

103 Chapitre 10 Optimalité de recherche dynamique La rédaction de ce chapitre est basée sur l article de Blum, Chawla et Kalai [BCK03]. Dans cette section, nous allons montrer qu il existe une structure, qui atteint l optimalité dynamique, si nous ne tenons pas compte du coût des rotations qu elle effectue après chaque accès Définition Dans le modèle dynamique (cfr point 2.2.1) des ABR que nous considérons, le coût d accès à un élément x i est égal au coût de localisation de x i plus le coût des rotations effectuées après avoir atteint x i. Une structure a la propriété d optimalité de recherche dynamique si, pour une quelconque séquence X, le coût nécessaire à la localisation des éléments de X est égal à O(OP T (X)), où OP T (X) est le coût d accès aux éléments de X pour l algorithme offline optimal. En d autres termes, une structure a l optimalité de recherche dynamique si son coût pour traiter une séquence (sans compter les rotations) est égal au coût de l algorithme offline optimal Intérêt Un argument en défaveur de l existence d un algorithme online optimal serait le suivant. Pour qu un algorithme soit optimal, il faut qu il puisse garder près de la racine les nœuds qui doivent encore être accédés. Mais le problème d un algorithme online est qu il ne peut pas deviner les accès à venir et que par conséquent il a trop de nœuds à maintenir près de la racine. 102

104 L intérêt de la propriété d optimalité de recherche dynamique est de rejeter cet argument, car elle montre qu il est possible pour une structure online de garder les nœuds à accéder suffisamment proches de la racine pour avoir un coût optimal Structure Ici, le but est de prouver qu il existe une structure ABR online qui atteint l optimalité de recherche dynamique. L élaboration de la structure se fait à l aide de distributions de probabilités sur les séquences d accès. Nous verrons qu il est possible de transformer une distribution de probabilités en un arbre binaire de recherche et un arbre binaire de recherche en une distribution de probabilités. Ces transformations sont telles que les nœuds proches de la racine sont ceux dont la probabilité d accès est la plus grande. Avant de présenter la structure, il est nécessaire de présenter quelques résultats. Toutes les démonstrations présentées ci-dessous sont basées sur l article [BCK03]. La contribution personnelle a consisté à détailler ces démonstrations et à justifier dans ces démonstrations des points qui ne l avaient pas été. Théorème 13. Le nombre de séquences d accès pouvant être exécutées avec un coût optimal k est de tout au plus 2 12k, pour tout k 0. Ce théorème n est pas démontré ici, mais une preuve peut être consultée dans [BCK03]. Théorème 14. Il existe une distribution de probabilités sur les séquences d accès, qui assigne une probabilité d au plus 2 13k à une séquence d accès dont le coût optimal est k. Démonstration : On choisit le nombre k dans l intervalle [1, ] selon la distribution 1/2 k. Ensuite, on choisit une séquence d accès X parmi toutes les séquences dont le coût optimal est k. Comme il existe au plus 2 12k séquences de coût optimal k, la probabilité de choisir X parmi toutes les séquences de coût k est de 2 12k. Finalement, la probabilité de choisir X vaut au plus : k 2 = 1 (10.1) 12k 2 13k Théorème 15. Un arbre binaire de recherche T peut être transformé en une distribution de probabilités p telle que pour tout nœud j appartenant à T : 103

105 p(j) 3 profondeur(j) (10.2) Démonstration : À chaque nœud j de T, on associe une probabilité p(j) qui est égale à la probabilité d atteindre j si on commence la recherche à la racine. Cette probabilité est déterminée de la manière suivante : 1. Commencer à la racine de l arbre. 2. Soit x le nœud courant : (a) Si x a deux fils, alors la probabilité d aller à gauche vaut 1/3, celle d aller à droite vaut 1/3 et celle de s arrêter vaut également 1/3. (b) Si x a un fils (disons le fils gauche), alors la probabilité d aller à gauche vaut 1/2 et celle de s arrêter vaut également 1/2. Le cas du fils droit est similaire. (c) Si x n a pas de fils, alors la probabilité de s arrêter vaut 1. Ce traitement est à itérer jusqu au nœud j. La probabilité p(j) correspond donc à la probabilité d atteindre le nœud j et de s y arrêter. De cette construction, nous déduisons immédiatement que p(j) 3 profondeur(j). Il ne reste plus qu à démontrer que j T p(j) = 1, de manière à vérifier que p soit bien une distribution de probabilités. Ceci peut se faire par récurrence sur la hauteur h(t ) de T : 1. Cas de base : la hauteur de T vaut 0. Dans ce cas, l arbre est constitué d un seul nœud dont la probabilité associée vaut Cas d induction : considérons que i T p(i) = 1 pour un arbre T de hauteur i et montrons que c est également le cas pour un arbre de hauteur i + 1. Soit T un arbre de hauteur i+1 et de racine t. Deux cas sont possibles : soit t a deux fils, soit il n en a qu un seul. Traitons le premier cas (le deuxième cas peut être résolu de manière similaire). La probabilité de s arrêter en t vaut 1/3, celle d aller dans le sous-arbre gauche de t vaut 1/3 et celle d aller dans le sous-arbre droit de t vaut 1/3. Comme le sous-arbre gauche de t a une hauteur i, nous pouvons y appliquer l hypothèse d induction. Mais comme ce sous-arbre est attaché à la racine de t comme fils gauche, nous avons que la probabilité de chaque nœud du sous-arbre doit être multipliée par 1/3. On obtient alors que : 104

106 i SAG(t) Finalement, nous avons que : p(i) = = 1 3 (10.3) p(i) = i T p(i) + p(i) + p(t) i SAG(t) i SAD(t) = = 1 Théorème 16. Pour une distribution de probabilités sur n accès, nous pouvons créer un arbre binaire de recherche T tel que pour tout nœud a de T : prof ondeur(a) 1 log(p(a)) (10.4) Démonstration : La construction de T se fait de manière récursive. Pour la racine de T, on choisit le premier i tel que i 1 j=1 p(j) 1/2 et n j=i+1 p(j) 1/2. Ensuite, on travaille de manière récursive sur les éléments strictement plus petits que i pour construire le sous-arbre gauche de i. Pour cela, il faut normaliser p, de manière à ce que i 1 j=1 p(j) = 1. Après cela, il faut effectuer un travail similaire sur les éléments strictement plus grands que i pour construire le sous-arbre droit de i. De la manière dont on construit T, nous constatons que pour tout nœud i de T, la somme des probabilités des nœuds appartenant au sous-arbre de i est d au plus 1/2 d 1, où d est la profondeur de i. Grâce à cette observation, nous pouvons montrer que la profondeur d un nœud i de probabilité p(i) ne peut pas être plus grande que log(p(i)). En effet, supposons que le nœud i de profondeur d soit tel que d 1 > log(p(i)) (dans ce cas d est plus grand que log(p(i))). Nous en déduisons que : 1 2 d 1 < 1 2 log(p(i)) = 2 log(p(i)) = p(i) 105

107 Et donc, 1/2 d 1 <p(i). Nous savons également que p(t i ) 1/2 d 1, où T i est le sous-arbre de i. En combinant ces deux résultats, nous obtenons que : p(t i ) 1 <p(i) (10.5) 2d 1 Or, ceci est impossible, car p(t i ) p(i). En faisant l hypothèse que d 1 > log(p(i)), nous sommes arrivés à une contradiction. On en déduit donc que : d 1 log(p(i)) d 1 log(p(i)) Théorème 17. Pour une quelconque distribution de probabilités p sur une séquence d accès, nous pouvons créer un algorithme online dont le coût pour traiter la séquence vaut tout au plus m log(p(x 1 x 2... x m )) et cela quelle que soit la séquence x 1,x 2,..., x m. Nous notons par p(x 1 x 2... x m ) la probabilité d avoir x 1,x 2,..., x m comme premier, deuxième,..., mème accès. Démonstration : Considérons les distributions de probabilités p 1,p 2,..., p m. Nous définissons la probabilité p i (x j ) comme la probabilité p d avoir x j comme ième accès sachant que x 1 était le premier accès, x 2 était le deuxième accès, et ainsi de suite jusque x i 1 le (i 1)ème accès. La probabilité p i (x j ) est définie en termes de probabilités conditionnelles de la manière suivante : p i (x j )=p(x j x 1 x 2... x i 1 ) (10.6) où p(x j x 1 x 2... x i 1 ) est la probabilité d avoir x j comme ième accès sachant que x 1,x 2,..., x i 1 étaient respectivement le premier, deuxième,..., (i 1)ème accès. Par définition des probabilités conditionnelles, nous avons que : p(b A) = p(a B) p(a) En se basant sur ce résultat, nous obtenons que : (10.7) p(x j x 1 x 2... x i 1 ) = p(x j (x 1 x 2... x i 1 ) p(x 1 x 2... x i 1 ) = p(x 1 x 2... x i 1 x j ) p(x 1 x 2... x i 1 ) 106

108 Pour la probabilité p(x 1 x 2... x i 1 x j ), nous n avons aucune restriction quant à la valeur que peut prendre le (i + 1)ème, (i + 2)ème,..., mème accès. Nous avons donc que : p(x j x 1 x 2... x i 1 )= xm b i+1 =x 1... x m b m=x 1 p(x 1... x i 1 x j b i+1... b m ) xm b i =x 1... x m b m=x 1 p(x 1...x i 1 b i... b m ) (10.8) La valeur de p i (x j ) peut alors être calculée algorithmiquement grâce au résultat ci-dessus. Soit le lemme suivant : p(a 1 A 2... A n )=p(a 1 ) p(a 2 A 1 )... p(a n A 1... A n 1 ) (10.9) En se basant sur ce lemme, nous avons que : p(x 1 x 2... x m ) = p(x 1 ) p(x 2 x 1 )... p(x m x 1... x m 1 ) = p 1 (x 1 ) p 2 (x 2 )... p m (x m ) m = p i (x i ) i=1 L algorithme online procède de la manière suivante. Pour le ième accès, on calcule la distribution de probabilités p i grâce à la formule Ensuite, on convertit la distribution de probabilités p i en un ABR en utilisant le théorème 16. De par cette construction, la profondeur d un accès x i est d au plus 1 log(p i (x i )). Le coût des m accès (en ne tenant compte que du coût pour localiser les éléments) est d au plus : m (1 log(p i (x i ))) = m log(p(x 1... x m )) (10.10) i=1 Théorème 18. Il existe un algorithme online, qui a la propriété d optimalité de recherche dynamique. Démonstration : Considérons la distribution de probabilités du théorème 14, qui assigne une probabilité de 2 13k à une séquence d accès dont le coût optimal est k. Combinons cette distribution de probabilités avec le théorème 17 pour obtenir un algorithme online, dont le coût d accès à une séquence 107

109 X = x 1,..., x m (en ne tenant compte que du coût pour localiser les éléments) est d au plus : m log ( 2 13 OP T (x 1...x m) ) = m + 13 OP T (x 1... x m ) 14 OP T (x 1... x m ), car m OP T (x 1... x m ) L algorithme online nécessite un coût d au plus 14 fois le coût optimal pour localiser les éléments d une séquence d accès. Cet algorithme a donc la propriété d optimalité de recherche dynamique Conclusion Dans cette section, nous avons présenté une structure qui atteint l optimalité de recherche dynamique. L existence d une telle structure a un grand intérêt, parce qu il s agit d un argument en faveur de l existence d une structure atteignant l optimalité dynamique. Un problème ouvert concernant l optimalité de recherche dynamique [BCK03] serait d élaborer une structure efficace, qui puisse atteindre cette propriété. 108

110 Chapitre 11 Expérimentations Dans ce chapitre, nous allons exécuter un certain nombre de jeux de tests pour analyser et comparer les performances en pratique des arbres rougesnoirs, des splay trees et des multi-splay trees. Le but est de surtout constater si les multi-splay trees fournissent des résultats intéressants en pratique et si l algorithme des multi-splay trees, qui est plus complexe que celui des arbres rouges-noirs et des splay trees, ne porte pas préjudice aux performances en pratique des multi-splay trees. Nous allons d abord expliquer le type de jeux de tests qui seront exécutés et ensuite, nous allons présenter les résultats de ces jeux de tests pour essayer d en tirer des constatations Jeux de tests Nous avons effectué plusieurs tests en considérant des tailles différentes pour la structure. Nous faisons varier la taille de la structure de 2 8 à2 16 en multipliant à chaque pas la taille de la structure par 2. Pour chaque taille n, nous faisons varier la taille de la séquence de n à 10 n par pas de log n. Pour chaque séquence, nous calculons le coût nécessaire à la structure pour l exécuter en prenant comme modèle de coût celui défini par le modèle dynamique (cfr point 2.2.1). Nous considérons deux types de distribution pour générer une séquence d accès : 1. distribution aléatoire 2. distribution working set 109

111 MST8 ST8 RB Fig Coûts d un arbre de taille 2 8 avec une distribution aléatoire 11.2 Distribution aléatoire Supposons que la taille de l arbre soit égale à n. Une séquence d accès est générée en choisissant de manière aléatoire les éléments qui la composent parmi les n éléments possibles. Les résultats de ces tests sont illustrés par les graphes des figures 11.1 et 11.2 (d autres graphes sont fournis en annexe). Ces résultats nous permettent de constater que le coût des arbres rouges-noirs est plus petit que celui des splay trees ; lui-même plus petit que celui des multi-splay trees. Ceci est vérifié sur chacun des graphiques cités ci-dessus. De plus, nous constatons sur chaque graphique que la différence de coût entre les trois structures s amplifie à mesure que la taille de la séquence augmente. Dès lors, au vue de ces résultats, on peut penser que les arbres rouges-noirs ont un meilleur comportement que les splay trees et que cette structure a un meilleur comportement que les multi-splay trees pour le type de distribution que nous considérons dans cette section. Le fait que les multi-splay trees aient de moins bonnes performances s expliquent par la complexité de l algorithme de cette structure et par le grand nombre d opérations de réorganisation qu elle nécessite. 110

112 5e e+07 MST16 ST16 RB16 4e e+07 3e e+07 2e e+07 1e+07 5e Fig Coûts d un arbre de taille 2 16 avec une distribution aléatoire 11.3 Distribution working set Supposons que la taille de la structure soit égale à n. Une séquence d accès est générée en choisissant de manière aléatoire les éléments qui la composent parmi un sous-ensemble de l ensemble 1,..., n. Ce sous-ensemble a une taille de n/5 et correspond à l ensemble n/2 n/10,..., n/2 +n/10. Le but est de tirer profit de la propriété working set des splay trees pour analyser son comportement dans ce cas. Les résultats de ces tests sont illustrés par les graphes des figures 11.3 et 11.4 (d autres graphes sont fournis en annexe). Si nous analysons le comportement des splay trees, nous remarquons qu au début il est similaire à leur comportement pour le premier type de distribution analysé. Ensuite, le comportement diffère, car nous assistons à une diminution du coût d exécution des séquences d accès. Cette diminution s explique par le fait que les splay trees ont la propriété working set. En effet, comme nous n accédons qu à un sous-ensemble des n éléments possibles, nous avons que de plus en plus d éléments de ce sous-ensemble ont tendance à se retrouver près de la racine, ce qui implique que nous avons de plus en plus d accès à faible coût. Et cela se traduit par une diminution du coût total de la séquence d accès. Après la phase de décroissance, nous avons une phase où le coût augmente, mais de 111

113 façon légère. Cette augmentation s explique par le fait que tous les éléments du sous-ensemble des éléments accédés ont été ramenés près de la racine, ce qui implique que nous ne pouvons plus espérer une amélioration du coût d exécution des séquences d accès. Dans cette phase, l augmentation du coût est légère, car les éléments accédés sont proches de la racine, ce qui implique que leur coût d accès est faible. Le comportement des arbres rouges-noirs diffère peu de leur comportement pour le premier type de distribution analysé, parce que les arbres rouges-noirs n ont pas la propriété working set et qu ils ne sont pas capables de s adapter à une séquence d accès. En ce qui concerne les multi-splay trees, nous constatons que leur comportement présente des analogies avec celui des splay trees, ce qui pourrait laisser suggérer que cette structure a la propriété working set. Ceci est à prendre avec précaution, car nous tirons une constatation sur quelques résultats, mais il n existe aucune preuve qui le démontre. Dans la dernière phase de croissance, nous constatons que le coût des multi-splay trees a tendance à croître plus vite que celui des splay trees. Ceci s explique par le fait que l algorithme des multi-splay trees exige plus d opérations de réorganisation que celui des splay trees. Nous pouvons également constater que le coût des multi-splay trees est plus petit que celui des arbres rouges-noirs. Au début de chaque graphique les arbres rouges-noirs ont un coût qui est meilleur que celui des splay trees et cette structure a un coût qui est meilleur que celui des multi-splay trees. Mais de par le type de distribution sur laquelle nous travaillons, la tendance s inverse rapidement. Les splay trees ont alors un coût meilleur que celui des multi-splay trees et ceux-ci ont un coût meilleur que celui des arbres rouges-noirs Conclusion Les différents jeux de tests exécutés nous ont permis de constater que les multi-splay trees souffrent de la complexité de leur algorithme et du grand nombre d opérations de réorganisation qu il nécessite. Nous avons également obtenu des résultats qui pourraient laisser suggérer que les multi-splay trees ont la propriété working set. Les tests effectués sur le deuxième type de distribution illustrent bien la capacité des splay trees à s adapter à une séquence d accès et à l incapacité des arbres rouges-noirs à faire de même. 112

114 MST8 ST8 RB Fig Coûts d un arbre de taille 2 8 avec une distribution working set 2.2e+07 2e+07 MST16 ST16 RB16 1.8e e e e+07 1e+07 8e+06 6e+06 4e+06 2e Fig Coûts d un arbre de taille 2 16 avec une distribution working set 113

115 Chapitre 12 Conclusion Nous avons étudié comme première structure les ABRO et nous avons détaillé l algorithme qui permet à cette structure d atteindre l optimalité statique en se basant sur la connaissance préalable de la distribution des clés à accéder. Puis, nous avons étudié les arbres rouges-noirs et les splay trees. En analysant les performances de ces structures, nous avons constaté que les arbres rouges-noirs fournissent des résultats intéressants sur un accès, alors que les splay trees ont besoin de séquences d accès plus grandes pour fournir de bonnes performances. Nous avons également constaté que les arbres rougesnoirs ne sont pas capables de s adapter aux particularités d une séquence d accès, alors que les splay trees y parviennent. C est cette qualité qui fait la force des splay trees. Et enfin, nous avons constaté que les arbres rouges-noirs sont O(logn) compétitif s, alors que les splay trees sont conjecturés être O(1) compétitif s. Ensuite, nous avons énoncé et démontré trois bornes inférieures sur le coût d exécution d une séquence d accès dans des ABR. L intérêt de telles bornes est grand, car elles permettent de développer de nouvelles structures. À l heure actuelle, le principal obstacle pour développer une structure qui puisse atteindre l optimalité dynamique, est le manque de bornes inférieures de qualité. La structure Tango a été développée sur base de l une des trois bornes étudiées : la borne inférieure d entrelacement. Cette structure est la première qui ait amélioré le taux trivial de compétitivité de O(log n). Cette structure atteint un taux de O(log(log n)). Le problème avec cette structure est qu elle est complexe, ce qui fait que son implémentation est assez lourde. Les multi-splay trees sont une structure de données ABR. Cette structure est basée sur les mêmes principes que Tango et elle atteint également un taux de compétitivité de O(log(log n)). Cette structure est plus simple 114

116 à implémenter que Tango. De plus, elle peut être étendue pour supporter les opérations d insertion et de suppression tout en gardant le taux de compétitivité de O(log(log n)). Ensuite, nous avons étudié une structure, qui atteint l optimalité de recherche dynamique. Nous avons également montré que l existence d une telle structure est importante, car il s agit d un argument en faveur de l existence d une structure optimale dynamiquement. Et enfin, nous avons exécuté des jeux de tests sur les arbres rouges-noirs, les splay trees et les multi-splay trees. Le but de ces tests était d analyser les performances en pratique de ces structures. Cela nous a permis de constater que les arbres rouges-noirs sont performants sur des séquences d accès, où les nœuds à accéder sont choisis de manière aléatoire parmi l ensemble des nœuds de l arbre. Nous avons également remarqué que les splay trees sont performants sur des séquences d accès, où les nœuds à accéder sont choisis de manière aléatoire parmi un sous-ensemble de l ensemble des nœuds de l arbre. Ceci est dû au fait que les splay trees ont la propriété working set. L analyse des performances des multi-splay trees sur ce type de séquences peut nous laisser suggérer que cette structure a également la propriété working set. Concernant les multi-splay trees, nous avons également constaté que l algorithme complexe de cette structure a une incidence sur ses performances en pratique. Ce mémoire a consisté en un travail de recherche bibliographique et il a consisté à synthétiser les grandes avancées dans le domaine des arbres binaires de recherche et de l optimalité dynamique. En général, les articles étudiés présentent les algorithmes et les démonstrations de manière assez succincte. Un objectif de ce mémoire a donc été de présenter ces algorithmes et ces démonstrations de manière didactique en les décortiquant et en les détaillant le plus possible. 115

117 Chapitre 13 Annexe 13.1 Implémentation De manière à analyser et comparer les performances en pratique des multi-splay trees, des splay trees et des arbres rouges-noirs, nous avons implémenté l algorithme des multi-splay trees et des splay trees. Pour l algorithme des arbres rouges-noirs, nous avons récupéré une implémentation sur le net [Nie05]. Ces trois implémentations sont fournies en annexe. Le but n est pas d avoir une implémentation de ces structures qui puissent faire partie d une librairie en implémentant par exemple un type générique pour les clés. Le but est de simplement avoir une implémentation permettant d exécuter des jeux de tests Multi-splay trees Les clés sont des éléments de type entier et il faut que la taille de l arbre soit égale à n =2 k 1( k>1). Les valeurs des clés correspond à l ensemble 1,..., n. Pour l implémentation de la structure, nous utilisons deux classes : 1. elem : cette classe représente un nœud de l arbre, ainsi que ses différents champs. 2. splaytree : cette classe représente le multi-splay tree. Nous détaillons ci-dessous les points principaux de l implémentation. Des explications plus détaillées sont fournies en tant que commentaires dans le code. L initialisation de la structure se fait à l aide de la méthode construirep, qui est appelée par le constructeur paramétré de la classe splaytree. Dans cette méthode, nous construisons un arbre parfait de n nœuds et nous initialisons 116

118 le fils préféré de chaque nœud à son fils gauche. Durant cette construction l isroot bit du fils gauche et du fils droit de chaque nœud est initialisé, respectivement, à false et true (car pour chaque nœud, son fils droit est son fils non préféré). De plus, le champ mindepth de chaque nœud x est initialisé à sa profondeur dans l arbre parfait (car tous les nœuds dans le splay subtree de x ont une profondeur plus grande que celle de x). L arbre parfait ainsi construit est, en fait, également un multi-splay tree et il est utilisé comme état initial de la structure. L avantage d une telle construction est qu elle permet d initialiser la structure avec un coût O(n). La méthode recherche localise d abord le nœud i passé en paramètre et réorganise ensuite la structure de manière à avoir un chemin préféré allant de la racine du multi-splay tree au nœud passé en paramètre. La réorganisation de la structure est effectuée dans la boucle principale de la méthode. Le traitement de cette boucle est le suivant. Si le nœud courant est la racine d un splay tree, alors il faut rechercher dans le splay tree de son père le nœud sur lequel effectuer un switch. Un fois ce nœud déterminé, on applique soit un switch droite-gauche (méthode switchdg), soit un switch gauche-droite (méthode switchgd). Et on recommence la boucle jusqu à ce que la racine de l arbre soit atteinte. Et lorsqu elle est atteinte, on splaye le nœud i pour le ramener à la racine de l arbre (méthode switchracine). Les méthodes switchgd et switchdg ne sont qu une implémentation des algorithmes décrits dans le chapitre 9 pour effectuer un switch. L implémentation est fournie ci-dessous. # include <iostream> # include <limits.h> # include <time.h> # include <math.h> # include <iomanip> # include <stdlib.h> # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> using namespace std ; class splaytree private : class elem 117

119 friend class splaytree ; int info ;// clé du noeud int profondeur ;// profondeur du noeud dans //l arbre de référence int mindepth ;// profondeur minimum dans le //splay subtree du noeud bool isroot ; elem fg ; elem fd ; elem pere ; elem() elem(int i, int prof=0, int mind=1, bool isr=false, elem g = NULL, elem d = NULL, elem p= NULL) :info(i),profondeur(prof), mindepth(mind), isroot(isr), fg(g), fd(d), pere(p) ; elem rac ;// racine du multi-splay tree void rotationsimple(elem,bool &) ; void zigzag(elem,bool &) ; void zigzig(elem,bool &) ; void splayingracine(elem ); void splayingto(elem, elem ); elem construirep(int,int,double,int, bool,elem ); elem localisation(int); elem determinerz(elem ); elem determinerx(elem ); void switchgd(elem ); void switchdg(elem ); return(b) ; void infixe(elem ); void destructeur(elem ); int min(int a, int b) if(a < b) return(a) ; else public : splaytree()rac=null ; splaytree(int); elem recherche(int);; 118

120 ; splaytree() ; splaytree : :splaytree(int n) //Constructeur paramétré du multi-splay tree elem p = construirep((n/2)+1,1,(log(n+1.0)/log(2.0)),0, true, NULL) ; rac=p ; splaytree : :elem splaytree : :construirep(int taille, int prof, double stop, int biais, bool isroot, elem parent) // Construit l état initial du multi-splay tree if(prof <= stop) elem p = new elem(taille+biais, prof, prof, isroot, NULL, NULL, parent) ; // la variable biais contient la valeur de la clé // du père de p, ce qui permet d initialiser la clé // de p à la bonne valeur p fg = construirep(taille/2, prof+1,stop,biais, false, p) ; p fd = construirep(taille/2, prof+1, stop, taille+biais, true, p) ; // Construction récursive pour le sous-arbre gauche // et le sous-arbre droit de p return(p) ; else return(null) ; void splaytree : :rotationsimple(elem p, bool & stop) // Cette méthode effectue une rotation simple. La variable stop //indique à l appelant si le noeud p est devenu la racine du //splay tree auquel il appartient (stop = true) ou non (stop = false) elem q=p pere ; int a=int MAX, b=int MAX ; 119

121 if(q isroot) // Dans ce cas, il faut changer l isroot bit de p et q, //car p devient la racine du splay tree auquel il //appartient et q ne l est plus q isroot=false ; p isroot=true ; stop=true ; if(q pere) // Mise à jour des pointeurs du père de q pour // qu il devienne le père de p if(q == q pere fd) q pere fd = p ; else q pere fg = p ; // Les opérations ci-dessous sont des mises à jour de //pointeurs pour effectuer la rotation simple p pere = q pere ; q pere = p ; if(p == q fg) q fg = p fd ; if(q fg) q fg pere = q ; p fd = q ; else q fd = p fg ; if(q fd) q fd pere = q ; p fg = q ; 120

122 // Les opérations ci-dessous mettent à jour les champs // mindepth, qui changent à cause de la rotation p mindepth = q mindepth ; if(q fg) a = q fg mindepth ; if(q fd) b = q fd mindepth ; q mindepth = min(q profondeur, min(a,b)) ; void splaytree : :zigzag(elem p, bool & stop) // Cette méthode effectue une rotation zig-zag. La variable stop //indique à l appelant si le noeud p est devenu la racine du splay //tree auquel il appartient (stop = true) ou non (stop = false) elem q=p pere ; elem z = q pere ; int a=int MAX, b=int MAX ; if(z isroot) // Dans ce cas, il faut changer l isroot bit de p et z, //car p devient la racine du splay tree auquel il //appartient et z ne l est plus // Mise à jour des pointeurs du père de z pour //qu il devienne le père de p z isroot=false ; p isroot=true ; stop=true ; // Les opérations ci-dessous sont des mises à jour de //pointeurs pour effectuer la rotation zig-zag p pere = z pere ; z pere = p ; q pere = p ; if(p == q fd) 121

123 else q fd = p fg ; if(q fd) q fd pere = q ; z fg = p fd ; if(z fg) z fg pere = z ; p fg = q ; p fd = z ; q fg = p fd ; if(q fg) q fg pere = q ; z fd = p fg ; if(z fd) z fd pere = z ; p fg = z ; p fd = q ; if(p pere) if(p pere fg == z) p pere fg = p ; else p pere fd = p ; // Les opérations ci-dessous mettent à jour les champs // mindepth, qui changent à cause de la rotation p mindepth = z mindepth ; if(z fg) a = z fg mindepth ; if(z fd) b = z fd mindepth ; 122

124 z mindepth = min(z profondeur, min(a,b)) ; a = INT MAX ; b = INT MAX ; if(q fg) a = q fg mindepth ; if(q fd) b = q fd mindepth ; q mindepth = min(q profondeur, min(a,b)) ; void splaytree : :zigzig(elem p, bool & stop) // Cette méthode effectue une rotation zig-zig. La variable // stop indique à l appelant si le noeud p est devenu la //racine du splay tree auquel il appartient (stop = true) //ou non (stop = false) elem q=p pere ; elem z = q pere ; int a = INT MAX, b = INT MAX ; if(z isroot) // Dans ce cas, il faut changer l isroot bit de p et z, //car p devient la racine du splay tree auquel il //appartient et z ne l est plus // Mise à jour des pointeurs du père de z pour //qu il devienne le père de p z isroot=false ; p isroot=true ; stop=true ; // Les opérations ci-dessous sont des mises à jour de //pointeurs pour effectuer la rotation zig-zig p pere = z pere ; q pere = p ; z pere = q ; 123

125 if(p == q fg) q fg = p fd ; if(q fg) q fg pere = q ; z fg = q fd ; if(z fg) z fg pere = z ; p fd = q ; q fd = z ; p mindepth = z mindepth ; if(z fg) a = z fg mindepth ; if(z fd) b = z fd mindepth ; z mindepth = min(z profondeur, min(a,b)) ; a = INT MAX ; if(q fg) a = q fg mindepth ; q mindepth = min(q profondeur, min(a,z mindepth)) ; else q fd = p fg ; if(q fd) q fd pere = q ; z fd = q fg ; if(z fd) z fd pere = z ; p fg = q ; q fg = z ; 124

126 p mindepth = z mindepth ; if(z fg) a = z fg mindepth ; if(z fd) b = z fd mindepth ; z mindepth = min(z profondeur, min(a,b)) ; a = INT MAX ; if(q fd) a = q fd mindepth ; q mindepth = min(q profondeur, min(a,z mindepth)) ; if(p pere) if(p pere fg == z) p pere fg = p ; else p pere fd = p ; void splaytree : :splayingracine(elem p) // Cette méthode splaye le noeud p jusqu à ce qu il devienne //la racine du multi-splay tree auquel il appartient elem q =p pere ; bool stop = false ; short int tester=0 ; // On vérifie que le noeud à splayer ne soit pas la //racine du multi-splay tree if(!p isroot) while(!stop && q) 125

127 if(q isroot) rotationsimple(p,stop) ; break ; else if(p == q fg) //si p est un fils gauche, on //incrémente test de 1 ++tester ; else //sinon test est décrémenté de 1 tester ; if(q == q pere fg) //si q est un fils gauche, on //incrémente test de 1 ++tester ; else //sinon test est décrémenté de 1 tester ; if(tester) //si test est différent de 0, cela //signifie qu on est remonté par deux //sens différents pour aller du //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zig zigzig(p,stop) ; tester=0 ; else //sinon on est remonté deux fois par le //même sens pour aller du //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zag zigzag(p,stop) ; 126

128 q = p pere ; if(!p pere)//si p n a pas de père, alors il // est la racine du multi-splay tree rac = p ; // on met à jour la racine du multi-splay tree void splaytree : :splayingto(elem p, elem arret) // Cette méthode splaye le noeud p jusqu à ce qu il devienne //le fils du noeud arret elem q =p pere ; short int test=0 ; bool stop=false ; while(q!= arret) if(q pere == arret) rotationsimple(p,stop) ; break ; else if(p == q fg) //si p est un fils gauche, on //incrémente test de 1 ++test ; else //sinon test est décrémenté de 1 test ; 127

129 if(q == q pere fg) //si q est un fils gauche, on //incrémente test de 1 ++test ; else //sinon test est décrémenté de 1 test ; if(test) //si test est different de 0, cela //signifie qu on est remonté par deux //sens différents pour aller du //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zig zigzig(p,stop) ; test=0 ; else //sinon on est remonté deux fois par le //même sens pour aller du //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zag zigzag(p,stop) ; q = p pere ; splaytree : :elem splaytree : :localisation(int i) // Cette méthode localise le noeud i dans le multi-splay tree elem p = rac ; elem q=null ; if(p) // On vérifie que l arbre ne soit pas vide do 128

130 q = p ; if(i == p info) return(p) ; else if(i < p info) p = p fg ; else p = p fd ; while(p) ; //si on sort du while, c est que l élément i //n est pas présent dans l arbre. return(null) ; splaytree : :elem splaytree : :recherche(int i) //Cette fonction recherche l élément i et réorganise la structure //pour tenir compte des changements causés par l accès i. elem p = localisation(i) ;//localisation de i elem save = p ; //On vérifie que le noeud i ne soit pas la racine du //multi-splay tree if(p) while(p!= rac) if(p isroot) // Dans ce cas, un changement de fils //préféré doit être effectué 129

131 //recherche du noeud a switcher, //qui sera stocké dans p à la fin //de la boucle while elem rac splay bas = p ; p=p pere ; (rac splay bas mindepth)-1) else else while(p profondeur!= p=p pere ; //après que le noeud à switcher //ait été localisé, il faut déterminer //le type de switch à effectuer if(rac splay bas info > p info) switchgd(p) ; else switchdg(p) ; p=p pere ; splayingracine(save) ;// le noeud i est remonté //jusqu à la racine return(null) ; void splaytree : :switchgd(elem y) // Cette méthode effectue un switch gauche-droite sur le noeud y elem z = NULL ; elem x = NULL ; int mingauche = INT MAX, mindroite = INT MAX ; 130

132 splayingracine(y) ;// on ramène y à la racine du splay tree //auquel il appartient z = determinerz(y) ; // on localise le noeud z. Il s agit du plus grand noeud, //qui a une information prof plus petite que celle //de y et qui est plus petit que y if(z) splayingto(z, y) ; // on splaye z jusqu à ce qu il devienne le fils //gauche de y if(z fd) // on fait du fils gauche de y dans P //son fils non préféré z fd isroot = true ; int a = INT MAX ; if(z fg) a = z fg mindepth ; z mindepth = min(z profondeur, a) ; mingauche = z mindepth ; else // z n existe pas // on fait du fils gauche de y dans P son fils //non préféré if(y fg) y fg isroot = true ; x = determinerx(y) ; // on localise le noeud x. Il s agit du plus petit noeud, //qui a une information prof plus petite que celle 131

133 //de y et qui est plus grand que y if(x) splayingto(x, y) ; // on splaye x jusqu à ce qu il devienne le fils //droit de y if(x fg) // on fait du fils droit de y dans P son //fils préféré x fg isroot = false ; if(x fg mindepth < x mindepth) x mindepth = x fg mindepth ; mindroite = x mindepth ; else // x n existe pas // on fait du fils droit de y dans P son fils préféré if(y fd) y fd isroot = false ; y mindepth = min(y profondeur, min(mingauche,mindroite)) ; void splaytree : :switchdg(elem y) // Cette méthode effectue un switch gauche-droite sur le noeud y elem z = NULL ; elem x = NULL ; int mingauche = INT MAX, mindroite = INT MAX ; splayingracine(y) ;// on ramène y à la racine du splay tree //auquel il appartient z = determinerz(y) ; 132

134 // on localise le noeud z. Il s agit du plus grand noeud, //qui a une information prof plus petite que celle //de y et qui est plus petit que y if(z) splayingto(z, y) ; // on splaye z jusqu à ce qu il devienne le fils //gauche de y if(z fd) // on fait du fils gauche de y dans P son //fils préféré z fd isroot = false ; if(z fd mindepth < z mindepth) z mindepth = z fd mindepth ; mingauche = z mindepth ; else // z n existe pas // on fait du fils gauche de y dans P son fils //préféré if(y fg) y fg isroot = false ; x = determinerx(y) ; // on localise le noeud x. Il s agit du plus petit noeud, //qui a une information prof plus petite que celle //de y et qui est plus grand que y if(x) splayingto(x, y) ; // on splaye x jusqu à ce qu il devienne le fils //droit de y 133

135 if(x fg) // on fait du fils droit de y dans P son // fils non préféré x fg isroot = true ; int a = INT MAX ; if(x fd) a = x fd mindepth ; x mindepth = min(x profondeur, a) ; mindroite = x mindepth ; else // x n existe pas // on fait du fils droit de y dans P son fils non //préféré if(y fd) y fd isroot = true ; y mindepth = min(y profondeur, min(mingauche,mindroite)) ; splaytree : :elem splaytree : :determinerz(elem y) // Cette méthode renvoie le plus grand noeud, qui a une information //prof plus petite que celle de y et qui est plus petit que y. elem x=y fg ; if(x && x mindepth < y profondeur) while(true) if(x profondeur < y profondeur) if(x fd && x fd mindepth < y profondeur) 134

136 else x = x fd ; return(x) ; y profondeur) else if(x fd && x fd mindepth < x = x fd ; else x = x fg ; else return(null) ; splaytree : :elem splaytree : :determinerx(elem y) // Cette méthode renvoie le plus petit noeud, qui a une information //prof plus petite que celle de y et qui est plus grand que y elem x=y fd ; if(x && x mindepth < y profondeur) while(true) if(x profondeur < y profondeur) if(x fg && x fg mindepth < y profondeur) x = x fg ; else return(x) ; else 135

137 y profondeur) else return(null) ; if(x fg && x fg mindepth < x = x fg ; else x = x fd ; splaytree : : splaytree() destructeur(rac) ; void splaytree : :destructeur(elem p) if(p) destructeur(p fg) ; destructeur(p fd) ; delete p; int main() return(0) ; 136

138 Splay trees Les clés sont des éléments de type entier. Les valeurs des n clés de l arbre correspondent à l ensemble 1,..., n. Pour l implémentation de la structure, nous utilisons deux classes : 1. elem : cette classe représente un nœud de l arbre. 2. splaytree : cette classe représente le splay tree. Nous détaillons ci-dessous les points principaux de l implémentation. Des explications plus détaillées sont fournies en tant que commentaires dans le code. L initialisation de la structure se fait dans le constructeur paramétré de la classe splaytree. Elle consiste à insérer de manière successive les n éléments de l arbre dans l ordre croissant. Elle fait appel pour cela à la méthode insertion. La méthode insertion consiste à insérer l élément passé en paramètre dans l arbre. Cette méthode n est qu une implémentation de l algorithme d insertion de splay trees décrit dans le chapitre 6. La méthode recherche consiste à localiser l élément passé en paramètre. Après cela, elle invoque la méthode splaying pour remonter l élément recherché à la racine. La méthode splaying consiste à remonter l élément passé en paramètre à la racine. La remontée est effectuée dans la boucle principale. Le traitement de cette boucle consiste à déterminer le type de rotation qu il faut effectuer (soit une rotation simple, soit une rotation zig-zig, soit une rotation zig-zag) et à invoquer, ensuite, la méthode adéquate pour l effectuer. La boucle est recommencée jusqu à ce que la racine soit atteinte. L implémentation est fournie ci-dessous. # include <iostream> # include <limits.h> # include <time.h> # include <math.h> # include <iomanip> # include <stdlib.h> # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> using namespace std ; class splaytree 137

139 private : class elem friend class splaytree ; int info ; elem fg ; elem fd ; elem pere ; elem() elem(int i, elem g = NULL, elem d= NULL, elem p = NULL) :info(i), fg(g), fd(d), pere(p) ; elem rac ; void rotationsimple(elem ); void zigzag(elem ); void zigzig(elem ); void splaying(elem ); void destructeur(elem ); ; public : splaytree()rac=null ; splaytree(int); elem recherche(int); void insertion(int); void suppression(int); splaytree() ; splaytree : :splaytree(int i) //constructeur du splay tree rac=new elem(1) ; for(int j=2 ; j <= i ; j++) insertion(j) ; 138

140 void splaytree : :rotationsimple(elem p) // si l élément à splayer n a pas de grand-père on appelle // cette fonction pour réaliser la rotation elem q=p pere ; p pere = NULL ; q pere = p ; if(p == q fg) q fg = p fd ; if(q fg) q fg pere = q ; p fd = q ; else q fd = p fg ; if(q fd) q fd pere = q ; p fg = q ; void splaytree : :zigzag(elem p) //si le noeud à splayer est le fils droit(gauche) d un fils //gauche(droit), on appelle cette fonction pour //effectuer la rotation elem q=p pere ; elem z = q pere ; p pere = z pere ; z pere = p ; 139

141 q pere = p ; if(p == q fd) q fd = p fg ; if(q fd) q fd pere = q ; z fg = p fd ; if(z fg) z fg pere = z ; p fg = q ; p fd = z ; else q fg = p fd ; if(q fg) q fg pere = q ; z fd = p fg ; if(z fd) z fd pere = z ; p fg = z ; p fd = q ; if(p pere) if(p pere fg == z) p pere fg = p ; else p pere fd = p ; void splaytree : :zigzig(elem p) // si le noeud à splayer est le fils gauche(droit) d un //fils gauche(droit), on appelle cette fonction pour //effectuer la rotation 140

142 elem q=p pere ; elem z = q pere ; p pere = z pere ; q pere = p ; z pere = q ; if(p == q fg) q fg = p fd ; if(q fg) q fg pere = q ; z fg = q fd ; if(z fg) z fg pere = z ; p fd = q ; q fd = z ; else q fd = p fg ; if(q fd) q fd pere = q ; z fd = q fg ; if(z fd) z fd pere = z ; p fg = q ; q fg = z ; if(p pere) if(p pere fg == z) p pere fg = p ; else p pere fd = p ; 141

143 void splaytree : :splaying(elem p) //fonction qui réalise un splaying sur un noeud. Ce splaying //remontera ce noeud jusqu à la racine de l arbre par //une série de rotations. Cette fonction déterminera //le type de rotation à réaliser sur le noeud //à chaque étape du splaying elem q =p pere ; short int test=0 ; while(q) //si p est la racine, alors son pointeur père q est nul if(!q pere) else rotationsimple(p) ; break ; if(p == q fg) //si p est un fils gauche, on //incrémente test de 1 ++test ; else //sinon test est décrémenté de 1 test ; if(q == q pere fg) //si q est un fils gauche, on //incrémente test de 1 ++test ; else //sinon test est décrémenté de 1 test ; if(test) //si test est différent de 0, cela //signifie qu on est remonté par deux //sens différents pour aller du 142

144 //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zig zigzig(p) ; test=0 ; else //sinon on est remonté deux fois par le //même sens pour aller du //noeud x à son grand-père. Il faut //donc effectuer une rotation zig-zag zigzag(p) ; q = p pere ; rac = p ; splaytree : :elem splaytree : :recherche(int i) //Cette fonction recherche un élément dans un splay tree. Si //l élément est présent dans l arbre, un pointeur vers le noeud //recherché est renvoyé. Sinon le pointeur NULL est renvoyé pour //signaler que l élément n est pas présent dans l arbre elem p = rac ; elem q=null ; if(p) do q = p ; if(i == p info) splaying(p) ; 143

145 else return(p) ; if(i < p info) p = p fg ; else p = p fd ; while(p) ; //si on sort du while, c est que l élément n est //pas dans l arbre. On réalise donc un splaying //sur le dernier élément rencontré pendant //la recherche. splaying(q) ; return(null) ; void splaytree : :insertion(int i) //Cette fonction insère un élément dans l arbre, puis y applique //un splaying elem p = rac ; if(p) elem q = NULL ; do q = p ; if( i<= p info) p = p fg ; else p = p fd ; 144

146 while(p) ; if( i<= q info) q fg = new elem(i) ; q fg pere = q ; splaying(q fg) ; else q fd = new elem(i) ; q fd pere = q ; splaying(q fd) ; else rac = new elem(i) ; void splaytree : :suppression(int i) //Pour supprimer un élément, on doit d abord appeler la //fonction rechercher en passant comme paramètre l élément //à supprimer. Cet élément devient alors la racine //de l arbre. Puis, on supprime cette racine et on obtient //deux sous-arbres que l on doit fusionner. Pour ce faire, //il suffit de prendre le plus grand élément dans le sous-arbre //gauche(le fils droit le plus à droite dans le sous-arbre //gauche) et de le remonter jusqu à la racine (par la fonction //de splaying). La racine du sous-arbre gauche ne possédant plus //de fils droit, il suffit de rattacher la racine du sous-arbre //droit comme fils droit de la racine du sous-arbre gauche. elem p; if((p = recherche(i))) splaying(p) ; // l élément à effacer est devenu la racine //de l arbre 145

147 elem ssarbreg = p fg ; if (p fg) rac = p fg ; p fg pere= 0 ; elem ssarbred = p fd ; delete p; // suppression de la racine de l arbre if( ssarbred && ssarbreg) ssarbred pere= 0 ; elem q = 0 ; for( p = rac ; p ; p= p fd) // recherche du noeud le plus à droite // du sous-arbre gauche if(q) q = p ; splaying(q) ; q fd = ssarbred ; ssarbred pere = q ; else if(ssarbred) rac = ssarbred ; ssarbred pere= 0 ; 146

148 else if(!ssarbreg) rac = 0 ; splaytree : : splaytree() destructeur(rac) ; void splaytree : :destructeur(elem p) if(p) destructeur(p fg) ; destructeur(p fd) ; delete p; int main() return(0) ; 147

149 Arbres rouges-noirs L implémentation est fournie ci-dessous. # include <stdio.h> # include <stdlib.h> # include <string.h> # include <stdarg.h> # include <time.h> # include <math.h> # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> / implementation independent declarations / / Red-Black tree description / typedef enum BLACK, RED nodecolor ; typedef struct nodetag struct nodetag left ; / left child / struct nodetag right ; / right child / struct nodetag parent ; / parent / nodecolor color ; / node color (BLACK, RED) / int key ; / key used for searching / / user data / nodetype ; #define NIL &sentinel / all leafs are sentinels / static nodetype sentinel = NIL, NIL, 0, BLACK, 0 ; / last node found, optimizes find/delete operations / static nodetype lastfind ; static nodetype root = NIL ; / root of Red-Black tree / static void rotateleft(nodetype x) / rotate node x to left / 148

150 nodetype y = x right ; / establish x->right link / x right = y left ; if (y left!= NIL) y left parent = x ; / establish y->parent link / if (y!= NIL) y parent = x parent ; if (x parent) if (x == x parent left) x parent left = y ; else x parent right = y ; else root = y ; / link x and y / y left = x ; if (x!= NIL) x parent = y ; static void rotateright(nodetype x) / rotate node x to right / nodetype y = x left ; / establish x->left link / x left = y right ; if (y right!= NIL) y right parent = x ; / establish y->parent link / if (y!= NIL) y parent = x parent ; if (x parent) 149

151 if (x == x parent right) x parent right = y ; else x parent left = y ; else root = y ; / link x and y / y right = x ; if (x!= NIL) x parent = y ; static void insertfixup(nodetype x) / maintain Red-Black tree balance after inserting node x / / check Red-Black properties / while (x!= root && x parent color == RED) / we have a violation / if (x parent == x parent parent left) nodetype y = x parent parent right ; if (y color == RED) / uncle is RED / x parent color = BLACK ; y color = BLACK ; x parent parent color = RED ; x = x parent parent ; 150

152 else / uncle is BLACK / if (x == x parent right) / make x a left child / x = x parent ; rotateleft(x) ; / recolor and rotate / x parent color = BLACK ; x parent parent color = RED ; rotateright(x parent parent) ; else / mirror image of above code / nodetype y = x parent parent left ; if (y color == RED) else / uncle is RED / x parent color = BLACK ; y color = BLACK ; x parent parent color = RED ; x = x parent parent ; / uncle is BLACK / if (x == x parent left) 151

153 x = x parent ; rotateright(x) ; x parent color = BLACK ; x parent parent color = RED ; rotateleft(x parent parent) ; root color = BLACK ; void insert(int key) nodetype current, parent, x; / allocate node for data and insert in tree / / find future parent / current = root ; parent = 0 ; while (current!= NIL) / if (compeq(key, current->key)) return STATUS DUPLICATE KEY ; / parent = current ; current = (key < current key)? current left : current right ; / setup new node / 152

154 x =(nodetype ) malloc (sizeof( x)) ; x parent = parent ; x left = NIL ; x right = NIL ; x color = RED ; x key = key ; / insert node in tree / if(parent) if((key < parent key)) parent left = x ; else parent right = x ; else root = x ; insertfixup(x) ; lastfind = NULL ; static void deletefixup(nodetype x) / maintain Red-Black tree balance after deleting node x / while (x!= root && x color == BLACK) if (x == x parent left) nodetype w = x parent right ; if (w color == RED) 153

155 BLACK) w color = BLACK ; x parent color = RED ; rotateleft (x parent) ; w = x parent right ; if (w left color == BLACK && w right color == w color = RED ; x = x parent ; else if (w right color == BLACK) w left color = BLACK ; w color = RED ; rotateright (w) ; w = x parent right ; w color = x parent color ; x parent color = BLACK ; w right color = BLACK ; rotateleft (x parent) ; x = root ; else nodetype w = x parent left ; if (w color == RED) w color = BLACK ; x parent color = RED ; rotateright (x parent) ; w = x parent left ; if (w right color == BLACK && w left color == 154

156 BLACK) w color = RED ; x = x parent ; else if (w left color == BLACK) w right color = BLACK ; w color = RED ; rotateleft (w) ; w = x parent left ; w color = x parent color ; x parent color = BLACK ; w left color = BLACK ; rotateright (x parent) ; x = root ; x color = BLACK ; void deleter(int key) nodetype x, y, z; / delete node z from tree / z = root ; while(z!= NIL) if((key == z key)) 155

157 else break ; z = (key < z key)? z left : z right ; / if (z == NIL) return STATUS KEY NOT FOUND ; / if (z left == NIL z right == NIL) / y has a NIL node as a child / y = z ; else / find tree successor with a NIL node as a child / y = z right ; while (y left!= NIL) y = y left ; / x is y s only child / if (y left!= NIL) x = y left ; else x = y right ; / remove y from the parent chain / x parent = y parent ; if (y parent) if (y == y parent left) y parent left = x ; else 156

158 else root = x ; y parent right = x ; if (y!= z) z key = y key ; if (y color == BLACK) deletefixup (x) ; free (y) ; lastfind = NULL ; int find(int key) / find node containing data / nodetype current = root ; while(current!= NIL) if((key == current key)) lastfind = current ; return 1; else current = (key < current key)? current left : current right ; 157

159 return 0; void destructeur(nodetype p) if(p!= NIL) destructeur(p left) ; destructeur(p right) ; free(p) ; int main() return(0) ; 13.2 Jeux de tests Nous fournissons ci-dessous le reste des diagrammes des jeux de tests pour montrer que les résultats obtenus sont bien consistants. 158

160 MST9 ST9 RB Fig Coûts d un arbre de taille 2 9 avec une distribution aléatoire MST10 ST10 RB Fig Coûts d un arbre de taille 2 10 avec une distribution aléatoire 159

161 1e MST11 ST11 RB Fig Coûts d un arbre de taille 2 11 avec une distribution aléatoire 2.5e+06 MST12 ST12 RB12 2e e+06 1e Fig Coûts d un arbre de taille 2 12 avec une distribution aléatoire 160

162 5e e+06 MST13 ST13 RB13 4e e+06 3e e+06 2e e+06 1e Fig Coûts d un arbre de taille 2 13 avec une distribution aléatoire 1.1e+07 1e+07 MST14 ST14 RB14 9e+06 8e+06 7e+06 6e+06 5e+06 4e+06 3e+06 2e+06 1e Fig Coûts d un arbre de taille 2 14 avec une distribution aléatoire 161

163 2.5e+07 MST15 ST15 RB15 2e e+07 1e+07 5e Fig Coûts d un arbre de taille 2 15 avec une distribution aléatoire MST9 ST9 RB Fig Coûts d un arbre de taille 2 9 avec une distribution working set 162

164 MST10 ST10 RB Fig Coûts d un arbre de taille 2 10 avec une distribution working set MST11 ST11 RB Fig Coûts d un arbre de taille 2 11 avec une distribution working set 163

165 1e MST12 ST12 RB Fig Coûts d un arbre de taille 2 12 avec une distribution working set 2.5e+06 MST13 ST13 RB13 2e e+06 1e Fig Coûts d un arbre de taille 2 13 avec une distribution working set 164

166 4.5e+06 4e+06 MST14 ST14 RB14 3.5e+06 3e e+06 2e e+06 1e Fig Coûts d un arbre de taille 2 14 avec une distribution working set 1e+07 9e+06 MST15 ST15 RB15 8e+06 7e+06 6e+06 5e+06 4e+06 3e+06 2e+06 1e Fig Coûts d un arbre de taille 2 15 avec une distribution working set 165

167 Bibliographie [AVL62] [BCK03] [Bit79] George M. Adel son-vel skii and Evgenii M. Landis. An algorithm for the organisation of information. Soviet Mathematics Doklay, 3 : , Avrim Blum, Shuchi Chawla, and Adam Kalai. Static optimality and dynamic search optimality in lists and trees. Algorithmica, 36(3) : , James R. Bitner. Heuristics that dynamically organize data structures. SIAM Journal of Computing, 8 :82 110, [BLM + 03] Gerth S. Brodal, George Lagogiannis, Christos Makris, Athanasios Tsakalidis, and Kostas Tsichlas. Optimal finger search trees in the pointer machine. Journal of Computer and System Sciences, 67(2) : , [BT80] [Car04] [Col00] [DHIP04] [DSW05] [DSW06] Mark R. Brown and Robert E. Tarjan. Design and analysis of a data structure for representing sorted lists. SIAM Journal Computer, 9 : , Jean Cardinal. Structures de l information. Presses Universitaire de Bruxelles, 3ème edition, Richard Cole. On the dynamic finger conjecture for splay trees. SIAM Journal of Computing, 30 :44 85, Erik D. Demaine, Dion Harmon, John Iacono, and Mihai Patrascu. Dynamic optimality-almost. In Proceedings of the 45th Annual IEEE Symposium on Fonudations of Computer Science, pages , Jonathan Derryberry, Daniel D. Sleator, and Chengwen C. Wang. A lower bound framework for binary search trees with rotations. Technical report, Carnegie Mellon University, Jonathan Derryberry, Daniel D. Sleator, and Chengwen C. Wang. (log log n)-competitive dynamic binary search trees. pages ,

168 [FS98] Philippe Flajolet and Robert Sedgewick. Introduction l analyse des algorithmes. International Thomson publishing, [Iac01] John Iacono. Alternatives to splay trees with o(log n) worst-case access times. Symposium on Discrete Algorithms, pages , [Iac05] John Iacono. Key-independent optimality. Algorithmica, 42(1) :3 10, [Knu73] Donald E. Knuth. Computing Programming, Sorting and Searching, volume 3. Addison-Wesley, 2ème edition, [Mar02] Olivier Markowitch. Université libre de bruxelles, INFO 090 : Algorithmique général 1, http :// [Nie05] Tom Niemann, http ://epaperpress.com/sortsearch/txt/ rbt.txt. [Sah05] Sartaj Sahni. Efficient binary search trees, University of Florida, COP 5536 : Advanced Data Structures, http :// sahni/cop5536. [Sed04] Robert Sedgewick. Algorithmes en C++. Pearson Education, [ST85] [SW04] [Tar85] [Wei99] [Wil89] Daniel D. Sleator and Robert E. Tarjan. Self-adjusting binary search trees. Journal of the ACM, 32 : , Daniel D. Sleator and Chengwen C. Wang. Dynamic optimaltity and multi-splay trees. Technical report, Carnegie Mellon University, Robert E. Tarjan. Amortized computational complexity. SIAM Journal on Algebraic and Discrete Methods, 6 : , Mark A. Weiss. Data Structures and Algorithm Analysis in Java. Addison-Wesley, Robert Wilber. Lower bounds for accessing binary search trees with rotations. SIAM Journal of Computing, 18 :56 67,

ARBRES BINAIRES DE RECHERCHE

ARBRES BINAIRES DE RECHERCHE ARBRES BINAIRES DE RECHERCHE Table de symboles Recherche : opération fondamentale données : éléments avec clés Type abstrait d une table de symboles (symbol table) ou dictionnaire Objets : ensembles d

Plus en détail

Les structures de données. Rajae El Ouazzani

Les structures de données. Rajae El Ouazzani Les structures de données Rajae El Ouazzani Les arbres 2 1- Définition de l arborescence Une arborescence est une collection de nœuds reliés entre eux par des arcs. La collection peut être vide, cad l

Plus en détail

Définitions. Numéro à préciser. (Durée : )

Définitions. Numéro à préciser. (Durée : ) Numéro à préciser (Durée : ) On étudie dans ce problème l ordre lexicographique pour les mots sur un alphabet fini et plusieurs constructions des cycles de De Bruijn. Les trois parties sont largement indépendantes.

Plus en détail

La fonction exponentielle

La fonction exponentielle DERNIÈRE IMPRESSION LE 2 novembre 204 à :07 La fonction exponentielle Table des matières La fonction exponentielle 2. Définition et théorèmes.......................... 2.2 Approche graphique de la fonction

Plus en détail

Quelques Algorithmes simples

Quelques Algorithmes simples Quelques Algorithmes simples Irène Guessarian [email protected] 10 janvier 2012 Je remercie Patrick Cegielski de son aide efficace pour la programmation Java ; la section sur le codage de Huffman a été

Plus en détail

1 de 46. Algorithmique. Trouver et Trier. Florent Hivert. Mél : [email protected] Page personnelle : http://www.lri.fr/ hivert

1 de 46. Algorithmique. Trouver et Trier. Florent Hivert. Mél : Florent.Hivert@lri.fr Page personnelle : http://www.lri.fr/ hivert 1 de 46 Algorithmique Trouver et Trier Florent Hivert Mél : [email protected] Page personnelle : http://www.lri.fr/ hivert 2 de 46 Algorithmes et structures de données La plupart des bons algorithmes

Plus en détail

De même, le périmètre P d un cercle de rayon 1 vaut P = 2π (par définition de π). Mais, on peut démontrer (difficilement!) que

De même, le périmètre P d un cercle de rayon 1 vaut P = 2π (par définition de π). Mais, on peut démontrer (difficilement!) que Introduction. On suppose connus les ensembles N (des entiers naturels), Z des entiers relatifs et Q (des nombres rationnels). On s est rendu compte, depuis l antiquité, que l on ne peut pas tout mesurer

Plus en détail

Image d un intervalle par une fonction continue

Image d un intervalle par une fonction continue DOCUMENT 27 Image d un intervalle par une fonction continue La continuité d une fonction en un point est une propriété locale : une fonction est continue en un point x 0 si et seulement si sa restriction

Plus en détail

Algorithmique et Programmation

Algorithmique et Programmation École Supérieure d Ingénieurs de Poitiers Gea Algorithmique et Programmation Laurent Signac ii Algorithmique et programmation Gea Table des matières Avant Propos v Structures de données Notion de pointeur..............................................

Plus en détail

Chapitre 7. Récurrences

Chapitre 7. Récurrences Chapitre 7 Récurrences 333 Plan 1. Introduction 2. Applications 3. Classification des récurrences 4. Résolution de récurrences 5. Résumé et comparaisons Lectures conseillées : I MCS, chapitre 20. I Rosen,

Plus en détail

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2 éducalgo Manuel d utilisation 26 juin 2011 Table des matières 1 Tâche à effectuer : écrire un algorithme 2 2 Comment écrire un algorithme? 3 2.1 Avec quoi écrit-on? Avec les boutons d écriture........

Plus en détail

Chapitre 3. Quelques fonctions usuelles. 1 Fonctions logarithme et exponentielle. 1.1 La fonction logarithme

Chapitre 3. Quelques fonctions usuelles. 1 Fonctions logarithme et exponentielle. 1.1 La fonction logarithme Chapitre 3 Quelques fonctions usuelles 1 Fonctions logarithme et eponentielle 1.1 La fonction logarithme Définition 1.1 La fonction 7! 1/ est continue sur ]0, +1[. Elle admet donc des primitives sur cet

Plus en détail

1 Recherche en table par balayage

1 Recherche en table par balayage 1 Recherche en table par balayage 1.1 Problème de la recherche en table Une table désigne une liste ou un tableau d éléments. Le problème de la recherche en table est celui de la recherche d un élément

Plus en détail

Limites finies en un point

Limites finies en un point 8 Limites finies en un point Pour ce chapitre, sauf précision contraire, I désigne une partie non vide de R et f une fonction définie sur I et à valeurs réelles ou complees. Là encore, les fonctions usuelles,

Plus en détail

LE PROBLEME DU PLUS COURT CHEMIN

LE PROBLEME DU PLUS COURT CHEMIN LE PROBLEME DU PLUS COURT CHEMIN Dans cette leçon nous définissons le modèle de plus court chemin, présentons des exemples d'application et proposons un algorithme de résolution dans le cas où les longueurs

Plus en détail

Dualité dans les espaces de Lebesgue et mesures de Radon finies

Dualité dans les espaces de Lebesgue et mesures de Radon finies Chapitre 6 Dualité dans les espaces de Lebesgue et mesures de Radon finies Nous allons maintenant revenir sur les espaces L p du Chapitre 4, à la lumière de certains résultats du Chapitre 5. Sauf mention

Plus en détail

3 Approximation de solutions d équations

3 Approximation de solutions d équations 3 Approximation de solutions d équations Une équation scalaire a la forme générale f(x) =0où f est une fonction de IR dans IR. Un système de n équations à n inconnues peut aussi se mettre sous une telle

Plus en détail

Optimisation non linéaire Irène Charon, Olivier Hudry École nationale supérieure des télécommunications

Optimisation non linéaire Irène Charon, Olivier Hudry École nationale supérieure des télécommunications Optimisation non linéaire Irène Charon, Olivier Hudry École nationale supérieure des télécommunications A. Optimisation sans contrainte.... Généralités.... Condition nécessaire et condition suffisante

Plus en détail

Travaux pratiques. Compression en codage de Huffman. 1.3. Organisation d un projet de programmation

Travaux pratiques. Compression en codage de Huffman. 1.3. Organisation d un projet de programmation Université de Savoie Module ETRS711 Travaux pratiques Compression en codage de Huffman 1. Organisation du projet 1.1. Objectifs Le but de ce projet est d'écrire un programme permettant de compresser des

Plus en détail

SUPPORT DE COURS. Dr. Omari Mohammed Maître de Conférences Classe A Université d Adrar Courriel : [email protected]

SUPPORT DE COURS. Dr. Omari Mohammed Maître de Conférences Classe A Université d Adrar Courriel : omarinmt@gmail.com Dr. Omari Mohammed Maître de Conférences Classe A Université d Adrar Courriel : [email protected] SUPPORT DE COURS Matière : Algorithmiques et Structures de Données 1 Niveau : 2 ème Année Licence en Informatique

Plus en détail

I - PUISSANCE D UN POINT PAR RAPPORT A UN CERCLE CERCLES ORTHOGONAUX POLES ET POLAIRES

I - PUISSANCE D UN POINT PAR RAPPORT A UN CERCLE CERCLES ORTHOGONAUX POLES ET POLAIRES I - PUISSANCE D UN POINT PAR RAPPORT A UN CERCLE CERCLES ORTHOGONAUX POLES ET POLAIRES Théorème - Définition Soit un cercle (O,R) et un point. Une droite passant par coupe le cercle en deux points A et

Plus en détail

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot Chapitre 5 Arithmétique binaire L es codes sont manipulés au quotidien sans qu on s en rende compte, et leur compréhension est quasi instinctive. Le seul fait de lire fait appel au codage alphabétique,

Plus en détail

Introduction à la théorie des graphes. Solutions des exercices

Introduction à la théorie des graphes. Solutions des exercices CAHIERS DE LA CRM Introduction à la théorie des graphes Solutions des exercices Didier Müller CAHIER N O 6 COMMISSION ROMANDE DE MATHÉMATIQUE 1 Graphes non orientés Exercice 1 On obtient le graphe biparti

Plus en détail

Exemples de problèmes et d applications. INF6953 Exemples de problèmes 1

Exemples de problèmes et d applications. INF6953 Exemples de problèmes 1 Exemples de problèmes et d applications INF6953 Exemples de problèmes Sommaire Quelques domaines d application Quelques problèmes réels Allocation de fréquences dans les réseaux radio-mobiles Affectation

Plus en détail

Chapitre 5 : Flot maximal dans un graphe

Chapitre 5 : Flot maximal dans un graphe Graphes et RO TELECOM Nancy A Chapitre 5 : Flot maximal dans un graphe J.-F. Scheid 1 Plan du chapitre I. Définitions 1 Graphe Graphe valué 3 Représentation d un graphe (matrice d incidence, matrice d

Plus en détail

La mesure de Lebesgue sur la droite réelle

La mesure de Lebesgue sur la droite réelle Chapitre 1 La mesure de Lebesgue sur la droite réelle 1.1 Ensemble mesurable au sens de Lebesgue 1.1.1 Mesure extérieure Définition 1.1.1. Un intervalle est une partie convexe de R. L ensemble vide et

Plus en détail

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004 Questionnaire d'examen final INF1101 Sigle du cours Nom : Signature : Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004 Professeur(s)

Plus en détail

ÉPREUVE COMMUNE DE TIPE 2008 - Partie D

ÉPREUVE COMMUNE DE TIPE 2008 - Partie D ÉPREUVE COMMUNE DE TIPE 2008 - Partie D TITRE : Les Fonctions de Hachage Temps de préparation :.. 2 h 15 minutes Temps de présentation devant le jury :.10 minutes Entretien avec le jury :..10 minutes GUIDE

Plus en détail

Programmation linéaire

Programmation linéaire 1 Programmation linéaire 1. Le problème, un exemple. 2. Le cas b = 0 3. Théorème de dualité 4. L algorithme du simplexe 5. Problèmes équivalents 6. Complexité de l Algorithme 2 Position du problème Soit

Plus en détail

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/ Recherche opérationnelle Les démonstrations et les exemples seront traités en cours Souad EL Bernoussi Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/ Table des matières 1 Programmation

Plus en détail

Plus courts chemins, programmation dynamique

Plus courts chemins, programmation dynamique 1 Plus courts chemins, programmation dynamique 1. Plus courts chemins à partir d un sommet 2. Plus courts chemins entre tous les sommets 3. Semi-anneau 4. Programmation dynamique 5. Applications à la bio-informatique

Plus en détail

Les arbres binaires de recherche

Les arbres binaires de recherche Institut Galilée Année 2010-2011 Algorithmique et arbres L2 TD 6 Les arbres binaires de recherche Type en C des arbres binaires (également utilisé pour les ABR) : typedef struct noeud_s { struct noeud_s

Plus en détail

Le produit semi-direct

Le produit semi-direct Le produit semi-direct Préparation à l agrégation de mathématiques Université de Nice - Sophia Antipolis Antoine Ducros Octobre 2007 Ce texte est consacré, comme son titre l indique, au produit semi-direct.

Plus en détail

Exercices - Fonctions de plusieurs variables : corrigé. Pour commencer

Exercices - Fonctions de plusieurs variables : corrigé. Pour commencer Pour commencer Exercice 1 - Ensembles de définition - Première année - 1. Le logarithme est défini si x + y > 0. On trouve donc le demi-plan supérieur délimité par la droite d équation x + y = 0.. 1 xy

Plus en détail

Probabilités sur un univers fini

Probabilités sur un univers fini [http://mp.cpgedupuydelome.fr] édité le 7 août 204 Enoncés Probabilités sur un univers fini Evènements et langage ensembliste A quelle condition sur (a, b, c, d) ]0, [ 4 existe-t-il une probabilité P sur

Plus en détail

Sujet proposé par Yves M. LEROY. Cet examen se compose d un exercice et de deux problèmes. Ces trois parties sont indépendantes.

Sujet proposé par Yves M. LEROY. Cet examen se compose d un exercice et de deux problèmes. Ces trois parties sont indépendantes. Promotion X 004 COURS D ANALYSE DES STRUCTURES MÉCANIQUES PAR LA MÉTHODE DES ELEMENTS FINIS (MEC 568) contrôle non classant (7 mars 007, heures) Documents autorisés : polycopié ; documents et notes de

Plus en détail

Continuité et dérivabilité d une fonction

Continuité et dérivabilité d une fonction DERNIÈRE IMPRESSIN LE 7 novembre 014 à 10:3 Continuité et dérivabilité d une fonction Table des matières 1 Continuité d une fonction 1.1 Limite finie en un point.......................... 1. Continuité

Plus en détail

Chp. 4. Minimisation d une fonction d une variable

Chp. 4. Minimisation d une fonction d une variable Chp. 4. Minimisation d une fonction d une variable Avertissement! Dans tout ce chapître, I désigne un intervalle de IR. 4.1 Fonctions convexes d une variable Définition 9 Une fonction ϕ, partout définie

Plus en détail

Eléments de Théorie des Graphes et Programmation Linéaire

Eléments de Théorie des Graphes et Programmation Linéaire INSTITUT NATIONAL POLYTECHNIQUE DE LORRAINE Ecole Nationale Supérieure d Electricité et de Mécanique Eléments de Théorie des Graphes et Programmation Linéaire Didier Maquin Professeur à l INPL Version

Plus en détail

ALGORITHMIQUE II NOTION DE COMPLEXITE. SMI AlgoII

ALGORITHMIQUE II NOTION DE COMPLEXITE. SMI AlgoII ALGORITHMIQUE II NOTION DE COMPLEXITE 1 2 Comment choisir entre différents algorithmes pour résoudre un même problème? Plusieurs critères de choix : Exactitude Simplicité Efficacité (but de ce chapitre)

Plus en détail

Complexité. Licence Informatique - Semestre 2 - Algorithmique et Programmation

Complexité. Licence Informatique - Semestre 2 - Algorithmique et Programmation Complexité Objectifs des calculs de complexité : - pouvoir prévoir le temps d'exécution d'un algorithme - pouvoir comparer deux algorithmes réalisant le même traitement Exemples : - si on lance le calcul

Plus en détail

Propriétés des options sur actions

Propriétés des options sur actions Propriétés des options sur actions Bornes supérieure et inférieure du premium / Parité call put 1 / 1 Taux d intérêt, capitalisation, actualisation Taux d intéret composés Du point de vue de l investisseur,

Plus en détail

I. Polynômes de Tchebychev

I. Polynômes de Tchebychev Première épreuve CCP filière MP I. Polynômes de Tchebychev ( ) 1.a) Tout réel θ vérifie cos(nθ) = Re ((cos θ + i sin θ) n ) = Re Cn k (cos θ) n k i k (sin θ) k Or i k est réel quand k est pair et imaginaire

Plus en détail

Annexe 6. Notions d ordonnancement.

Annexe 6. Notions d ordonnancement. Annexe 6. Notions d ordonnancement. APP3 Optimisation Combinatoire: problèmes sur-contraints et ordonnancement. Mines-Nantes, option GIPAD, 2011-2012. [email protected] Résumé Ce document

Plus en détail

Résolution d équations non linéaires

Résolution d équations non linéaires Analyse Numérique Résolution d équations non linéaires Said EL HAJJI et Touria GHEMIRES Université Mohammed V - Agdal. Faculté des Sciences Département de Mathématiques. Laboratoire de Mathématiques, Informatique

Plus en détail

Cours de Master Recherche

Cours de Master Recherche Cours de Master Recherche Spécialité CODE : Résolution de problèmes combinatoires Christine Solnon LIRIS, UMR 5205 CNRS / Université Lyon 1 2007 Rappel du plan du cours 16 heures de cours 1 - Introduction

Plus en détail

Les indices à surplus constant

Les indices à surplus constant Les indices à surplus constant Une tentative de généralisation des indices à utilité constante On cherche ici en s inspirant des indices à utilité constante à définir un indice de prix de référence adapté

Plus en détail

Continuité en un point

Continuité en un point DOCUMENT 4 Continuité en un point En général, D f désigne l ensemble de définition de la fonction f et on supposera toujours que cet ensemble est inclus dans R. Toutes les fonctions considérées sont à

Plus en détail

Sur certaines séries entières particulières

Sur certaines séries entières particulières ACTA ARITHMETICA XCII. 2) Sur certaines séries entières particulières par Hubert Delange Orsay). Introduction. Dans un exposé à la Conférence Internationale de Théorie des Nombres organisée à Zakopane

Plus en détail

Eteindre. les. lumières MATH EN JEAN 2013-2014. Mme BACHOC. Elèves de seconde, première et terminale scientifiques :

Eteindre. les. lumières MATH EN JEAN 2013-2014. Mme BACHOC. Elèves de seconde, première et terminale scientifiques : MTH EN JEN 2013-2014 Elèves de seconde, première et terminale scientifiques : Lycée Michel Montaigne : HERITEL ôme T S POLLOZE Hélène 1 S SOK Sophie 1 S Eteindre Lycée Sud Médoc : ROSIO Gauthier 2 nd PELGE

Plus en détail

La demande Du consommateur. Contrainte budgétaire Préférences Choix optimal

La demande Du consommateur. Contrainte budgétaire Préférences Choix optimal La demande Du consommateur Contrainte budgétaire Préférences Choix optimal Plan du cours Préambule : Rationalité du consommateur I II III IV V La contrainte budgétaire Les préférences Le choix optimal

Plus en détail

TSTI 2D CH X : Exemples de lois à densité 1

TSTI 2D CH X : Exemples de lois à densité 1 TSTI 2D CH X : Exemples de lois à densité I Loi uniforme sur ab ; ) Introduction Dans cette activité, on s intéresse à la modélisation du tirage au hasard d un nombre réel de l intervalle [0 ;], chacun

Plus en détail

LA PHYSIQUE DES MATERIAUX. Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE

LA PHYSIQUE DES MATERIAUX. Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE LA PHYSIQUE DES MATERIAUX Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE Pr. A. Belayachi Université Mohammed V Agdal Faculté des Sciences Rabat Département de Physique - L.P.M [email protected] 1 1.Le réseau

Plus en détail

Chapitre VI - Méthodes de factorisation

Chapitre VI - Méthodes de factorisation Université Pierre et Marie Curie Cours de cryptographie MM067-2012/13 Alain Kraus Chapitre VI - Méthodes de factorisation Le problème de la factorisation des grands entiers est a priori très difficile.

Plus en détail

I Stabilité, Commandabilité et Observabilité 11. 1 Introduction 13 1.1 Un exemple emprunté à la robotique... 13 1.2 Le plan... 18 1.3 Problème...

I Stabilité, Commandabilité et Observabilité 11. 1 Introduction 13 1.1 Un exemple emprunté à la robotique... 13 1.2 Le plan... 18 1.3 Problème... TABLE DES MATIÈRES 5 Table des matières I Stabilité, Commandabilité et Observabilité 11 1 Introduction 13 1.1 Un exemple emprunté à la robotique................... 13 1.2 Le plan...................................

Plus en détail

LES TYPES DE DONNÉES DU LANGAGE PASCAL

LES TYPES DE DONNÉES DU LANGAGE PASCAL LES TYPES DE DONNÉES DU LANGAGE PASCAL 75 LES TYPES DE DONNÉES DU LANGAGE PASCAL CHAPITRE 4 OBJECTIFS PRÉSENTER LES NOTIONS D ÉTIQUETTE, DE CONS- TANTE ET DE IABLE DANS LE CONTEXTE DU LAN- GAGE PASCAL.

Plus en détail

chapitre 4 Nombres de Catalan

chapitre 4 Nombres de Catalan chapitre 4 Nombres de Catalan I Dénitions Dénition 1 La suite de Catalan (C n ) n est la suite dénie par C 0 = 1 et, pour tout n N, C n+1 = C k C n k. Exemple 2 On trouve rapidement C 0 = 1, C 1 = 1, C

Plus en détail

Raisonnement par récurrence Suites numériques

Raisonnement par récurrence Suites numériques Chapitre 1 Raisonnement par récurrence Suites numériques Terminale S Ce que dit le programme : CONTENUS CAPACITÉS ATTENDUES COMMENTAIRES Raisonnement par récurrence. Limite finie ou infinie d une suite.

Plus en détail

INF601 : Algorithme et Structure de données

INF601 : Algorithme et Structure de données Cours 2 : TDA Arbre Binaire B. Jacob IC2/LIUM 27 février 2010 Plan 1 Introuction 2 Primitives u TDA Arbin 3 Réalisations u TDA Arbin par cellules chaînées par cellules contiguës par curseurs (faux pointeurs)

Plus en détail

Métriques de performance pour les algorithmes et programmes parallèles

Métriques de performance pour les algorithmes et programmes parallèles Métriques de performance pour les algorithmes et programmes parallèles 11 18 nov. 2002 Cette section est basée tout d abord sur la référence suivante (manuel suggéré mais non obligatoire) : R. Miller and

Plus en détail

La NP-complétude. Johanne Cohen. PRISM/CNRS, Versailles, France.

La NP-complétude. Johanne Cohen. PRISM/CNRS, Versailles, France. La NP-complétude Johanne Cohen PRISM/CNRS, Versailles, France. Références 1. Algorithm Design, Jon Kleinberg, Eva Tardos, Addison-Wesley, 2006. 2. Computers and Intractability : A Guide to the Theory of

Plus en détail

Développement décimal d un réel

Développement décimal d un réel 4 Développement décimal d un réel On rappelle que le corps R des nombres réels est archimédien, ce qui permet d y définir la fonction partie entière. En utilisant cette partie entière on verra dans ce

Plus en détail

Cours d Analyse. Fonctions de plusieurs variables

Cours d Analyse. Fonctions de plusieurs variables Cours d Analyse Fonctions de plusieurs variables Licence 1ère année 2007/2008 Nicolas Prioux Université de Marne-la-Vallée Table des matières 1 Notions de géométrie dans l espace et fonctions à deux variables........

Plus en détail

Complément d information concernant la fiche de concordance

Complément d information concernant la fiche de concordance Sommaire SAMEDI 0 DÉCEMBRE 20 Vous trouverez dans ce dossier les documents correspondants à ce que nous allons travailler aujourd hui : La fiche de concordance pour le DAEU ; Page 2 Un rappel de cours

Plus en détail

Baccalauréat ES/L Métropole La Réunion 13 septembre 2013 Corrigé

Baccalauréat ES/L Métropole La Réunion 13 septembre 2013 Corrigé Baccalauréat S/L Métropole La Réunion 13 septembre 2013 Corrigé A. P. M.. P. XRCIC 1 Commun à tous les candidats Partie A 1. L arbre de probabilité correspondant aux données du problème est : 0,3 0,6 H

Plus en détail

F411 - Courbes Paramétrées, Polaires

F411 - Courbes Paramétrées, Polaires 1/43 Courbes Paramétrées Courbes polaires Longueur d un arc, Courbure F411 - Courbes Paramétrées, Polaires Michel Fournié [email protected] http://www.math.univ-toulouse.fr/ fournie/ Année 2012/2013

Plus en détail

Grandes lignes ASTRÉE. Logiciels critiques. Outils de certification classiques. Inspection manuelle. Definition. Test

Grandes lignes ASTRÉE. Logiciels critiques. Outils de certification classiques. Inspection manuelle. Definition. Test Grandes lignes Analyseur Statique de logiciels Temps RÉel Embarqués École Polytechnique École Normale Supérieure Mercredi 18 juillet 2005 1 Présentation d 2 Cadre théorique de l interprétation abstraite

Plus en détail

Les algorithmes de base du graphisme

Les algorithmes de base du graphisme Les algorithmes de base du graphisme Table des matières 1 Traçage 2 1.1 Segments de droites......................... 2 1.1.1 Algorithmes simples.................... 3 1.1.2 Algorithmes de Bresenham (1965).............

Plus en détail

Nouvelles propositions pour la résolution exacte du sac à dos multi-objectif unidimensionnel en variables binaires

Nouvelles propositions pour la résolution exacte du sac à dos multi-objectif unidimensionnel en variables binaires Nouvelles propositions pour la résolution exacte du sac à dos multi-objectif unidimensionnel en variables binaires Julien Jorge [email protected] Laboratoire d Informatique de Nantes Atlantique,

Plus en détail

Calcul différentiel sur R n Première partie

Calcul différentiel sur R n Première partie Calcul différentiel sur R n Première partie Université De Metz 2006-2007 1 Définitions générales On note L(R n, R m ) l espace vectoriel des applications linéaires de R n dans R m. Définition 1.1 (différentiabilité

Plus en détail

Fonctions de plusieurs variables

Fonctions de plusieurs variables Module : Analyse 03 Chapitre 00 : Fonctions de plusieurs variables Généralités et Rappels des notions topologiques dans : Qu est- ce que?: Mathématiquement, n étant un entier non nul, on définit comme

Plus en détail

La classification automatique de données quantitatives

La classification automatique de données quantitatives La classification automatique de données quantitatives 1 Introduction Parmi les méthodes de statistique exploratoire multidimensionnelle, dont l objectif est d extraire d une masse de données des informations

Plus en détail

Comparaison de fonctions Développements limités. Chapitre 10

Comparaison de fonctions Développements limités. Chapitre 10 PCSI - 4/5 www.ericreynaud.fr Chapitre Points importants 3 Questions de cours 6 Eercices corrigés Plan du cours 4 Eercices types 7 Devoir maison 5 Eercices Chap Et s il ne fallait retenir que si points?

Plus en détail

I. Ensemble de définition d'une fonction

I. Ensemble de définition d'une fonction Chapitre 2 Généralités sur les fonctions Fonctions de références et fonctions associées Ce que dit le programme : Étude de fonctions Fonctions de référence x x et x x Connaître les variations de ces deux

Plus en détail

Suites numériques 3. 1 Convergence et limite d une suite

Suites numériques 3. 1 Convergence et limite d une suite Suites numériques 3 1 Convergence et limite d une suite Nous savons que les termes de certaines suites s approchent de plus en plus d une certaine valeur quand n augmente : par exemple, les nombres u n

Plus en détail

Probabilités sur un univers fini

Probabilités sur un univers fini [http://mp.cpgedupuydelome.fr] édité le 10 août 2015 Enoncés 1 Proailités sur un univers fini Evènements et langage ensemliste A quelle condition sur (a,, c, d) ]0, 1[ 4 existe-t-il une proailité P sur

Plus en détail

Programmation linéaire et Optimisation. Didier Smets

Programmation linéaire et Optimisation. Didier Smets Programmation linéaire et Optimisation Didier Smets Chapitre 1 Un problème d optimisation linéaire en dimension 2 On considère le cas d un fabricant d automobiles qui propose deux modèles à la vente, des

Plus en détail

MIS 102 Initiation à l Informatique

MIS 102 Initiation à l Informatique MIS 102 Initiation à l Informatique Responsables et cours : Cyril Gavoille Catherine Pannier Matthias Robine Marc Zeitoun Planning : 6 séances de cours 5 séances de TD (2h40) 4 séances de TP (2h40) + environ

Plus en détail

Théorie et Codage de l Information (IF01) exercices 2013-2014. Paul Honeine Université de technologie de Troyes France

Théorie et Codage de l Information (IF01) exercices 2013-2014. Paul Honeine Université de technologie de Troyes France Théorie et Codage de l Information (IF01) exercices 2013-2014 Paul Honeine Université de technologie de Troyes France TD-1 Rappels de calculs de probabilités Exercice 1. On dispose d un jeu de 52 cartes

Plus en détail

TP 2 Réseaux. Adresses IP, routage et sous-réseaux

TP 2 Réseaux. Adresses IP, routage et sous-réseaux TP 2 Réseaux Adresses IP, routage et sous-réseaux C. Pain-Barre INFO - IUT Aix-en-Provence version du 24/2/2 Adressage IP. Limites du nombre d adresses IP.. Adresses de réseaux valides Les adresses IP

Plus en détail

Précision d un résultat et calculs d incertitudes

Précision d un résultat et calculs d incertitudes Précision d un résultat et calculs d incertitudes PSI* 2012-2013 Lycée Chaptal 3 Table des matières Table des matières 1. Présentation d un résultat numérique................................ 4 1.1 Notations.........................................................

Plus en détail

Algorithmes d'apprentissage

Algorithmes d'apprentissage Algorithmes d'apprentissage 1 Agents qui apprennent à partir d'exemples La problématique : prise de décision automatisée à partir d'un ensemble d'exemples Diagnostic médical Réponse à une demande de prêt

Plus en détail

LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN

LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN Les contenues de ce document sont la propriété exclusive de la société REVER. Ils ne sont transmis qu à titre d information et ne peuvent en aucun cas

Plus en détail

INTRODUCTION A L ELECTRONIQUE NUMERIQUE ECHANTILLONNAGE ET QUANTIFICATION I. ARCHITECTURE DE L ELECRONIQUE NUMERIQUE

INTRODUCTION A L ELECTRONIQUE NUMERIQUE ECHANTILLONNAGE ET QUANTIFICATION I. ARCHITECTURE DE L ELECRONIQUE NUMERIQUE INTRODUCTION A L ELECTRONIQUE NUMERIQUE ECHANTILLONNAGE ET QUANTIFICATION I. ARCHITECTURE DE L ELECRONIQUE NUMERIQUE Le schéma synoptique ci-dessous décrit les différentes étapes du traitement numérique

Plus en détail

Table des matières. I Mise à niveau 11. Préface

Table des matières. I Mise à niveau 11. Préface Table des matières Préface v I Mise à niveau 11 1 Bases du calcul commercial 13 1.1 Alphabet grec...................................... 13 1.2 Symboles mathématiques............................... 14 1.3

Plus en détail

Fibonacci et les paquerettes

Fibonacci et les paquerettes Fibonacci et les paquerettes JOLY Romain & RIVOAL Tanguy Introduction Quand on entend dire que l on peut trouver le nombre d or et la suite de Fibonacci dans les fleurs et les pommes de pin, on est au

Plus en détail

CCP PSI - 2010 Mathématiques 1 : un corrigé

CCP PSI - 2010 Mathématiques 1 : un corrigé CCP PSI - 00 Mathématiques : un corrigé Première partie. Définition d une structure euclidienne sur R n [X]... B est clairement symétrique et linéaire par rapport à sa seconde variable. De plus B(P, P

Plus en détail

Problèmes de Mathématiques Filtres et ultrafiltres

Problèmes de Mathématiques Filtres et ultrafiltres Énoncé Soit E un ensemble non vide. On dit qu un sous-ensemble F de P(E) est un filtre sur E si (P 0 ) F. (P 1 ) (X, Y ) F 2, X Y F. (P 2 ) X F, Y P(E) : X Y Y F. (P 3 ) / F. Première Partie 1. Que dire

Plus en détail

Architecture des Systèmes d Information Architecture des Systèmes d Information

Architecture des Systèmes d Information Architecture des Systèmes d Information Plan... Tableaux et tris I3 - Algorithmique et programmation 1 Rappels Nicol Delestre 2 Tableaux à n dimensions 3 Initiation aux tris Tableaux - v2.0.1 1 / 27 Tableaux - v2.0.1 2 / 27 Rappels : tableau

Plus en détail

Soit la fonction affine qui, pour représentant le nombre de mois écoulés, renvoie la somme économisée.

Soit la fonction affine qui, pour représentant le nombre de mois écoulés, renvoie la somme économisée. ANALYSE 5 points Exercice 1 : Léonie souhaite acheter un lecteur MP3. Le prix affiché (49 ) dépasse largement la somme dont elle dispose. Elle décide donc d économiser régulièrement. Elle a relevé qu elle

Plus en détail

Baccalauréat ES/L Amérique du Sud 21 novembre 2013

Baccalauréat ES/L Amérique du Sud 21 novembre 2013 Baccalauréat ES/L Amérique du Sud 21 novembre 2013 A. P. M. E. P. EXERCICE 1 Commun à tous les candidats 5 points Une entreprise informatique produit et vend des clés USB. La vente de ces clés est réalisée

Plus en détail

CHOIX OPTIMAL DU CONSOMMATEUR. A - Propriétés et détermination du choix optimal

CHOIX OPTIMAL DU CONSOMMATEUR. A - Propriétés et détermination du choix optimal III CHOIX OPTIMAL DU CONSOMMATEUR A - Propriétés et détermination du choix optimal La demande du consommateur sur la droite de budget Résolution graphique Règle (d or) pour déterminer la demande quand

Plus en détail

Ordonnancement. N: nains de jardin. X: peinture extérieure. E: électricité T: toit. M: murs. F: fondations CHAPTER 1

Ordonnancement. N: nains de jardin. X: peinture extérieure. E: électricité T: toit. M: murs. F: fondations CHAPTER 1 CHAPTER 1 Ordonnancement 1.1. Étude de cas Ordonnancement de tâches avec contraintes de précédences 1.1.1. Exemple : construction d'une maison. Exercice. On veut construire une maison, ce qui consiste

Plus en détail

III- Raisonnement par récurrence

III- Raisonnement par récurrence III- Raisonnement par récurrence Les raisonnements en mathématiques se font en général par une suite de déductions, du style : si alors, ou mieux encore si c est possible, par une suite d équivalences,

Plus en détail

Algorithmique, Structures de données et langage C

Algorithmique, Structures de données et langage C UNIVERSITE PAUL SABATIER TOULOUSE III Algorithmique, Structures de données et langage C L3 IUP AISEM/ICM Janvier 2005 J.M. ENJALBERT Chapitre 1 Rappels et compléments de C 1.1 Structures Une structure

Plus en détail

Calcul fonctionnel holomorphe dans les algèbres de Banach

Calcul fonctionnel holomorphe dans les algèbres de Banach Chapitre 7 Calcul fonctionnel holomorphe dans les algèbres de Banach L objet de ce chapitre est de définir un calcul fonctionnel holomorphe qui prolonge le calcul fonctionnel polynômial et qui respecte

Plus en détail

Arbres binaires de recherche

Arbres binaires de recherche 1 arbre des comparaisons 2 recherche dichotomique l'arbre est recalculé à chaque recherche 2 5 3 4 7 9 1 6 1 2 3 4 5 6 7 9 10 conserver la structure d'arbre au lieu de la reconstruire arbre binaire de

Plus en détail

Arbres binaires de décision

Arbres binaires de décision 1 Arbres binaires de décision Résumé Arbres binaires de décision Méthodes de construction d arbres binaires de décision, modélisant une discrimination (classification trees) ou une régression (regression

Plus en détail

LES GENERATEURS DE NOMBRES ALEATOIRES

LES GENERATEURS DE NOMBRES ALEATOIRES LES GENERATEURS DE NOMBRES ALEATOIRES 1 Ce travail a deux objectifs : ====================================================================== 1. Comprendre ce que font les générateurs de nombres aléatoires

Plus en détail

Résolution de systèmes linéaires par des méthodes directes

Résolution de systèmes linéaires par des méthodes directes Résolution de systèmes linéaires par des méthodes directes J. Erhel Janvier 2014 1 Inverse d une matrice carrée et systèmes linéaires Ce paragraphe a pour objet les matrices carrées et les systèmes linéaires.

Plus en détail