Avantages des arborescences de recherche binaires par rapport aux tables de hachage


102

Quels sont les avantages des arbres de recherche binaires par rapport aux tables de hachage?

Les tables de hachage peuvent rechercher n'importe quel élément dans le temps Theta (1) et il est tout aussi facile d'ajouter un élément ... mais je ne suis pas sûr des avantages de l'inverse.


pour les tables de hachage, quels sont les temps d'exécution de find () insert () et remove ()? thêta (1) thêta (1) et thêta (1) n'est-ce pas?
Consacré

8
Presque toujours, oui. Si vous rencontrez beaucoup de collisions, ces temps pourraient atteindre O (n).
Christian Mann

1
Ces temps dépendent également de votre fonction de hachage. Si pour une raison étrange ce n'est pas O (1), évidemment vos opérations auront une limite minimale de l'efficacité de votre fonction de hachage.
Christian Mann

Je dirais que les plus grands avantages du BST sont qu'il se trouve dans une structure de données triée. Détail du cas d'utilisation déjà répertorié ici .
Yuantao

Réponses:


93

N'oubliez pas que les arbres de recherche binaires (basés sur des références) sont économes en mémoire. Ils ne réservent pas plus de mémoire que nécessaire.

Par exemple, si une fonction de hachage a une plage R(h) = 0...100, vous devez allouer un tableau de 100 éléments (pointeurs vers), même si vous ne faites que hacher 20 éléments. Si vous deviez utiliser une arborescence de recherche binaire pour stocker les mêmes informations, vous n'alloueriez que l'espace dont vous avez besoin, ainsi que certaines métadonnées sur les liens.


33
Il n'est pas vrai que la plage entière des sorties de fonction de hachage doit exister dans le tableau. Les valeurs de hachage peuvent simplement être modifiées par la longueur du tableau pour permettre un tableau plus petit. Bien sûr, le nombre ultime d'éléments ajoutés peut ne pas être connu, de sorte que la table de hachage peut toujours allouer plus d'espace que nécessaire. Cependant, les arbres de recherche binaires peuvent gaspiller autant de mémoire, voire plus. Les implémentations liées ont besoin d'espace pour au moins deux pointeurs supplémentaires par élément (trois si vous utilisez un pointeur parent), et les BST basés sur des tableaux peuvent gaspiller beaucoup de mémoire pour les parties non remplies de l'arborescence.
Solaraeus du

4
@Solaraeus: Les BST basés sur des tableaux sont les meilleurs à comparer aux tables de hachage et ils ne sont pas plus inutiles que les tables de hachage. Vous pouvez également étendre un BST avec un peu plus d'une copie de mémoire, par rapport à recalculer la table entière.
Guvante

125

Un avantage que personne d'autre n'a souligné est que l'arbre de recherche binaire vous permet d'effectuer des recherches par plage de manière efficace.

Afin d'illustrer mon idée, je veux faire un cas extrême. Supposons que vous souhaitiez obtenir tous les éléments dont les clés sont comprises entre 0 et 5000. Et en fait, il n'y a qu'un seul élément de ce type et 10 000 autres éléments dont les clés ne sont pas dans la plage. BST peut effectuer des recherches par plage assez efficacement car il ne recherche pas un sous-arbre, ce qui est impossible d'avoir la réponse.

Alors, comment pouvez-vous effectuer des recherches par plage dans une table de hachage? Soit vous devez itérer chaque espace de compartiment, qui est O (n), soit vous devez rechercher si chacun des 1,2,3,4 ... jusqu'à 5000 existe. (qu'en est-il des clés entre 0 et 5000 sont un ensemble infini? par exemple, les clés peuvent être des décimales)


11
Les BST effectuent des recherches de distance efficacement! Pour moi, c'est la meilleure réponse en termes d'approche pratique et algorithmique.
2013

4
wow cela explique vraiment pourquoi les arbres sont si associés aux bases de données; leurs avantages sont plus visibles lorsque vous devez effectuer un filtrage basé sur des clés. avec les cartes de hachage, vous devez effectuer une boucle sur toutes les clés pour résoudre "trouver tous les éléments avec une clé entre 1000 et 3290"
Dmitry

77

Un "avantage" d'un arbre binaire est qu'il peut être parcouru pour lister tous les éléments dans l'ordre. Ce n'est pas impossible avec une table de hachage, mais ce n'est pas une opération normale une conception dans une structure hachée.


3
traverser dans n'importe quel ordre n'aurait probablement aucun sens sur une table de hachage.
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesigner. Voir Table de hachage linéaire
triée

