Pourquoi est std::map mis en œuvre comme un rouge-noir arbre?
Pourquoi est std::map
mis en œuvre comme un rouge-noir arbre?
Il y a plusieurs équilibré arbres binaires (techniciennes se chargent) là-bas. Quelles ont été la conception de compromis dans le choix d'un rouge-noir arbre?
- Bien que toutes les implémentations que j'ai vu utiliser un RB-tree, note que c'est encore dépendant de l'implémentation.
- Il est dépendant de l'implémentation, alors pourquoi il en est ainsi que la mise en œuvre utilisation RB-arbres?
- J'aimerais vraiment savoir si tout STL réalisateur a pensé à l'aide d'une benne de la Liste.
- C++de map et set sont effectivement commandé la carte et de l'ensemble ordonné. Ils ne sont pas mis en œuvre à l'aide de fonctions de hachage. Chaque requête est prendre
O(logn)
et pasO(1)
, mais les valeurs sont toujours triés. À partir de C++11 (je crois), il y aunordered_map
etunordered_set
, qui sont mis en œuvre à l'aide de fonctions de hachage, et bien qu'ils ne sont pas triés, la plupart des requêtes et les opérations sont possibles dansO(1)
(moyennement) - c'est vrai, mais pas que c'est intéressant dans la pratique. Le standard de fait de la complexité des garanties avec un algorithme spécifique ou un ensemble d'algorithmes dans l'esprit.
- Il existe plusieurs autres types de auto-équilibrage des arbres avec le même big-O complexité rouge-noir arbre, comme le B-arbre et arbre AVL.
Vous devez vous connecter pour publier un commentaire.
Probablement les deux plus commun d'auto équilibrage de l'arbre algorithmes sont Arbres rouge-Noir et AVL arbres. À l'équilibre de l'arbre, après une insertion/mise à jour deux algorithmes utilisent la notion de rotations où les nœuds de l'arbre sont en rotation pour effectuer le ré-équilibrage.
Alors que dans les deux algorithmes d'insérer ou de supprimer des opérations sont en O(log n), dans le cas de la Rouge-Noir arbre de ré-équilibrage de la rotation est un O(1) opération alors qu'avec AVL c'est un O(log n) opération, ce qui rend le Rouge-Noir arbre plus efficace dans cet aspect de la ré-équilibrage de la scène et l'une des raisons pour lesquelles il est plus couramment utilisé.
Arbres rouge-Noir sont utilisés dans la plupart de la collection de bibliothèques, y compris les offres de Java et Microsoft .NET Framework.
std::map
implémentations, traquer les développeurs, et demandez-leur quels critères qu'ils ont utilisés pour prendre la décision, de sorte que cela reste de la spéculation.Ça dépend vraiment de l'utilisation. AVL arbre a généralement plus de rotations de rééquilibrage. Donc, si votre application n'a pas trop d'insertion et de suppression d'opérations, mais le poids lourdement sur la recherche, puis l'arbre AVL est probablement un bon choix.
std::map
utilise le Rouge-Noir arbre qu'il obtient un compromis raisonnable entre la vitesse de nœud d'insertion, la suppression et la recherche.AVL arbres ont une hauteur maximale de 1,44 logn, tandis que RB arbres ont un maximum de 2logn. L'insertion d'un élément dans un AVL peut impliquer un rééquilibrage à un point de l'arbre. Le rééquilibrage des finitions de l'insertion. Après l'insertion d'une nouvelle feuille, la mise à jour les ancêtres de cette feuille doit être fait jusqu'à la racine, ou jusqu'à un point où les deux sous-arbres sont de la même profondeur. La probabilité d'avoir à mettre à jour k nœuds est de 1/3^k. Le rééquilibrage est O(1). Suppression d'un élément peut impliquer plus d'un rééquilibrage (jusqu'à la moitié de la profondeur de l'arbre).
RB-arbres sont des B-arbres de l'ordre de 4 représentés comme des arbres binaires. 4-nœud dans le B-arbre à deux niveaux dans l'équivalent du BST. Dans le pire des cas, tous les nœuds de l'arbre sont de 2 nœuds, avec une seule chaîne de 3-nœuds vers une feuille. Cette feuille sera à une distance de 2logn à partir de la racine.
Va vers le bas à partir de la racine du point d'insertion, on doit changer à 4 nœuds en 2-nœuds, pour s'assurer que l'insertion ne sera pas de saturer une feuille. En revenant de l'insertion, tous ces nœuds doivent être analysés pour s'assurer qu'ils représentent correctement à 4 nœuds. Cela peut aussi être fait en descendant dans l'arbre. Le coût global sera le même. Il n'y a pas de repas gratuit! Suppression d'un élément de l'arbre est du même ordre.
Tous ces arbres ont besoin que les nœuds portent des informations sur la taille, le poids, la couleur, etc. Seulement Écarter les arbres sont gratuits à partir de ces informations supplémentaires. Mais la plupart des gens ont peur de s'écartent des arbres, à cause de la ramdomness de leur structure!
Enfin, les arbres peuvent aussi transporter des informations de poids dans les nœuds, permettant des poids d'équilibrage. Différents systèmes peuvent être appliquées. On devrait rééquilibrer lorsqu'un sous-arbre contient plus de 3 fois le nombre d'éléments de l'autre sous-arbre. Le rééquilibrage est à nouveau fait soit devant un simple ou double rotation. Cela signifie un pire cas de 2,4 logn. On peut s'en tirer avec 2 fois au lieu de 3, un bien meilleur ratio, mais cela peut signifier qu'il reste un peu moins que 1% de la sous-arbres déséquilibrés ici et là. Délicat!
Quel type d'arbre est le meilleur? AVL pour vous. Ils sont les plus simples à code, et ont leurs pires hauteur la plus proche de logn. Pour un arbre de 1000000 éléments, un AVL sera au plus de hauteur de 29, un RB 40, et un poids équilibré 36 ou 50 selon le rapport.
Il y a beaucoup d'autres variables: l'aléatoire, le ratio des ajouts, des suppressions, des recherches, etc.
Les réponses précédentes seulement l'adresse de l'arbre des solutions de rechange rouge et noir probablement ne reste que pour des raisons historiques.
Pourquoi pas une table de hachage?
Un type exige seulement partielle de la commande (
<
comparaison) pour être utilisé comme une clé dans un arbre. Cependant, les tables de hachage, il faut que chaque type de clé a unhash
fonction définie. Le maintien de ces exigences de type à un minimum est très important pour la programmation générique.La conception d'une bonne table de hachage nécessite la connaissance intime du contexte, il lequel il sera utilisé. Devrait-il utiliser en abordant, ou lié chaînage? Quels sont les niveaux de charge doit-elle accepter avant de la redimensionner? Devrait-il utiliser un cher de hachage qui évite les collisions, ou celui qui est rude et rapide?
Depuis le TSL ne pouvez pas anticiper ce qui est le meilleur choix pour votre application, le défaut doit être plus souple. Les arbres "fonctionne" et échelle bien.
(C++11 a ajouter des tables de hachage avec
unordered_map
. Vous pouvez voir à partir de la la documentation il nécessite la définition des politiques de configurer plusieurs de ces options.)Quels sont les autres arbres?
Rouge Noir arbre de l'offre de recherche rapide et sont auto-équilibrage, à la différence des techniciennes se chargent. Un autre utilisateur a souligné ses avantages par rapport à l'auto-équilibrage arbre AVL.
Alexander Stepanov (Le créateur de la STL) a dit qu'il allait utiliser une B* * * * Arbre au lieu d'un Rouge-Noir arbre si il a écrit
std::map
de nouveau, parce que c'est plus convivial et moderne de la mémoire caches.Faut-il toujours utiliser un rouge noir arbre ou B* arbre?
En d'autres occasions, Alex a déclaré que
std::vector
est presque toujours la meilleure liste de conteneur pour des raisons similaires. Il est rarement intéressant d'utiliserstd::list
oustd::deque
même pour les situations qui nous a été enseigné à l'école (comme la suppression d'un élément à partir du milieu de la liste).std::vector
est si rapide que les battements ces structures pour tout, mais les grandesN
.L'application de ce raisonnement, si vous avez seulement un petit nombre d'éléments (des centaines?) à l'aide d'un
std::vector
et linéaire de la recherche peut être plus efficace que celle de l'arbre de la mise en œuvre destd::map
. En fonction de la fréquence de l'insertion, triésstd::vector
combiné avecstd::binary_search
peut être le plus rapide choix.Mise à jour 2017-06-14: webbertiger modifier sa réponse après que j'ai commenté. Je tiens à souligner que sa réponse est aujourd'hui beaucoup mieux à mes yeux. Mais j'ai gardé ma réponse juste à titre d'information supplémentaire...
En raison du fait que je pense que la première réponse est fausse (correction: pas les deux en plus) et la troisième est une fausse affirmation. Je sens que je eu de clarifier les choses...
Les 2 plus populaires arbre AVL Rouge et Noir (RB). La principale différence se situent dans l'utilisation:
La principale différence de la coloration. Vous avez moins de ré-équilibrer l'action en RB arbre que AVL parce que la coloration de vous permettre de vous parfois sauter ou de raccourcir ré-équilibrer les actions qui ont un parent hi coût. En raison de la coloration, RB arbre ont aussi plus de niveau de nœuds, car il pourrait accepter les noeuds rouges entre noirs (avoir les possibilités de ~2x plus de niveaux) ce qui rend la recherche (lire) un peu moins efficace... mais parce que c'est une constante (2x), il reste en O(log n).
Si vous considérez l'impact sur les performances pour une modification d'un arbre (significatif) VS les performances de la consultation d'un arbre (presque insignifiant), il est naturel de préférer RB sur AVL pour un cas général.
C'est juste le choix de votre mise en œuvre, elles pourraient être mises en œuvre comme l'équilibre de toute l'arbre. Les différents choix sont tous comparables, avec des différences mineures. Donc tout est bon à tout.