HashSet <T>与Dictionary <K,V>搜索时间以查找项目是否存在

hal*_*ton 101 .net performance dictionary hashset

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


Dictionary<K, V> t = new Dictionary<K, V>();
// add 10 million items.
Run Code Online (Sandbox Code Playgroud)

谁的.Contains方法会更快返回?

只是为了澄清,我的要求是我有1000万个对象(嗯,真的是字符串),我需要检查它们是否存在于数据结构中.我永远不会迭代.

had*_*had 147

HashSet vs List vs Dictionary性能测试,取自此处.

添加1000000个对象(不检查重复项)

包含对10000个集合的一半对象的检查

删除10000个集合的一半对象

  • 这个答案并没有告诉你 HashSet 和 Dictionary 的性能比较......它告诉你的是它们都比 List 更快......好吧......是的!明显地!HashSet 可能快 3 倍,但你不会知道,因为相关测试已经崩溃为“它们是瞬时的……***与 List 相比***”。 (10认同)
  • 很棒的分析!看起来.Contains for Dictionary是如此之快,以至于在OP的情况下根本没有使用HashSet的好处. (9认同)
  • 与先前的评论似乎暗示的相反,是的,您应该切换到HashSet,因为它可以为您提供所需的内容:存储一组值(而不是维护某种映射).这个答案表明与Dictionary相比,对性能没有负面影响. (3认同)
  • 是的,我和OP有同样的问题.我已经有一个字典,我正在使用其他原因,并想知道我是否从更改为Hashset而不是使用ContainsKey中受益.看起来答案是否定的,因为两者都如此之快. (2认同)

Jon*_*eet 69

我假设你Dictionary<TKey, TValue>在第二种情况下的意思?HashTable是一个非泛型类.

您应该根据实际需求为作业选择合适的集合.你真的想要将每个键映射到一个值吗?如果是这样,请使用Dictionary<,>.如果您关心它作为一组,请使用HashSet<>.

我希望HashSet<T>.ContainsDictionary<TKey, TValue>.ContainsKey(这是可比较的操作,假设你明智地使用你的字典)基本上执行相同 - 他们从根本上使用相同的算法.我想随着条目Dictionary<,>变大,你最终会有更大的可能性,而Dictionary<,>不是使用HashSet<>,但是我认为与仅选择错误的数据类型的痛苦相比,这是微不足道的.试图实现.

  • 如果您已经在字典中有数据,那么您的第一条评论显然是错误的 - 您还需要将键与值相关联.也许不是*这个*特定的代码,但这是无关紧要的.如果由于其他原因你已经有了`Dictionary',你应该使用它. (8认同)
  • 你知道Dictionary有一个ContainsKey函数吗?你为什么要复制数据? (4认同)
  • @halivingston在这种情况下使用HashSet.很明显,*就是你所需要的一切. (3认同)
  • 好,谢谢.我现在实际上有一个HashSet <TKey>,还有一个Dictionary <Tkey,TValue>的副本也在内存中.我首先.在HashSet上包含,然后在Dictionary <TKey,TValue>中检索值.我现在有无限的记忆,但很快我担心我的记忆会被限制,我们的团队会要求我在记忆中删除这些重复的东西,此时我将被迫使用Dictionary <TKey,TValue>. (2认同)

rip*_*lan 7

来自Dictionary <TKey,TValue>的MSDN文档

“通过使用其键检索值非常快,接近O(1),因为Dictionary类是作为哈希表实现的。

带有注释:

“检索速度取决于为TKey指定的类型的哈希算法的质量”

我知道您的问题/帖子很旧-但是在寻找类似问题的答案时,我偶然发现了这个问题。

希望这可以帮助。向下滚动到“ 备注”部分以获取更多详细信息。 https://msdn.microsoft.com/zh-CN/library/xfhwa508(v=vs.110).aspx


Rei*_*l-- 6

该问题接受的答案并不能有效回答该问题!它恰好给出了正确的答案,但他们提供的证据并未显示该答案。

该答案表明,在 aDictionary或上进行键查找HashSet比在 a 中查找要快得多List。这是事实,但并不有趣,也不令人惊讶,也不能证明它们具有相同的速度。

我运行了下面的代码来比较查找时间,我的结论是它们实际上是相同的速度。(或者至少,如果有任何差异,那么差异完全在该速度的标准偏差之内)

具体来说,在这个测试中,对于我来说,100,000,000 次查找花费了 10 到 11.5 秒。

测试代码:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)