Arbre B
En informatique, un arbre B (appelĂ© aussi B-arbre par analogie au terme anglais « B-tree ») est une structure de donnĂ©es en arbre Ă©quilibrĂ©. Les arbres B sont principalement mis en Ćuvre dans les mĂ©canismes de gestion de bases de donnĂ©es et de systĂšmes de fichiers. Ils stockent les donnĂ©es sous une forme triĂ©e et permettent une exĂ©cution des opĂ©rations d'insertion et de suppression en temps toujours logarithmique.
DĂ©couvreurs ou inventeurs | |
---|---|
Date de découverte | |
ProblÚme lié | |
Structure des données |
Pire cas |
, , |
---|---|
Moyenne |
, , |
Pire cas | |
---|---|
Moyenne |
Le principe est de permettre aux nĆuds parents de possĂ©der plus de deux nĆuds enfants : c'est une gĂ©nĂ©ralisation de lâarbre binaire de recherche. Ce principe minimise la taille de l'arbre et rĂ©duit le nombre d'opĂ©rations d'Ă©quilibrage. De plus un arbre B grandit Ă partir de la racine, contrairement Ă un arbre binaire de recherche qui croĂźt Ă partir des feuilles.
Le créateur des arbres B, Rudolf Bayer, n'a pas explicité la signification du « B ». L'explication la plus fréquente est que le B correspond au terme anglais « balanced » (en français : « équilibré »). Cependant, il pourrait aussi découler de « Bayer », du nom du créateur, ou de « Boeing », du nom de la firme pour laquelle le créateur travaillait (Boeing Scientific Research Labs).
Origine
Les arbres B ont Ă©tĂ© inventĂ©s en 1970 par Rudolf Bayer et Edward M.McCreight dans les laboratoires de recherche de Boeing. Le but Ă©tait de pouvoir gĂ©rer les pages d'index de fichiers de donnĂ©es, en tenant compte du fait que le volume des index pouvait ĂȘtre si grand que seule une fraction des pages pouvait ĂȘtre chargĂ©e en mĂ©moire vive. Le premier article[2] dĂ©crivant le mĂ©canisme des arbres B a Ă©tĂ© Ă©crit en juillet et publiĂ© en .
Structure
Structure générale
Un arbre Ă©tiquetĂ© est un arbre (au sens informatique du terme) tel qu'Ă chaque nĆud on associe une Ă©tiquette ou clĂ© (ou bien plusieurs Ă©tiquettes ou clĂ©s dans le cas des arbres B) prise(s) dans un ensemble donnĂ©. Donc formellement un arbre Ă©tiquetĂ© est un couple formĂ© d'un graphe orientĂ©, acyclique et connexe et d'une fonction d'Ă©tiquetage des arbres qui attribue Ă chaque nĆud une Ă©tiquette ou une clĂ©. Parmi les arbres Ă©tiquetĂ©s, un arbre B possĂšde quelques propriĂ©tĂ©s spĂ©cifiques supplĂ©mentaires.
Soient L et U deux entiers naturels non nuls tels que L †U. En toute gĂ©nĂ©ralitĂ©, on dĂ©finit alors un L-U arbre B[3] de la maniĂšre suivante : chaque nĆud, sauf la racine, possĂšde un minimum de Lâ1 clĂ©s (appelĂ©es aussi Ă©lĂ©ments), un maximum de Uâ1 clĂ©s et au plus U fils[4]. Pour chaque nĆud interne â nĆud qui nâest pas une feuille â, le nombre de fils est toujours Ă©gal au nombre de clĂ©s augmentĂ© dâune unitĂ©. Si n est le nombre de fils, alors on parle de n-nĆud. Un L-U arbre ne contient que des n-nĆuds avec L †n †U. Souvent on choisit la configuration L = t et U = 2 Ă t : t est appelĂ© le degrĂ© minimal de lâarbre B.
De plus, la construction des arbres B garantit quâun arbre B est toujours Ă©quilibrĂ©. Chaque clĂ© dâun nĆud interne est en fait une borne qui distingue les sous-arbres de ce nĆud. Par exemple, si un nĆud a 3 fils â lesquels constituent les racines respectives de trois sous-arbres : sous-arbre gauche, sous-arbre du milieu et sous-arbre droit â, alors il a 2 clĂ©s notĂ©es c1 et c2 qui dĂ©limitent les clĂ©s de chaque sous-arbre : les clĂ©s du sous-arbre gauche seront infĂ©rieures Ă c1 ; les clĂ©s du sous-arbre du milieu seront comprises entre c1 et c2 ; les clĂ©s du sous-arbre droit seront supĂ©rieures Ă c2.
Implémentation
Un arbre B est implĂ©mentĂ© par un arbre enracinĂ©[5]. Un nĆud est Ă©tiquetĂ© par :
- Un entier qui correspond au nombre de clefs contenues dans le nĆud .
- clefs notées .
- Un booléen indiquant si est une feuille ou non.
- pointeurs notés associés aux fils de . Une feuille ne contient pas de pointeurs.
De plus, un arbre B vérifie ces propriétés :
- Toutes les feuilles ont la mĂȘme profondeur, Ă savoir la hauteur de lâarbre.
- Si nâest pas une feuille :
- Pour , pour toute clef du fils : .
- pour toute clef du fils : .
- pour toute clef du fils : .
- Si nâest ni une feuille, ni la racine, est compris entre L-1 et U-1.
Exemple de nĆud en C++
template<typename T, size_t U>
struct Noeud {
size_t n; // nombre de clés utilisées
bool feuille; // si ce nĆud est une feuille
Noeud<T, U>* parent = nullptr; // connaĂźtre le parent peut ĂȘtre nĂ©cessaire dans certains algorithmes
T cles[U-1]; // tableau des clés
Noeud<T, U>* branches[U]; // tableau des branches, si ce n'est pas une feuille
};
En pratique
La plupart du temps, la configuration est telle que U = 2 L. On parle alors dâarbre B d'ordre L.
Un arbre B dâordre t est alors dĂ©fini plus simplement par un arbre qui satisfait les propriĂ©tĂ©s suivantes :
- Chaque nĆud a au plus clĂ©s.
- Chaque nĆud qui nâest ni racine ni feuille possĂšde au moins clĂ©s.
- Si l'arbre est non vide, la racine est aussi non vide.
- Un nĆud qui possĂšde k fils contient k â 1 clefs.
- Toutes les feuilles se situent Ă la mĂȘme hauteur.
Opérations
Comme on le verra par la suite, la hauteur d'un B-arbre est logarithmique en le nombre d'Ă©lĂ©ments. Ainsi, les opĂ©rations de recherche, insertion et suppression sont implĂ©mentables en O(log n) dans le pire cas, oĂč n est le nombre d'Ă©lĂ©ments.
Recherche
La recherche est effectuĂ©e de la mĂȘme maniĂšre que dans un arbre binaire de recherche. Partant de la racine, on parcourt rĂ©cursivement lâarbre ; Ă chaque nĆud, on choisit le sous-arbre fils dont les clĂ©s sont comprises entre les mĂȘmes bornes que celles de la clĂ© recherchĂ©e grĂące Ă une recherche dichotomique.
Pseudo-code
fonction Rechercher(noeud, x):
i = 0
tant que i < noeud.taille et x > noeud.cles[i]:
i += 1
si noeud.feuille:
retourner i < noeud.taille et x == noeud.cles[i]
sinon:
si i < noeud.taille et x == noeud.cles[i]:
retourner Vrai
sinon:
retourner Rechercher(noeud.branches[i], x)
Dans de nombreuses implĂ©mentations, l'Ă©galitĂ© () entre Ă©lĂ©ments est remplacĂ©e par l'Ă©quivalence (). Il faut donc veiller Ă utiliser des types de donnĂ©es oĂč deux Ă©lĂ©ments Ă©quivalents sont considĂ©rĂ©s comme Ă©gaux.
Insertion
Lâinsertion nĂ©cessite tout dâabord de chercher le nĆud oĂč la nouvelle clĂ© devrait ĂȘtre insĂ©rĂ©e, et lâinsĂ©rer. La suite se dĂ©roule rĂ©cursivement, selon quâun nĆud ait ou non trop de clĂ©s : sâil possĂšde un nombre acceptable de clĂ©s, on ne fait rien ; autrement on le transforme en deux nĆuds, chacun possĂ©dant un nombre minimum de clĂ©s, puis on fait « remonter » la clĂ© du milieu qui est alors insĂ©rĂ©e dans le nĆud pĂšre. Ce dernier peut du coup se retrouver avec un nombre excessif de fils ; le procĂ©dĂ© se poursuit ainsi jusquâĂ ce que lâon atteigne la racine. Si celle-ci doit ĂȘtre divisĂ©e, on fait « remonter » la clĂ© du milieu dans une nouvelle racine, laquelle gĂ©nĂšrera comme nĆuds fils les deux nĆuds crĂ©Ă©s Ă partir de lâancienne racine, Ă lâinstar de l'Ă©tape prĂ©cĂ©dente. Pour que lâopĂ©ration soit possible, on remarque quâil faut que U â„ 2 L ; sinon les nouveaux nĆuds ne possĂšderont pas suffisamment de clĂ©s.
Une variante consiste Ă Ă©clater prĂ©ventivement chaque nĆud « plein » (possĂ©dant le nombre maximal de clĂ©s) rencontrĂ© lors de la recherche du nĆud oĂč se rĂ©alisera l'insertion. De cette maniĂšre on Ă©vite une remontĂ©e dans l'arbre, puisque l'on assure que le pĂšre d'un nĆud Ă scinder en deux peut accueillir une clĂ© supplĂ©mentaire. La contrepartie en est une lĂ©gĂšre augmentation de la hauteur moyenne de l'arbre.
Pseudo-code
fonction Inserer(x,c)
n = nombre de clefs du noeud x
Soit i tel que x.clef[i] > c ou i >= n
Si x est une feuille :
Inserer c dans x.clef a la i-ieme place
Sinon:
Si x.fils[i] est complet:
Scinder x.fils[i]
Si c > x.clef[i]:
i := i+1
FinSi
FinSi
Inserer(x.fils[i],c)
FinSi
FinFonction
Suppression
On doit dâabord chercher la clĂ© Ă supprimer et la supprimer du nĆud qui la contient.
- Si le nĆud est interne, on procĂšde de maniĂšre similaire aux arbres binaires de recherche en recherchant la clĂ© k la plus Ă gauche dans le sous-arbre droit de la clĂ© Ă supprimer ou la plus Ă droite dans le sous-arbre gauche. Cette clĂ© k appartient Ă une feuille. On peut la permuter avec la clĂ© Ă supprimer, que lâon supprime ensuite. Comme elle appartient Ă une feuille, on se ramĂšne au cas suivant.
- Si le nĆud est une feuille, soit il possĂšde encore suffisamment de clĂ©s et lâalgorithme termine, soit il dispose de moins de Lâ1 clĂ©s et on se trouve dans lâune des deux situations suivantes :
- soit un de ses frĂšres Ă droite ou Ă gauche possĂšde suffisamment de clĂ©s pour pouvoir en « passer » une Ă la feuille en question : dans ce cas cette clĂ© remplace la clĂ© qui sĂ©pare les deux sous-arbres dans lâarbre pĂšre, qui va elle-mĂȘme dans la feuille en question ;
- soit aucun de ses frĂšres nâa suffisamment de clĂ©s : dans ce cas, le pĂšre fait passer une de ses clĂ©s dans un des deux (ou le seul) frĂšres pour permettre Ă la feuille de fusionner avec celui-ci. Ceci peut cependant conduire le pĂšre Ă ne plus avoir suffisamment de clĂ©s. On rĂ©itĂšre alors lâalgorithme : si le nĆud a un frĂšre avec suffisamment de clĂ©s, la clĂ© la plus proche va ĂȘtre Ă©changĂ©e avec la clĂ© du pĂšre, puis la clĂ© du pĂšre et ses nouveaux descendants sont ramenĂ©s dans le nĆud qui a besoin dâune clĂ© ; sinon on effectue une fusion Ă lâaide dâune clĂ© du pĂšre et ainsi de suite. Si lâon arrive Ă la racine et quâelle possĂšde moins de L Ă©lĂ©ments, on fusionne ses deux fils pour donner une nouvelle racine.
Ăquilibrage
Notamment aprĂšs une suppression, l'arbre peut ĂȘtre rĂ©Ă©quilibrĂ©. Cette opĂ©ration consiste Ă rĂ©partir Ă©quitablement les valeurs dans les diffĂ©rents nĆuds de l'arbre et Ă rĂ©tablir les propriĂ©tĂ©s de remplissage minimum des nĆuds.
Le rĂ©Ă©quilibrage commence au niveau des feuilles et progresse vers la racine, jusqu'Ă celle-ci. La redistribution consiste Ă transfĂ©rer un Ă©lĂ©ment d'un nĆud voisin qui possĂšde suffisamment de valeurs vers le nĆud qui en manque. Cette redistribution est appelĂ©e rotation. Si aucun voisin ne peut fournir de valeur sans ĂȘtre lui mĂȘme sous la limite, le nĆud dĂ©ficient doit ĂȘtre fusionnĂ© avec un voisin. Cette opĂ©ration provoque la perte d'un sĂ©parateur dans le nĆud parent, celui-ci peut alors ĂȘtre en dĂ©ficit et a besoin d'ĂȘtre Ă©quilibrĂ©. La fusion et redistribution se propage jusqu'Ă la racine, seul Ă©lĂ©ment oĂč la dĂ©ficience en valeurs est tolĂ©rĂ©e.
Un algorithme d'Ă©quilibrage simple consiste Ă :
- Si le nĆud voisin gauche existe et dispose de suffisamment de valeurs pour pouvoir en offrir une, rĂ©aliser une rotation gauche.
- Sinon, si le nĆud voisin droite existe et dispose de suffisamment d'Ă©lĂ©ments, rĂ©aliser une rotation droite.
- Sinon, le nĆud dĂ©ficient doit ĂȘtre fusionnĂ© avec un de ses voisins tel que la somme du nombre de leurs clĂ©s plus 1 soit infĂ©rieure ou Ă©gale Ă la capacitĂ© maximale (). La valeur supplĂ©mentaire correspond au sĂ©parateur prĂ©sent dans le parent. Cette opĂ©ration est toujours possible si avec et ou le contraire, soit un nĆud immĂ©diatement sous la limite de clĂ©s et un nĆud exactement Ă la limite.
- copier le sĂ©parateur Ă la fin du nĆud de gauche
- ajouter tous les Ă©lĂ©ments du nĆud de droite Ă la fin du nĆud de gauche
- effacer le nĆud de droite et effacer le sĂ©parateur du parent puis vĂ©rifier qu'il contient assez d'Ă©lĂ©ments. Si ce n'est pas le cas, rĂ©Ă©quilibrer le parent avec ses voisins.
Rotation gauche
La rotation Ă gauche d'un cran entre deux nĆuds voisins se fait en
- dĂ©plaçant le sĂ©parateur, prĂ©sent dans le parent, Ă la fin du nĆud de gauche
- dĂ©plaçant le premier Ă©lĂ©ment du nĆud de droite en tant que sĂ©parateur dans le parent
Ce genre d'opĂ©ration peut ĂȘtre Ă©galement utilisĂ© pour compresser l'arbre: un arbre destinĂ© Ă la lecture seule peut ĂȘtre vidĂ© d'un maximum de cases mĂ©moires inutilisĂ©es en remplissant au maximum un minimum de nĆuds.
Hauteur dans le pire des cas
Soit le nombre de clefs que contient lâarbre B. La hauteur de lâarbre vĂ©rifie lâinĂ©galitĂ© :
Remarques
- Les arbres 2-3-4 sont les structures de donnĂ©es dâarbre B les plus utilisĂ©es : ils correspondent en fait Ă des 2-4 arbres B ou arbres B dâordre 2.
- Les B-arbres prĂ©sentent l'avantage d'ĂȘtre Ă©quilibrĂ©s (toutes les feuilles sont Ă la mĂȘme hauteur), ce qui permet d'obtenir une majoration de la hauteur et donc de meilleures complexitĂ©s (en O(log n)) pour les opĂ©rations de base (recherche, insertion, suppression) que pour un arbre classique (oĂč l'insertion est en O(h), avec h la hauteur de l'arbre, donc potentiellement en O(n) suivant l'implĂ©mentation choisie).
Variantes
Lâarbre Arbre B+ (en) diffĂšre lĂ©gĂšrement de lâarbre B, en ceci que toutes les donnĂ©es sont stockĂ©es exclusivement dans des feuilles, et celles-ci sont reliĂ©es entre elles.
Dâautres variantes existent Ă©galement, telles que lâarbre B* (en).
Annexes
- (en) Rudolf Bayer, Binary B-Trees for Virtual Memory, ACM-SIGFIDET Workshop 1971, San Diego, California, Session 5B, pp. 219-235.
- (en) Rudolf Bayer et McCreight, E. M. Organization and Maintenance of Large Ordered Indexes. Acta Informatica 1, 173-189, 1972.
Références
- R. Bayer et E. McCreight, « Organization and maintenance of large ordered indices », SIGFIDET '70: Proceedings of the 1970 ACM SIGFIDET (now SIGMOD) Workshop on Data Description, Access and Control, ACM,â , p. 107-141 (ISBN 978-1-4503-7941-0, DOI 10.1145/1734663.1734671)
- (en) R. Bayer et E. McCreight, « Organization and maintenance of large ordered indices », Proceedings of the 1970 ACM SIGFIDET (now SIGMOD) Workshop on Data Description, Access and Control - SIGFIDET '70, ACM Press,â , p. 107 (DOI 10.1145/1734663.1734671, lire en ligne, consultĂ© le )
- L-U arbre B doit se lire « L U arbre B », car L-U représente une expression composée, et non pas la soustraction de deux nombres.
- « Lâ1 » et « Uâ1 » figurent ici des expressions de soustraction.
- (en) Thomas H.Cormen, Introduction to algorithms, 1989, pp.485-504.
Voir aussi
Liens externes
- (en) cs.usfca.edu : animation permettant d'insérer et de supprimer visuellement des éléments dans un arbre B
- (it) (en) B-tree GUI : Spataro Fabrizio e Todaro Michelangelo â Emulatore Java BTree â BTree Java Emulator.
- (en) Slady.net : animation sous forme dâapplet Java permettant de construire visuellement des arbres B.