(Quand) la recherche dans la table de hachage est-elle O (1)?

71

On dit souvent que la recherche de table de hachage fonctionne à temps constant: vous calculez la valeur de hachage, ce qui vous donne un index pour une recherche de tableau. Pourtant, cela ignore les collisions; dans le pire des cas, chaque élément arrive dans le même compartiment et le temps de recherche devient linéaire ( ).Θ(n)

Y a-t-il des conditions sur les données qui peuvent rendre la recherche dans une table de hachage vraiment ? Est-ce seulement en moyenne, ou une table de hachage peut-elle avoir la recherche pire des cas?O ( 1 )O(1)O(1)

Remarque: je viens du point de vue d'un programmeur ici; Lorsque je stocke des données dans une table de hachage, ce sont presque toujours des chaînes ou des structures de données composites, et les données changent pendant la durée de vie de la table de hachage. Ainsi, bien que j'apprécie les réponses concernant les hachages parfaits, elles sont mignonnes mais anecdotiques et peu pratiques de mon point de vue.

Suivi PS: Pour quel type de données les opérations de table de hachage sont-elles O (1)?

Gilles, arrête de faire le mal
la source
3
Pouvez-vous vivre avec temps d’accès amorti? En général, les performances de la table de hachage dépendent énormément de la charge de travail que vous êtes prêt à tolérer pour les hashtables clairsemées et de la manière dont les valeurs de hachage réelles sont distribuées. O(1)
Raphaël
5
Oh, au fait: vous pouvez éviter le pire comportement linéaire en utilisant des arbres de recherche (équilibrés) au lieu de listes.
Raphaël
1
@Raphael Je serais très intéressé par une réponse qui explique (en gros) quand je peux compter sur amorti et quand je ne le peux pas. Quant à la façon dont les valeurs de hachage sont distribuées, cela fait partie de ma question: comment puis-je savoir? Je sais que les fonctions de hachage sont censées bien répartir les valeurs; mais s'ils le faisaient toujours, le pire des cas ne serait jamais atteint, ce qui n'a pas de sens. O(1)
Gilles 'SO- arrête d'être méchant'
1
Faites également attention à l'optimisation prématurée; pour des données plus petites (plusieurs milliers d'éléments), j'ai souvent vu des arbres binaires équilibrés surperformant les hashtables en raison d'une surcharge moins importante (les comparaisons de chaînes sont beaucoup moins chères que les tables de hachage). O(logn)
isturdy
Continuons cette discussion sur le chat .
Raphaël

Réponses:

41

Il existe deux paramètres sous lesquels vous pouvez obtenir pires cas.O(1)

  1. Si votre configuration est statique, le hachage FKS vous apportera les garanties plus défavorables . Mais comme vous l'avez indiqué, votre réglage n'est pas statique.O(1)

  2. Si vous utilisez le hachage Cuckoo, les requêtes et les suppressions sont considérées comme étant le cas le plus défavorable de , mais l'insertion n'est attendue que de . Le hachage de coucou fonctionne assez bien si vous avez une limite supérieure sur le nombre total d'insertions et si vous définissez une taille de table environ 25% plus grande.O ( 1 )O(1)O(1)

Il y a plus d'informations ici .

Suresh
la source
3
Pourriez-vous développer sur FKS et Cuckoo? Les deux termes sont nouveaux pour moi.
Gilles 'SO- arrête d'être méchant'
1
Qu'en est-il du hachage parfait dynamique? Il comporte les recherches cas les plus défavorables et les insertions et suppressions amorties. ( citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.30.8165 )O ( 1 )O(1)O(1)
Joe
2
FKS sont les initiales de (Fredman, Komlós, Szemerédi) et Cuckoo est le nom d'une espèce de mule. Il est utilisé pour ce type de hachage, car les poussins à coucou poussent les œufs de sibilings hors du nid. Cela ressemble un peu au fonctionnement de cette méthode hasing.
Uli
1
@Suresh: Vraiment? Je pensais que vous aviez besoin de fonctions -independent, que j’ai toujours associées à la nécessité d’extensions. Je me suis trompé. Va supprimer mon commentaire dans un peu. logn
Louis
1
Pour faire un commentaire plus utile sur cette réponse, comme le fait remarquer @Suresh, le hachage du coucou fonctionnera bien sans les fonctions de hachage fantaisistes (et volumineuses) utilisées pour l’analyser de manière théorique.
Louis
21

