最糟糕的情况是从集合</int>创建HashSet <int>的复杂性

时间:2012-12-28 15:13:21

标签: c# .net complexity-theory

我有一组int值,我用以下方式填充HashSet<int> -

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

假设迭代IEnumerableO(n),那么以这种方式创建HashSet<int>最坏情况的复杂性是什么?

3 个答案:

答案 0 :(得分:7)

文档实际上说明了:

  

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

http://msdn.microsoft.com/en-us/library/bb301504.aspx

答案 1 :(得分:5)

通过在集合达到其最大大小时向同一个存储桶提供所有散列的对象,可以将最坏情况带到O(N^2)。例如,如果传递构造为

的17519 int s序列
x[i] = i * 17519

对于介于1和17519之间的i,所有数字都将散列到Microsoft HashSet<int>实现的初始存储桶中,并O(N^2)插入:

var h = new HashSet<int>(Enumerable.Range(1, 17519).Select(i => i*17519));

设置brea kpoint,并检查调试器中的h。查看Raw View /非公共成员/ m_buckets。观察到初始存储桶有17519个元素,而其余的17518都有零。

答案 2 :(得分:2)

使用简并哈希码(常量)的快速实验表明它是二次的。

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));
}

输出:

0 0
1 8
2 34
3 73
4 131

现在有些人声称你没有得到HashCode的多次碰撞。虽然这在技术上是正确的,但对性能至关重要的不是HashCode的碰撞,而是铲斗索引的碰撞。我认为HashSet<T>使用类似bucket = (hash&0x7FFFFFFF)%Capacity的内容。因此,如果你添加一个整数序列,它是一个首选桶大小的倍数,它仍然会很慢。