Merci pour le lien, c'est une idée entrecroisée! Je ne pense pas avoir jamais vu ou utilisé une implémentation de cela (du moins pas sciemment).
FrustratedWithFormsDesigner

1
Lien Wayback Machine pour l'article - web.archive.org/web/20100323091632/http
//www.concentric.net

51

En plus de tous les autres bons commentaires:

Les tables de hachage en général ont un meilleur comportement de cache nécessitant moins de lectures de mémoire par rapport à un arbre binaire. Pour une table de hachage, vous n'effectuez normalement qu'une seule lecture avant d'avoir accès à une référence contenant vos données. L'arbre binaire, s'il s'agit d'une variante équilibrée, nécessite quelque chose de l'ordre de k * lg (n) lectures de mémoire pour une constante k.

D'un autre côté, si un ennemi connaît votre fonction de hachage, l'ennemi peut imposer votre table de hachage pour faire des collisions, ce qui entrave considérablement ses performances. La solution de contournement consiste à choisir la fonction de hachage au hasard dans une famille, mais un BST ne présente pas cet inconvénient. De plus, lorsque la pression de la table de hachage augmente trop, vous avez souvent tendance à agrandir et à réallouer la table de hachage, ce qui peut être une opération coûteuse. Le BST a ici un comportement plus simple et n'a pas tendance à allouer soudainement beaucoup de données et à effectuer une opération de rehachage.

Les arbres ont tendance à être la structure de données moyenne ultime. Ils peuvent agir comme des listes, peuvent facilement être divisés pour un fonctionnement parallèle, ont une suppression, une insertion et une recherche rapides de l'ordre de O (lg n) . Ils ne font rien de particulièrement bien, mais ils n'ont pas non plus de comportement excessivement mauvais.

