Les réponses précédentes ne traitent que des alternatives d'arbres et le rouge noir ne reste probablement que pour des raisons historiques.
Pourquoi pas une table de hachage?
Un type requiert uniquement l' <
opérateur (comparaison) comme clé dans une arborescence. Cependant, les tables de hachage nécessitent que chaque type de clé ait une hash
fonction définie. Garder les exigences de type au minimum est très important pour la programmation générique afin que vous puissiez l'utiliser avec une grande variété de types et d'algorithmes.
Concevoir une bonne table de hachage nécessite une connaissance intime du contexte dans lequel elle sera utilisée. Doit-il utiliser l'adressage ouvert ou le chaînage lié? Quels niveaux de charge doit-il accepter avant de redimensionner? Doit-il utiliser un hachage coûteux qui évite les collisions, ou qui est rude et rapide?
Étant donné que la STL ne peut pas prévoir quel est le meilleur choix pour votre application, la valeur par défaut doit être plus flexible. Les arbres "fonctionnent" et évoluent bien.
(C ++ 11 a ajouté des tables de hachage avec unordered_map
. Vous pouvez voir dans la documentation qu'il nécessite de définir des politiques pour configurer bon nombre de ces options.)
Et les autres arbres?
Les arbres rouges noirs offrent une recherche rapide et s'équilibrent automatiquement, contrairement aux BST. Un autre utilisateur a souligné ses avantages par rapport à l'arborescence AVL à équilibrage automatique.
Alexander Stepanov (le créateur de STL) a déclaré qu'il utiliserait un arbre B * au lieu d'un arbre rouge-noir s'il écrivait à std::map
nouveau, car il est plus convivial pour les caches de mémoire modernes.
L'un des plus grands changements depuis lors a été la croissance des caches. Les erreurs de cache sont très coûteuses, la localité de référence est donc beaucoup plus importante maintenant. Les structures de données basées sur des nœuds, qui ont une faible localité de référence, ont beaucoup moins de sens. Si je concevais STL aujourd'hui, j'aurais un ensemble différent de conteneurs. Par exemple, un arbre B * en mémoire est un bien meilleur choix qu'un arbre rouge-noir pour implémenter un conteneur associatif. - Alexander Stepanov
Les cartes devraient-elles toujours utiliser des arbres?
Une autre implémentation possible des cartes serait un vecteur trié (tri par insertion) et une recherche binaire. Cela fonctionnerait bien pour les conteneurs qui ne sont pas souvent modifiés mais qui sont fréquemment interrogés. Je fais souvent cela en C au fur qsort
et à mesure que je suis bsearch
intégré.
Dois-je même utiliser la carte?
Considérations de cache signifient il est rarement judicieux d'utiliser std::list
ou std::deque
plus , std:vector
même pour ces situations nous ont été enseignées à l' école (comme la suppression d' un élément du milieu de la liste). Appliquant ce même raisonnement, l'utilisation d'une boucle for pour rechercher une liste de manière linéaire est souvent plus efficace et plus propre que de créer une carte pour quelques recherches.
Bien sûr, le choix d'un conteneur lisible est généralement plus important que les performances.