Arbre de segments
En informatique, un arbre segment (en anglais segment tree), est un arbre enracinĂ© pour stocker des intervalles ou des segments. Il permet des requĂȘtes afin de savoir quels segments contiennent un certain point. C'est, en principe, une structure statique ; c'est une structure qui ne peut plus ĂȘtre modifiĂ©e une fois qu'elle est crĂ©Ă©e. Une structure de donnĂ©es similaire est l'arbre intervalle.
Un arbre segment pour un ensemble I de n intervalles utilise un stockage de O(n log n) et peut ĂȘtre construit en un temps de O(n log n). Dans un arbre segment on peut rechercher tous les intervalles qui contiennent un certain point (la requĂȘte) en O(log n + k), oĂč k est le nombre d'intervalles ou segments extraits[1].
Les applications de l'arbre segment sont dans les domaines de la géométrie algorithmique et du systÚme d'information géographique.
L'arbre segment peut aussi ĂȘtre gĂ©nĂ©ralisĂ© Ă des espaces avec des plus grandes dimensions.
Description de la structure
Cette section décrit la structure d'un arbre segment à 1 dimension.
Soit S l'ensemble d'intervalles, ou segments. Soit p1, p2, ..., pm la liste des points d'extrémités d'intervalle distincts, trié de gauche à droite. On considÚre le partitionnement de la réelle ligne induite par ces points. Les régions de ce partitionnement sont nommés intervalles élémentaires. Ainsi, les intervalles élémentaires, sont de gauche à droite.
Comme cela, la liste des intervalles Ă©lĂ©mentaires consistent Ă des intervalles ouverts entre deux points d'extrĂ©mitĂ©s consĂ©cutifs pi et pi+1, alternĂ©s avec des intervalles fermĂ©s qui consistent en un seul point d'extrĂ©mitĂ©. Les points isolĂ©s sont traitĂ©s comme des intervalles car la rĂ©ponse Ă une requĂȘte n'est pas nĂ©cessairement la mĂȘme Ă l'intĂ©rieur d'un intervalle Ă©lĂ©mentaire et ses points d'extrĂ©mitĂ©s[2].
Ătant donnĂ© un ensemble I d'intervalles, ou segments, un arbre segment T pour I est structurĂ© comme ceci :
- T est un arbre binaire
- Ses feuilles correspondant aux intervalles élémentaires induits par les points d'extrémités dans I, d'une maniÚre ordonnée : la feuille la plus à gauche correspond à l'intervalle le plus à gauche, ainsi de suite. L'intervalle élémentaire correspondant à la feuille v est noté Int(v).
- Les nĆuds internes de T correspondent Ă des intervalles qui sont l'union d'intervalles Ă©lĂ©mentaires : l'intervalle Int(N) correspondant au nĆud N est l'union des intervalles correspondants aux feuilles de l'arbre qui dĂ©bute Ă la racine N. Cela implique que Int(N) est l'union des intervalles de ces deux fils (sous-arbres).
- Chaque nĆud ou feuille v de T stocke l'intervalle Int(v) ou dans certaines structures de donnĂ©es un ensemble d'intervalles. Ce sous-ensemble canonique de nĆuds v contient les intervalles [x, xâČ] de I de telle maniĂšre que [x, xâČ] contient Int(v) et ne contient pas Int(parent(v)). Cela Ă©tant, chaque nĆud dans T stocke les segments qui couvrent son intervalle, mais qui ne couvrent pas l'intervalle de son parent[3].
Exigences de stockage
Cette section analyse le coût du stockage d'un arbre segment à 1 dimension.
Un arbre segment T sur un ensemble I de n intervalles utilise un stockage de O(n log n).
- Preuve:
- Lemma: Tout intervalle [x, xâČ] de I est stockĂ© dans l'ensemble canonique pour, au maximum, deux nĆuds Ă la mĂȘme profondeur.
- Preuve: Soit v1, v2, v3 trois nĆuds Ă la mĂȘme profondeur, numĂ©rotĂ©s de gauche Ă droite ; et soit p(v) le nĆud pĂšre de n'importe quel nĆud v. Supposons que [x, xâČ] est stockĂ© Ă v1 and v3. Cela signifie que [x, xâČ] couvre en entier l'intervalle depuis le point d'extrĂ©mitĂ© gauche de Int(v1) jusqu'au point d'extrĂ©mitĂ© droite de Int(v3). Remarquons que tous les segments Ă un niveau particulier ne se chevauchent pas et ordonnĂ©s de gauche Ă droite : par construction, cela est vrai pour le niveau contenant les feuilles, et la propriĂ©tĂ© n'est pas perdue en allant au niveau au-dessus en combinant par pair les segments adjacents. Maintenant, soit parent(v2) = parent(v1), ou c'est celui Ă droite de ce dernier (les arĂȘtes dans ce graphe ne se croisent pas). Dans le premier cas, le point le plus Ă gauche de Int(parent(v2)) est le mĂȘme que le point le plus Ă gauche de Int(v1) ; dans le second cas, le point le plus Ă gauchede Int(parent(v2)) est Ă droite du point le plus Ă droite de Int(parent(v1)), et ainsi, aussi Ă droite du point le plus Ă droite de Int(v1). Dans les deux cas, Int(parent(v2)) dĂ©bute au niveau, ou Ă droite, du point le plus Ă gauche de Int(v1). Un raisonnement similaire montre que Int(parent(v2)) se termine au niveau, ou Ă gauche, du point le plus Ă droite de Int(v3). Int(parent(v2)) doit ainsi ĂȘtre contenu dans [x, xâČ] ; par consĂ©quent [x, xâČ] ne sera pas stockĂ© Ă v2.
- L'ensemble I a au plus 4n + 1 intervalles Ă©lĂ©mentaires. Car T est un arbre binaire Ă©quilibrĂ© avec au plus 4n + 1 feuilles, sa hauteur est O(logn). Ătant donnĂ© qu'un intervalle est au plus stockĂ© deux fois Ă une certaine profondeur de l'arbre, ainsi le stockage total est O(nlogn)[4].
Construction
Cette section décrit la construction d'un arbre segment à 1 dimension.
Un arbre segment Ă partir de l'ensemble de segments I, peut-ĂȘtre construit comme ceci. PremiĂšrement, les points d'extrĂ©mitĂ©s des intervalles dans I sont triĂ©s. les intervalles Ă©lĂ©mentaires sont obtenus Ă partir de cela. Ensuite, un arbre binaire Ă©quilibrĂ© est construit sur les intervalles Ă©lĂ©mentaires, et pour chaque sommet v l'intervalle Int(v) est dĂ©terminĂ©. Il reste Ă calculer le sous-ensemble canonique pour les nĆuds. Pour rĂ©ussir cela, les intervalles dans I sont insĂ©rĂ©s un par un dans l'arbre segment. Un intervalle X = [x, xâČ] peut ĂȘtre insĂ©rĂ© dans un sous-arbre enracinĂ© Ă t, en utilisant la procĂ©dure suivante[5] :
- Si Int(T) est contenu dans X alors stocker X Ă T, et finir.
- Else :
- Si X intersecte l'intervalle du fils gauche de T, alors insérer X dans ce fils, récursivement.
- Si X intersecte l'intervalle du fils droit de T, alors insérer X dans ce fils, récursivement.
L'opération de construction complÚte nécessite le temps O(nlogn), n étant le nombre de segments dans I.
- Preuve
- Trier les points d'extrémités prend O(nlogn). Construire un arbre binaire équilibré depuis les points d'extrémités nécessite un temps linéaire en n.
- L'insertion d'un intervalle X = [x, xâČ] dans l'arbre coĂ»te O(logn).
- Preuve:Visiter chaque nĆud prend un temps constant (en assumant que les sous-ensembles canoniques sont stockĂ©s dans une structure de donnĂ©es simple, comme une liste chaĂźnĂ©e). Quand on visite un nĆud v, soit on stocke X Ă v, ou Int(v) contient un point d'extrĂ©mitĂ© de X. Comme prouvĂ© au-dessus, un intervalle est au plus stockĂ© deux fois Ă chaque niveau de l'arbre. Il y a aussi au plus un nĆud Ă chaque niveau oĂč son intervalle correspondant contient x, et un nĆud oĂč son intervalle contient xâČ. Donc, au plus quatre nĆuds par niveau sont visitĂ©s. Ătant donnĂ© qu'il y a O(logn) niveaux, le coĂ»t total de l'insertion est O(logn)[1].
RequĂȘte
Cette section dĂ©crit l'opĂ©ration d'une requĂȘte dans un arbre segment Ă 1 dimension.
Une requĂȘte pour un arbre segment, reçoit une point qx (qui devrait ĂȘtre une des feuilles de l'arbre), et retrouve une liste de tous les segments stockĂ©s qui contiennent le point qx.
Formellement Ă©noncĂ© ; en fonction d'un nĆud (sous-arbre) v et une requĂȘte sur un point qx, la requĂȘte peut ĂȘtre faite en utilisant l'algorithme suivant :
- Signaler tous les intervalles dans I(v)
- Si v n'est pas une feuille :
- Si qx est dans Int(fils gauche de v) alors
- RĂ©aliser une requĂȘte dans le fils gauche de v.
- Si qx est dans Int(fils droit de v) alors
- RĂ©aliser une requĂȘte dans le fils droit de v.
- Si qx est dans Int(fils gauche de v) alors
Si un arbre segment contient n intervalles, ceux qui contiennent un point d'une requĂȘte peuvent ĂȘtre signalĂ©s en un temps O(logn + k), oĂč k est le nombre d'intervalles signalĂ©s.
- Proof:L'algorithme de requĂȘte visite un nĆud par niveau de l'arbre, donc O(logn) nĆuds au total. D'un autre cĂŽtĂ©, Ă un nĆud v, les segments dans I sont signalĂ©s en un temps O(1 + kv), oĂč kvest le nombre d'intervalles signalĂ©s au nĆud v. La somme de tous les kv pour tous les nĆuds v visitĂ©s, est k, le nombre de segments signalĂ©s[4].
Généralisation pour de plus grandes dimensions
L'arbre segment peut ĂȘtre gĂ©nĂ©ralisĂ© pour des espaces Ă plus grandes dimensions, dans la forme d'un arbre segment Ă plusieurs niveaux. Les versions Ă plus de dimensions, l'arbre segment stocke une collection d'axes-parallĂšles (hyper-)rectangles, et peut retrouver les rectangles qui contiennent le point d'une certaine requĂȘte. La structure utilise un espace de O(nlogdn) et rĂ©sout les requĂȘtes en O(logdn).
L'utilisation de cascade fractionnĂ©e diminue la borne du temps de requĂȘte par un facteur logarithmique. L'utilisation d'arbre intervalle au niveau le plus profond des structures associĂ©es diminue la borne infĂ©rieure du stockage par un facteur logarithmique[6].
Notes
Une requĂȘte qui demande tous les intervalles qui contiennent un certain point est souvent mentionnĂ© en anglais comme stabbing query[7].
L'arbre segment est moins efficace que l'arbre intervalle pour les requĂȘtes de distance dans 1 dimension, cela est dĂ» au stockage qui est davantage consĂ©quent : O(nlogn) contre O(n) pour l'arbre d'intervalle. L'importance de l'arbre segment est que les segments dans chaque nĆud, son sous-ensemble canonique peut ĂȘtre stockĂ© d'une maniĂšre arbitraire[7].
Pour n intervalles oĂč les points d'extrĂ©mitĂ©s sont dans une petite plage de nombres entiers (par exemple, dans la plage [1,...,O(n)]), une structure de donnĂ©e optimale existe avec un temps de prĂ©traitement linĂ©aire et un temps de requĂȘte de O(1+k) pour signaler tous les k intervalles qui contiennent le point d'une certaine requĂȘte.
Un autre avantage de l'arbre segment est qu'il peut ĂȘtre facilement adaptĂ© aux requĂȘtes de comptage ; qui est de signaler le nombre de segments qui contiennent un certain point, au lieu de signaler les segments eux-mĂȘmes. Ă la place de stocker les intervalles dans des sous-ensembles canoniques, on peut simplement stocker le nombre qu'ils sont. Ainsi un arbre linĂ©aire utilise un stockage linĂ©aire, et requiert un temps de requĂȘte de O(log n)[8].
Des versions avec de plus grandes dimensions pour l'arbre intervalle et pour les arbres de recherche prioritaies n'existent pas ; cela Ă©tant, il n'y a pas d'extension claire de ces structures qui rĂ©sout le problĂšme analogue dans des dimensions supĂ©rieurs. Mais les structures peuvent ĂȘtre utilisĂ©s comme structures associĂ©es des arbres segments[6].
Histoire
L'arbre segment a Ă©tĂ© inventĂ© par Jon Louis Bentley en 1977, dans "Solutions to Kleeâs rectangle problems"[7].
Références
- de Berg et al. 2000, p. 227
- de Berg et al. 2000, p. 224
- de Berg et al. 2000, p. 225â226
- de Berg et al. 2000, p. 226
- de Berg et al. 2000, p. 226â227
- de Berg et al. 2000, p. 230
- de Berg et al. 2000, p. 229
- de Berg et al. 2000, p. 229â230
Sources citées
- (en) Mark de Berg, Marc van Kreveld, Mark Overmars et Otfried Schwarzkopf, Computational Geometry: algorithms and applications, Springer-Verlag Berlin Heidelberg New York, (ISBN 3-540-65620-0, DOI 10.1007/978-3-540-77974-2), « More Geometric Data Structures »
- http://www.cs.nthu.edu.tw/~wkhon/ds/ds10/tutorial/tutorial6.pdf