141 votes

HashSet<T> versus Dictionary<K, V> en ce qui concerne le temps de recherche pour trouver si un élément existe

HashSet<T> t = new HashSet<T>();
// add 10 million items

Dictionary<K, V> t = new Dictionary<K, V>();
// add 10 million items.

Dont .Contains retournera plus rapidement ?

Pour clarifier, j'ai besoin de 10 millions d'objets (en fait, des chaînes de caractères) dont je dois vérifier l'existence dans la structure de données. Je n'itérerai JAMAIS.

2 votes

Étape 1 : Voir si les deux font la même chose (dans ce cas, les deux collections ont des objectifs différents). Étape 2 : Consultez la documentation et voyez si vous vous sentez bien dans leur complexité asymptotique. Étape 3 : Si vous sentez que vous devez vous inquiéter davantage, mesurez-vous et posez ensuite la question en affichant le repère qui va avec. Dans votre cas, la question devient inutile dès la première étape.

197voto

had Points 401

Test de performance HashSet vs Liste vs Dictionnaire, tiré de ici .

Ajouter 1000000 objets (sans vérifier les doublons)

Contient la vérification de la moitié des objets d'une collection de 10000

Supprimer la moitié des objets d'une collection de 10000

14 votes

Excellente analyse ! Il semble que le .Contains pour Dictionary soit si rapide qu'il n'y a aucun avantage à utiliser HashSet, dans le cas de l'OP.

4 votes

Oui, j'ai eu la même question que l'OP. J'ai déjà un dictionnaire que j'utilise pour d'autres raisons, et je voulais savoir s'il était avantageux de passer à un Hashset au lieu d'utiliser ContainsKey. On dirait que la réponse est non puisque les deux sont si rapides.

8 votes

Contrairement à ce que les commentaires précédents semblent impliquer, oui, vous devriez passer à HashSet car il vous donne ce que vous voulez : stocker un ensemble de valeurs (par opposition à la maintenance d'une sorte de mappage). Cette réponse indique qu'il n'y aura pas d'impact négatif sur les performances par rapport à Dictionary.

82voto

Jon Skeet Points 692016

Je suppose que vous voulez dire Dictionary<TKey, TValue> dans le second cas ? HashTable est une classe non générique.

Vous devez choisir la bonne collection pour le travail en fonction de vos besoins réels. Est-ce que vous veulent pour faire correspondre chaque clé à une valeur ? Si oui, utilisez Dictionary<,> . Si vous uniquement si vous y attachez de l'importance en tant qu'ensemble, utilisez HashSet<> .

Je m'attendrais HashSet<T>.Contains y Dictionary<TKey, TValue>.ContainsKey (qui sont des opérations comparables, en supposant que vous utilisiez votre dictionnaire de manière raisonnable) pour effectuer fondamentalement la même chose - ils utilisent le même algorithme, fondamentalement. Je suppose qu'avec les entrées dans Dictionary<,> étant plus large, vous avez plus de chances de faire sauter le cache avec Dictionary<,> qu'avec HashSet<> mais j'imagine que c'est insignifiant par rapport à la difficulté de choisir le mauvais type de données, simplement en fonction de ce que vous essayez d'obtenir.

0 votes

Oui, je voulais dire Dictionary<TKey, TValue>. Je suis seulement concerné par la recherche de l'existence d'un élément dans une structure de données, c'est à dire tous .

7 votes

@halivingston Dans ce cas, utilisez HashSet. Cela rend évident le fait que est tout ce dont vous avez besoin.

0 votes

Dans 60% des cas, il y aura un échec, donc je pense que je peux doubler mon coût mémoire. Je devrais peut-être reconsidérer la question et me contenter d'utiliser le dictionnaire.

13voto

ripvlan Points 86

Extrait de la documentation MSDN sur le dictionnaire<TKey,TValue>.

"La récupération d'une valeur en utilisant sa clé est très rapide, proche de O(1) car la classe Dictionary est implémentée comme une table de hachage. "

Avec une note :

"La vitesse de récupération dépend de la qualité de l'algorithme de hachage du type spécifié pour TKey"

Je sais que votre question/poste est ancienne - mais en cherchant une réponse à une question similaire, je suis tombée sur ceci.

J'espère que cela vous aidera. Faites défiler la page jusqu'au Remarques pour plus de détails. https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx

6voto

Brondahl Points 75

La réponse acceptée à cette question ne répond PAS valablement à la question ! Elle donne la bonne réponse, mais cette réponse n'est pas démontrée par les preuves fournies.

Ce que cette réponse montre, c'est que les recherches de clés sur une Dictionary o HashSet sont beaucoup plus rapides que de chercher dans une List . Ce qui est vrai, mais n'est ni intéressant, ni surprenant, ni la preuve qu'ils ont la capacité d'agir. même vitesse.

J'ai exécuté le code ci-dessous pour comparer les temps de recherche, et ma conclusion est qu'ils sont en fait de la même vitesse. (Ou du moins, s'il y a une différence, alors la différence est bien dans l'écart type de cette vitesse).

Plus précisément, 100 000 000 de recherches prenaient entre 10 et 11,5 secondes pour les deux, pour moi, dans ce test.

Code de test :

private const int TestReps = 100_000_000;
[Test]
public void CompareHashSetContainsVersusDictionaryContainsKey()
{
    for (int j = 0; j < 10; j++)
    {
        var rand = new Random();
        var dict = new Dictionary<int, int>();
        var hash = new HashSet<int>();

        for (int i = 0; i < TestReps; i++)
        {
            var key = rand.Next();
            var value = rand.Next();
            hash.Add(key);
            dict.TryAdd(key, value);
        }

        var testPoints = Enumerable.Repeat(1, TestReps).Select(_ => rand.Next()).ToArray();
        var timer = new Stopwatch();
        var total = 0;

        timer.Restart();
            for (int i = 0; i < TestReps; i++)
            {
                var newKey = testPoints[i];
                if (hash.Contains(newKey))
                {
                    total++;
                }
            }
        Console.WriteLine(timer.Elapsed);

        var target = total;
        Assert.That(total == target);

        timer.Restart();
            for (int i = 0; i < TestReps; i++)
            {
                var newKey = testPoints[i];
                if (dict.ContainsKey(newKey))
                {
                    total++;
                }
            }
        Console.WriteLine(timer.Elapsed);

        Assert.That(total == target * 2);
        Console.WriteLine("Set");
    }
}

4voto

Andrew Bezzub Points 8794

Il s'agit de structures de données différentes. Il n'existe pas non plus de version générique de HashTable .

HashSet contient des valeurs de type T qui HashTable (ou Dictionary ) contient des paires clé-valeur. Vous devez donc choisir la collection en fonction des données que vous souhaitez stocker.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X