Lors de la mise en œuvre d'un dictionnaire («Je souhaite rechercher les données client par leur identifiant client»), les structures de données typiques utilisées sont des tables de hachage et des arbres de recherche binaires. Je sais par exemple que la bibliothèque C ++ STL implémente des dictionnaires (ils les appellent des cartes) en utilisant des arbres de recherche binaires (équilibrés), et le framework .NET utilise des tables de hachage sous le capot.
Quels sont les avantages et les inconvénients de ces structures de données? Existe-t-il une autre option raisonnable dans certaines situations?
Notez que je ne suis pas particulièrement intéressé par les cas où les clés ont une structure sous-jacente forte, disons, ce sont tous des entiers compris entre 1 et n ou quelque chose.
la source
Réponses:
Un traité entier pourrait être écrit sur ce sujet; Je vais juste couvrir quelques points saillants, et je vais garder la discussion sur d'autres structures de données au minimum (il existe en effet de nombreuses variantes). Tout au long de cette réponse, est le nombre de clés dans le dictionnaire.n
La réponse courte est que les tables de hachage sont plus rapides dans la plupart des cas , mais peuvent être très mauvaises au pire. Les arbres de recherche présentent de nombreux avantages, y compris le comportement du pire des cas , mais sont un peu plus lents dans les cas typiques.
Les arbres de recherche binaires équilibrés ont une complexité assez uniforme: chaque élément prend un nœud dans l'arbre (généralement 4 mots de mémoire), et les opérations de base (recherche, insertion, suppression) prennent temps (asymptotique garanti borne supérieure). Plus précisément, un accès dans l'arbre prend environ l o g 2 ( n ) comparaisons.O ( l g ( n ) ) l o g2( n )
Les tables de hachage sont un peu plus variables. Ils nécessitent un tableau d'environ pointeurs. L'accès à un élément dépend de la qualité de la fonction de hachage. Le but d'une fonction de hachage est de disperser les éléments. Une table de hachage «fonctionne» si tous les éléments que vous souhaitez y stocker ont des hachages différents. Si tel est le cas, les opérations de base (recherche, insertion, suppression) prennent O ( 1 ) , avec une constante assez petite (un calcul de hachage plus une recherche de pointeur). Cela rend les tables de hachage très rapides dans de nombreux cas typiques.2 n O ( 1 )
Un problème général avec les tables de hachage est que la complexité n'est pas garantie.O ( 1 )
Lorsque vous jetez la localité de données dans le mélange, les tables de hachage fonctionnent mal. Ils fonctionnent précisément parce qu'ils stockent des éléments connexes très éloignés, ce qui signifie que si l'application recherche des éléments partageant un préfixe dans l'ordre, elle ne bénéficiera pas des effets de cache. Cela n'est pas pertinent si l'application effectue des recherches essentiellement aléatoires.
Un autre facteur en faveur des arbres de recherche est qu'ils sont une structure de données immuable : si vous avez besoin de prendre une copie d'un arbre et d'y modifier quelques éléments, vous pouvez partager la plupart de la structure de données. Si vous prenez une copie d'une table de hachage, vous devez copier tout le tableau de pointeurs. De plus, si vous travaillez dans un langage purement fonctionnel, les tables de hachage ne sont souvent pas une option.
En particulier, si vous avez besoin de l' ordre des clés, par exemple si vous souhaitez pouvoir répertorier les clés par ordre alphabétique, les tables de hachage ne vous seront d'aucune aide (vous devrez les trier), tandis que vous peut simplement parcourir un arbre de recherche dans l'ordre.
Vous pouvez combiner des arbres de recherche binaires et des tables de hachage sous la forme d' arbres de hachage . Un arbre de hachage stocke les clés dans un arbre de recherche en fonction de leur hachage. Ceci est utile, par exemple, dans un langage de programmation purement fonctionnel où vous souhaitez travailler sur des données qui n'ont pas de relation d'ordre facile à calculer.
Lorsque les clés sont des chaînes (ou des entiers), un trie peut être une autre option. Un trie est un arbre, mais indexé différemment d'un arbre de recherche: vous écrivez la clé en binaire, et allez à gauche pour un 0 et à droite pour un 1. Le coût d'un accès est donc proportionnel à la longueur de la clé. Les essais peuvent être compressés pour supprimer les nœuds intermédiaires; ceci est connu comme un arbre de patricia trie ou radix . Les arbres Radix peuvent surperformer les arbres équilibrés, en particulier lorsque de nombreuses clés partagent un préfixe commun.
la source