Cette réponse résume des parties de TAoCP Vol 3, Ch 6.4.

Supposons que nous ayons un ensemble de valeurs , que nous voulons stocker dans un tableau de taille . Nous employons une fonction de hachage ; typiquement,. Nous appelons le facteur de charge de . Ici, nous supposerons le naturel ; dans les scénarios pratiques, nous avons , cependant, et doivent cartographier jusqu'à nous.n A m h : V [ 0 .. M ) M | V | α = nVnAmh:V[0..M)M|V| Am=MmMmα=nmAm=MmMm

La première observation est que même si présente des caractéristiques uniformes¹, la probabilité que deux valeurs aient la même valeur de hachage est élevée; c’est essentiellement un exemple du fameux paradoxe des anniversaires . Par conséquent, nous devrons généralement faire face à des conflits et abandonner tout espoir de pire des cas.O ( 1 )hO(1)

Qu'en est-il du cas moyen, cependant? Supposons que chaque clé de se produit avec la même probabilité. Le nombre moyen d'entrées vérifiées (recherche réussie) resp. (recherche infructueuse) dépend de la méthode de résolution de conflit utilisée.C S n C U n[0..M)CnSCnU

Chaînage

Chaque entrée de tableau contient (un pointeur sur l'en-tête de) une liste liée. C'est une bonne idée car la longueur de liste attendue est petite ( ), même si la probabilité d'avoir des collisions est élevée. Au final, nous obtenons Cela peut être légèrement amélioré en stockant les listes (partiellement ou complètement) dans la table. C S n1+αnm

CnS1+α2 and CnU1+α22.

Palpage linéaire

Lorsque vous insérez (ou cherchez une valeur) , vérifiez les positions dans cet ordre jusqu'à une position vide (resp. ) est trouvé. L'avantage est que nous travaillons localement et sans structures de données secondaires; cependant, le nombre d'accès moyens diverge pour : Pour , toutefois, les performances sont comparables à celles du chaînage².v

h(v),h(v)1,,0,m1,,h(v)+1
vα1α<0,75
CnS12(1+11α) and CnU12(1+(11α)2).
α<0.75

Double hachage

Similaire à sonder linéaire mais la taille de l' étape de recherche est commandée par une seconde fonction de hachage qui est premier à . Aucune dérivation formelle n'est donnée, mais des observations empiriques suggèrent que Cette méthode a été adaptée par Brent. Cette variante amortit les coûts d’insertion accrus par des recherches moins coûteuses.C S n1M

CnS1αln(11α) and CnU11α.

Notez que le retrait d'éléments des tables et leur extension présentent des difficultés variables pour les méthodes respectives.

En bout de ligne, vous devez choisir une implémentation qui s'adapte bien à vos cas d'utilisation typiques. Le temps d'accès attendu dans est possible s'il n'est pas toujours garanti. En fonction de la méthode utilisée, maintenir low est essentiel; vous devez faire un compromis entre le temps d'accès (prévu) et les frais généraux. Un bon choix pour est aussi central, évidemment.O(1)hαh


1] Etant donné que les programmeurs non avertis arbitrairement muets peuvent fournir , toute hypothèse concernant sa qualité n’est pas pratique dans la pratique. 2] Notez comment cela coïncide avec les recommandations d'utilisation de Java .h
Hashtable

Raphaël
la source
10

Une fonction de hachage parfaite peut être définie comme une fonction injective d’un ensemble à un sous-ensemble des entiers . Si une fonction de hachage parfaite existe pour vos données et vos besoins de stockage, vous pouvez facilement obtenir le comportement . Par exemple, vous pouvez obtenir la performance d'une table de hachage pour la tâche suivante: étant donné un tableau d'entiers et un ensemble d'entiers, déterminer si contient pour chaque . Une étape de pré-traitement impliquerait de créer une table de hachage dans , puis de vérifier chaque élément de rapport à lui dansS{0,1,2,...,n}O(1)O(1)lSlxxSO(|l|)SO(|S|) . Au total, c'est . Une implémentation naïve utilisant la recherche linéaire pourrait être ; en utilisant la recherche binaire, vous pouvez faire (notez que cette solution est un espace , car la table de hachage doit mapper des entiers distincts de vers des segments distincts).O(|l|+|S|)O(|l||S|)O(log(|l|)|S|)O(|l|)l

