Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# HashSet的查找时间复杂度是多少<;T>;(iQualityComparer<;T>;)?_C#_Runtime_Complexity Theory_Hashset - Fatal编程技术网

C# HashSet的查找时间复杂度是多少<;T>;(iQualityComparer<;T>;)?

C# HashSet的查找时间复杂度是多少<;T>;(iQualityComparer<;T>;)?,c#,runtime,complexity-theory,hashset,C#,Runtime,Complexity Theory,Hashset,在C#NET中,我喜欢使用hashset,因为它们的查找时间复杂度为O(1)。如果要查询的数据很大,我通常更喜欢使用哈希集而不是列表,因为它具有这种时间复杂性 让我困惑的是HashSet的构造函数,它将IEqualityComparer作为参数: 在上面的链接中,注释指出“构造函数是一个O(1)操作”,但如果是这样,我想知道查找是否仍然是O(1) 特别是,在我看来,如果我要编写一个比较器传递给哈希集的构造函数,每当我执行查找时,都必须对每个键执行比较器代码,以检查是否存在匹配项。这不是O(1)

在C#NET中,我喜欢使用hashset,因为它们的查找时间复杂度为O(1)。如果要查询的数据很大,我通常更喜欢使用哈希集而不是列表,因为它具有这种时间复杂性

让我困惑的是HashSet的构造函数,它将IEqualityComparer作为参数:

在上面的链接中,注释指出“构造函数是一个O(1)操作”,但如果是这样,我想知道查找是否仍然是O(1)

特别是,在我看来,如果我要编写一个比较器传递给哈希集的构造函数,每当我执行查找时,都必须对每个键执行比较器代码,以检查是否存在匹配项。这不是O(1),而是O(n)

当元素添加到集合中时,实现是否在内部构造查找表


一般来说,如何确定有关.NET数据结构复杂性的信息?

哈希集通过哈希(通过
IEqualityComparer.GetHashCode
)对插入的对象进行哈希处理,并根据哈希将对象放入桶中。桶本身存储在一个数组中,因此是O(1)部分

例如(这不一定就是C#实现的工作方式,它只是提供了一种味道),它获取散列的第一个字符,并将以1开头的散列的所有内容抛出到bucket 1中。散列2、bucket 2等等。在这个bucket中是另一个bucket数组,它被散列中的第二个字符分割。对于散列中的每个字符,依此类推

现在,当您查找某个内容时,它会对其进行散列,并跳转到相应的桶中。它必须执行多个数组查找(哈希中的每个字符一个),但不会随着N的增加而增长,N是您添加的对象数,因此为O(1)


对于您的另一个问题,这里有一篇博文,内容涉及大量集合操作的复杂性:

这取决于您的
IEqualityComparer
实现提供的哈希函数(
GetHashCode()
)的质量。理想的散列函数应该提供分布均匀的随机散列码集。这些散列码将用作索引,允许将键映射到值,因此逐键搜索值会更有效,尤其是当键是复杂的对象/结构时

必须对每个键执行比较器代码才能进行检查 看看有没有火柴。这不是O(1),而是O(n)

这不是哈希表的工作方式,这是一种简单的bruteforce搜索。在使用哈希表的情况下,您可以使用更智能的方法,使用索引搜索(哈希代码)。

如果您通过IEqualityComparer,则查找仍然是O(1)。哈希集仍然使用与未传递IEqualityComparer相同的逻辑;它只使用IEqualityComparer的GetHashCode和Equals实现,而不是System.Object的实例方法(或相关对象提供的覆盖)

如果我要编写一个比较器来传递给哈希集的构造函数,那么每当我执行查找时,都必须在每个键上执行比较器代码,以检查是否存在匹配项。这不是O(1),而是O(n)

让我们调用您正在搜索的“查询”值

您能解释一下为什么您认为必须对每个键执行比较器,以查看它是否与查询匹配吗


这种看法是错误的。(当然,除非比较器提供的哈希代码对于每个键都是相同的!)搜索算法对哈希代码与查询哈希代码匹配的每个键执行相等比较器,对哈希表中的桶数进行模化。这就是哈希表获得O(1)查找时间的方式

当元素添加到集合中时,实现是否在内部构造查找表

通常,我如何确定有关.NET数据结构复杂性的信息


阅读文档。

实际上,
哈希集的查找时间并不总是O(1)

正如其他人已经提到的,HashSet使用
IEqualityComparer.GetHashCode()

现在考虑一个结构或对象,它总是返回相同的哈希代码<代码> x>代码> < 如果将n个项目添加到哈希集中,则其中将有n个项目具有相同的哈希(只要对象不相等)。

因此,如果要检查哈希代码为
x
的元素是否存在于哈希集中,它将对哈希代码为
x
的所有对象运行相等性检查,以测试哈希集是否包含该元素

,只需使用不同的输入大小对其进行测试,并查看查找时间是否缩放或保持不变。不过,很确定文档是正确的。一旦构造函数结束,它仍然是一个哈希集。不保留源数据结构本身(例如,在这种情况下没有“代理”)。查找是O(1),但插入是摊销O(1)。@Kirby,这一点不变。您可以从IEnumerable构建哈希集,或者稍后单独添加元素:唯一可能不同的是容量,它不会影响[lookup]的时间复杂性。只需了解一下哈希表的实际工作原理:(哈希集是一个简化的哈希表)@sll哈希到bucket中总是会发生;如果没有碰撞,水桶可以装一件东西。谢谢你,斯科特。出于某种原因,您的解释对我来说非常清楚,特别是关于调用“IEqualityComparer.GetHashCode”的部分。现在,这很有意义了。@Kirby这里的基本解释是正确的,但基于字符的哈希实现却不正确。事实上,只有一个数组索引操作可以为哈希代码检索正确的bucket(无跳跃);索引计算为
hashCode%bucket.Length
。是。有一张素努的桌子