Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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# 创建哈希集的最坏情况复杂性<;int>;收藏_C#_.net_Complexity Theory - Fatal编程技术网

C# 创建哈希集的最坏情况复杂性<;int>;收藏

C# 创建哈希集的最坏情况复杂性<;int>;收藏,c#,.net,complexity-theory,C#,.net,Complexity Theory,我有一个int值的集合,我用它以以下方式填充HashSet- var hashSet = new HashSet<int>(myIEnumerable); var hashSet=新hashSet(myIEnumerable); 假设迭代IEnumerable是O(n),那么以这种方式创建HashSet的最坏情况复杂度是多少?您可以通过在集达到最大大小时提供所有散列到同一个bucket的对象,将最坏情况带到O(n^2)。例如,如果传递一个17519ints的序列,该序列构造为 x

我有一个
int
值的集合,我用它以以下方式填充
HashSet
-

var hashSet = new HashSet<int>(myIEnumerable);
var hashSet=新hashSet(myIEnumerable);

假设迭代
IEnumerable
O(n)
,那么以这种方式创建
HashSet
最坏情况复杂度是多少?

您可以通过在集达到最大大小时提供所有散列到同一个bucket的对象,将最坏情况带到
O(n^2)
。例如,如果传递一个17519
int
s的序列,该序列构造为

x[i] = i * 17519
对于介于1和17519之间(含1和17519之间)的
i
,在Microsoft实施
HashSet
时,所有数字都将散列到初始存储桶,以
O(N^2)
插入:

var h = new HashSet<int>(Enumerable.Range(1, 17519).Select(i => i*17519));
varh=newhashset(Enumerable.Range(117519)。选择(i=>i*17519));

设置呼吸点,并在调试器中检查
h
。查看原始视图/非公共成员/m_bucket。请注意,初始存储桶有17519个元素,而其余17518个元素都有零。

文档实际上说明:

此构造函数是一个O(n)操作,其中n是 集合参数中的元素


对退化哈希代码(常数)的快速实验表明它是二次的

for(int n=0;n<100;n++)
{
    var start=DateTime.UtcNow;
    var s=new HashSet<Dumb>(Enumerable.Range(0,n*10000).Select(_=>new Dumb()));
    Console.Write(n+" ");
    Console.WriteLine((int)((DateTime.UtcNow-start).TotalSeconds*10));
}


现在有人声称,对于int,不会出现
HashCode
的多次冲突。虽然从技术上讲这是正确的,但影响性能的不是哈希代码的冲突,而是bucket索引的冲突。我认为
HashSet
使用了类似于
bucket=(hash&0x7FFFFFFF)%Capacity的东西。因此,如果您添加一个整数序列,它是首选存储桶大小的倍数,它仍然会非常慢。

如果它是O(N^2),我不会感到惊讶,但是对于非摊销的最坏情况复杂性呢?如果您假设自定义时间的
GetHashCode
,则可以强制执行比O(N^2)更坏的时间。例如,您可以有一个永远不会返回的
GetHashCode
,永远无法完成任务,或者您可以有一个
GetHashCode
方法,该方法需要
O(n^2)
时间进行计算,因此,使
HashSet
方法变得更糟糕。@Servy我的观点是,由于您无法控制
Int32
的.NET的
GetHashCode
,因此您无法强制
将新的HashSet(myIEnumerable)
从OP放入
O(N^2)
区域。当您控制
GetHashCode
时,您可以强制
HashSet
无限期地阻塞:)
HashSet
是中间路线:您所能做的最糟糕的事情是
O(N^2)
通过为.NET实现
Int64.GetHashCode
提供一个特别糟糕的序列。对于
int
s,您仍然可以创建bucket索引的冲突。只需添加容量倍数为
的整数即可。在这种情况下,我期望O(n^2)加法性能,但我太懒了,无法计算出
HashSet
的首选容量。但这是最坏情况下的复杂度还是摊销后的复杂度?@ughtsegment您的意思是“平均”复杂度,而不是“摊销”。“摊余”用于有时成本较高(例如支持存储翻倍)而其余成本较低的业务。这一概念与平均与最坏情况是正交的。要补充到CodeInChaos的答案中,它既是最坏的情况,也是分摊的复杂性。(考虑到他解释了为什么两者都有可能,我在这里说明的是实际情况。)不,一般来说,最坏的情况当然是二次的,但这适用于具有相同GetHashCode()输出的对象。我想知道int的情况。@JeppeStigNielsen我使用.NET Reflector来了解
HashSet
如何获得它在散列计算中使用的模值。我使用这些信息向构造函数提供了各种值,这些值都属于同一个索引,在我的测试中,性能下降几乎是完全二次的。看起来最坏的情况下的复杂性实际上是
O(n^2)
,即使哈希值中没有冲突。如果所有对象都返回相同的哈希代码,那么由于冲突,这就是O(n*n)。但是OP的问题是关于int的集合。所以我想知道选择一对具有相同哈希代码的int有多困难(可能?),我不认为您执行的测试与我在问题中描述的测试相同。我特别感兴趣的是将包含已知数量元素的集合传递给
HashSet
构造函数的最坏情况复杂性,而不是多个
Add
调用的复杂性。@SergeyS
int
是少数没有冲突的类型之一。可能的
int
值的数量不大于可能的
int
值的数量,因此
int
值的哈希代码对于不同的值实际上是唯一的。(换句话说,它的散列码可以自己返回。)其他类型,如
byte
char
的值也小于
int
,因此不会发生冲突。即使使用它,也可能导致桶索引发生冲突。完成任务更烦人@这和构造函数是一样的。请参阅更新的代码。
0 0
1 8
2 34
3 73
4 131