EDIT: Pour clarifier la manière dont la table de hachage est générée dans :O(|l|)

La liste contient des nombres entiers à partir d' un ensemble fini , le cas échéant avec des répétitions, et . Nous voulons déterminer si est dans . Pour ce faire, nous pré-calculons une table de hachage pour les éléments de : une table de recherche. La table de hachage encodera une fonction . Pour définir , on suppose d' abord pour tout . Ensuite, parcourez linéairement les éléments de en définissant . Cela prend temps etlUNSUxSllh:U{true,false}hh(x)=falsexUylh(y)=trueO(|l|)O(|U|) espace.

Notez que mon analyse initiale supposait que contenait au moins éléments distincts. S'il contient moins d'éléments distincts (par exemple, ), l'espace requis peut être supérieur (même s'il ne s'agit pas de plus de ).lO(|U|)O(|1|)O(|U|)

EDIT2: La table de hachage peut être stockée sous la forme d'un tableau simple. La fonction de hachage peut être la fonction d'identité sur . Notez que la fonction identité est trivialement une fonction de hachage parfaite. est la table de hachage et code une fonction séparée. Je suis confuse / confuse dans certains de ce qui précède, mais je vais essayer de l'améliorer bientôt.Uh

Patrick87
la source
Pourriez-vous développer la partie où vous créez la table de hachage dans ? Je peux voir comment faire cela si vous ne vous inquiétez pas des collisions, mais cela signifie que les recherches ultérieures peuvent prendre plus que , jusqu'à . O(|l|)O(|S|)O(|l||S|)
Gilles 'SO- arrête d'être méchant'
Je ne comprends pas la définition de . Vous définissez une fonction sans expliquer comment elle est représentée; Pourriez-vous écrire quelques lignes de pseudocode? Il y a aussi un problème de notation; et bijective ne vont pas bien ensemble. hh:U{false,true}h
Gilles 'SO- arrête d'être méchant'
@ Gilles Il s'agit essentiellement d'une table de consultation pour les membres d'une liste. Lorsque vous avez une fonction de hachage parfaite avec un inverse connu et peu coûteux, au lieu de stocker la chose elle-même, il vous suffit de stocker 1 bit (que la chose avec l'unique hash ait été ajoutée). Si des collisions sont possibles, je pense que cela est appelé un filtre de Bloom, mais peut en tout état de cause fournir un "non" définitif à la question de l'adhésion, ce qui reste utile dans de nombreux scénarios.
Patrick87
9

Une fonction de hachage parfaite donnera pire des recherches.O(1)

De plus, si le nombre maximal de collisions possible est , on peut dire que la recherche dans la table de hachage est dans le pire des cas. Si le nombre de collisions attendu est , la recherche dans la table de hachage peut être considérée comme étant dans le cas moyen.O ( 1 ) O ( 1 ) O ( 1 )O(1)O(1)O(1)O(1)

Nicholas Meyer
la source
Une fonction de hachage parfaite serait parfaite, mais comment puis-je en obtenir une? Combien cela va-t-il me coûter? Et comment puis-je savoir quel est le nombre maximal ou prévu de collisions?
Gilles 'SO- arrête d'être méchant'
2
@Gilles une fonction de hachage parfaite est toute fonction qui produira un hachage unique pour toutes les entrées possibles. Si vos entrées possibles sont finies (et uniques), c'est facile à faire.
Rafe Kettler
1
@RafeKettler Mes entrées sont généralement des chaînes ou des structures de données composées, et j'ajoute et supprime généralement des entrées au fur et à mesure de l'évolution de mes données. Comment puis-je faire un hachage parfait pour cela?
Gilles 'SO- arrête d'être méchant'
4
Oui, mais c'est le but. Une fonction de hachage déterministe parfaite n'existe pas si le domaine est plus grand que la plage.
Suresh
@Suresh: Si vous êtes autorisé à choisir une nouvelle fonction de hachage et à augmenter la taille de la table en cas de collision, vous pouvez toujours trouver une fonction de hachage (déterministe) qui - pour les données déjà présentes dans la table plus la nouvelle élément que vous essayez d'insérer - n'a pas de collision (est "parfait"). C'est pourquoi le hachage parfait et dynamique sélectionne périodiquement une nouvelle fonction de hachage aléatoire.
David Cary