Enfin, les BST sont beaucoup plus faciles à implémenter dans des langages fonctionnels (purs) par rapport aux tables de hachage et ils ne nécessitent pas de mises à jour destructives pour être implémentées (l' argument de persistance de Pascal ci-dessus).


3
BSTs are much easier to implement in (pure) functional languages compared to hash-tables- vraiment? Je veux apprendre un langage fonctionnel maintenant!
nawfal

1
La table de hachage doit être persistante dans un langage fonctionnel. Cela complique souvent les implémentations.
JE DONNE DES RÉPONSES CRAP

pour élaborer, si vous créez des structures de données président dans des langages fonctionnels, tout ce que vous finissez par faire est d'écrire le même code que vous le feriez en assemblage, sauf à chaque opération que vous transformez explicitement votre tableau de mémoire / registres, ou parlez à un serveur pour faire semblant pour faire ça. Je suis tout à fait conscient de votre état, mais il est isomorphe à l'approche impérative si cela est fait correctement (vous ne pouvez pas copier de manière réaliste une grande quantité de données sur chaque transformation dans la vie réelle, vous devez tricher).
Dmitry

27

Les principaux avantages d'un arbre binaire par rapport à une table de hachage sont que l'arbre binaire vous donne deux opérations supplémentaires que vous ne pouvez pas faire (facilement, rapidement) avec une table de hachage

  • trouver l'élément le plus proche (pas nécessairement égal à) d'une valeur clé arbitraire (ou le plus proche au-dessus / au-dessous)

  • parcourir le contenu de l'arborescence dans un ordre trié

Les deux sont connectés - l'arbre binaire conserve son contenu dans un ordre trié, de sorte que les choses qui nécessitent cet ordre trié sont faciles à faire.


BST trouve la correspondance la plus proche, uniquement si la correspondance exacte n'existe pas, non? Et si vous trouviez une correspondance exacte à la racine elle-même?
developer747

2
@ developer747: Ensuite, la feuille la plus proche en dessous et au-dessus sont la feuille la plus à droite du sous-arbre de gauche et la feuille la plus à gauche du sous-arbre de droite.
Chris Dodd

16

Un arbre de recherche binaire (équilibré) a également l'avantage que sa complexité asymptotique est en fait une limite supérieure, tandis que les temps "constants" pour les tables de hachage sont des temps amortis: si vous avez une fonction de hachage inadaptée, vous pourriez finir par se dégrader en temps linéaire , plutôt que constant.


3
Pour ramener ce point à la maison, un cas dégénéré est lorsque la collection contient plusieurs copies d'une seule clé. dans le BST, insérer est O (log n), dans une table de hachage, insérer est O (n)
SingleNegationElimination

2
Lorsqu'une table de hachage contient plusieurs copies d'une seule clé, insérer est (toujours) O (1) et non O (n). Le problème pour les tables de hachage est lorsqu'il existe de nombreuses clés différentes avec le même hachage. Cela peut être évité par un schéma de hachage dynamique qui passe à une fonction de hachage différente lorsqu'il y a de nombreuses collisions.
Chris Dodd le

Notez qu'un arbre déséquilibré peut dégénérer en une liste et avoir également une recherche O (n).
awiebe

9

Une table de hachage prendrait plus d'espace lors de sa création - elle disposera d'emplacements disponibles pour les éléments qui doivent encore être insérés (qu'ils soient insérés ou non), un arbre de recherche binaire ne sera aussi grand que nécessaire. être. De plus, lorsqu'une table de hachage a besoin de plus d'espace, l'expansion vers une autre structure peut prendre du temps, mais cela peut dépendre de l'implémentation.


8

Un arbre de recherche binaire peut être implémenté avec une interface persistante , où un nouvel arbre est renvoyé mais l'ancien arbre continue d'exister. Mis en œuvre avec soin, les anciens et les nouveaux arbres partagent la plupart de leurs nœuds. Vous ne pouvez pas faire cela avec une table de hachage standard.


6

Un arbre binaire est plus lent à rechercher et à insérer, mais a la très belle fonctionnalité de traversée d'infixe qui signifie essentiellement que vous pouvez parcourir les nœuds de l'arbre dans un ordre trié.

Itérer dans les entrées d'une table de hachage n'a tout simplement pas beaucoup de sens car elles sont toutes dispersées dans la mémoire.


6

From Cracking the Coding Interview, 6e édition

Nous pouvons implémenter la table de hachage avec un arbre de recherche binaire équilibré (BST). Cela nous donne un temps de recherche O (log n). L'avantage de cela est d'utiliser potentiellement moins d'espace, car nous n'allouons plus un grand tableau. Nous pouvons également parcourir les clés dans l'ordre, ce qui peut parfois être utile.


5

Les BST fournissent également les opérations «findPredecessor» et «findSuccessor» (pour trouver le prochain élément le plus petit et le suivant le plus grand) en temps O (logn), ce qui peut également être des opérations très pratiques. Hash Table ne peut pas fournir dans ce temps l'efficacité.


Si vous recherchez des opérations "findPredecessor" et "findSuccessor", alors HashTable est un mauvais choix pour la structure de données en premier lieu.
AKDesai

1

Si vous souhaitez accéder aux données de manière triée, une liste triée doit être maintenue en parallèle à la table de hachage. Un bon exemple est Dictionary in .Net. (voir http://msdn.microsoft.com/en-us/library/3fcwy8h6.aspx ).

Cela a pour effet secondaire non seulement de ralentir les insertions, mais cela consomme une plus grande quantité de mémoire qu'un b-tree.

De plus, comme un b-tree est trié, il est simple de trouver des plages de résultats, ou d'effectuer des unions ou des fusions.


1

Cela dépend aussi de l'utilisation, Hash permet de localiser la correspondance exacte. Si vous souhaitez interroger une plage, BST est le choix. Supposons que vous ayez beaucoup de données e1, e2, e3 ..... fr.

Avec la table de hachage, vous pouvez localiser n'importe quel élément en temps constant.

Si vous voulez trouver des valeurs de plage supérieures à e41 et inférieures à e8, BST peut le trouver rapidement.

L'élément clé est la fonction de hachage utilisée pour éviter une collision. Bien sûr, nous ne pouvons pas éviter totalement une collision, auquel cas nous recourons au chaînage ou à d'autres méthodes. Cela rend la récupération plus de temps constant dans le pire des cas.

Une fois pleine, la table de hachage doit augmenter sa taille de compartiment et recopier à nouveau tous les éléments. Il s'agit d'un coût supplémentaire non présent sur BST.


1

Les tables de hachage ne sont pas adaptées à l'indexation. Lorsque vous recherchez une plage, les BST sont meilleurs. C'est la raison pour laquelle la plupart des index de base de données utilisent des arbres B + au lieu des tables de hachage


les index de bases de données sont des deux types d'arbres de hachage et B +. Lorsque vous voulez faire une comparaison comme supérieur ou inférieur à, alors l'index des arbres B + est utile, sinon l'index de hachage est utile pour la recherche. Pensez également au moment où les données ne sont pas comparables et si vous voulez créer un index, alors db créera un index de hachage et non un index d'arborescence B +. @ssD
Sukhmeet Singh

1

Les arbres de recherche binaires sont un bon choix pour implémenter le dictionnaire si les clés ont un ordre total (les clés sont comparables) défini sur elles et que vous souhaitez conserver les informations de commande.

Comme BST préserve les informations de commande, il vous fournit quatre opérations de jeu dynamique supplémentaires qui ne peuvent pas être effectuées (efficacement) à l'aide de tables de hachage. Ces opérations sont:

  1. Maximum
  2. Le minimum
  3. Successeur
  4. Prédécesseur

Toutes ces opérations, comme toutes les opérations BST, ont une complexité temporelle de O (H). De plus, toutes les clés stockées restent triées dans le BST, vous permettant ainsi d'obtenir la séquence triée de clés simplement en parcourant l'arborescence dans l'ordre.

En résumé, si tout ce que vous voulez, ce sont des opérations d'insertion, de suppression et de suppression, la table de hachage est imbattable (la plupart du temps) en termes de performances. Mais si vous voulez une ou toutes les opérations énumérées ci-dessus, vous devez utiliser un BST, de préférence un BST auto-équilibré.


0

Le principal avantage de la table de hachage est qu'elle effectue presque toutes les opérations dans ~ = O (1). Et c'est très facile à comprendre et à mettre en œuvre. Il résout efficacement de nombreux «problèmes d'entrevue». Donc, si vous voulez craquer une interview de codage, faites-vous de meilleurs amis avec la table de hachage ;-)


Je pense que l'OP a demandé des avantages de BST par rapport au hachage.
Sniper

0

Un hashmap est un tableau associatif d'ensemble. Ainsi, votre tableau de valeurs d'entrée est regroupé dans des compartiments. Dans un schéma d'adressage ouvert, vous avez un pointeur vers un compartiment, et chaque fois que vous ajoutez une nouvelle valeur dans un compartiment, vous découvrez où dans le compartiment il y a des espaces libres. Il y a plusieurs façons de faire cela: vous commencez au début du compartiment et incrémentez le pointeur à chaque fois et testez s'il est occupé. C'est ce qu'on appelle le palpage linéaire. Ensuite, vous pouvez effectuer une recherche binaire comme add, où vous doublez la différence entre le début du bucket et où vous doublez vers le haut ou vers le bas chaque fois que vous recherchez un espace libre. C'est ce qu'on appelle le sondage quadratique. D'ACCORD. Maintenant, le problème dans ces deux méthodes est que si le compartiment déborde dans l'adresse de compartiment suivante, vous devez alors-

  1. Double la taille de chaque seau - malloc (N seaux) / modifier la fonction de hachage - Temps requis: dépend de l'implémentation de malloc
  2. Transférez / copiez chacune des données de buckets précédentes dans les nouvelles données de buckets. Il s'agit d'une opération O (N) où N représente l'ensemble des données

D'ACCORD. mais si vous utilisez une liste liée, il ne devrait pas y avoir un tel problème, non? Oui, dans les listes liées, vous n'avez pas ce problème. Considérant que chaque bucket commence par une liste liée, et si vous avez 100 éléments dans un bucket, il vous faudra parcourir ces 100 éléments pour atteindre la fin de la liste liée, donc List.add (élément E) prendra du temps pour-

  1. Hash l'élément dans un bucket - Normal comme dans toutes les implémentations
  2. Prenez le temps de trouver le dernier élément de ladite opération seau-O (N).

L'avantage de l'implémentation de la liste liée est que vous n'avez pas besoin de l'opération d'allocation de mémoire et de transfert / copie O (N) de tous les compartiments comme dans le cas de l'implémentation d'adressage ouvert.

Ainsi, la façon de minimiser l'opération O (N) est de convertir l'implémentation en celle d'un arbre de recherche binaire où les opérations de recherche sont O (log (N)) et vous ajoutez l'élément à sa position en fonction de sa valeur. La caractéristique supplémentaire d'un BST est qu'il est trié!


0

Les arbres de recherche binaires peuvent être plus rapides lorsqu'ils sont utilisés avec des clés de chaîne. Surtout quand les cordes sont longues.

Arbres de recherche binaires utilisant des comparaisons pour moins / plus qui sont rapides pour les chaînes (lorsqu'elles ne sont pas égales). Ainsi, un BST peut répondre rapidement lorsqu'une chaîne n'est pas trouvée. Lorsqu'il est trouvé, il ne devra faire qu'une seule comparaison complète.

Dans une table de hachage. Vous devez calculer le hachage de la chaîne et cela signifie que vous devez parcourir tous les octets au moins une fois pour calculer le hachage. Puis à nouveau, lorsqu'une entrée correspondante est trouvée.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.