C#Dictionary内部数组大小

时间:2012-09-28 13:12:05

标签: c# arrays dictionary hashcode internal

我不确定这是否是正确的问题,但请不要杀我:)

我和一位朋友争论过C#的字典...... 她告诉我,如果我让一个元素说字典。并且密钥的哈希码是100000,那么字典的内部数组将是100000的大小!

这是真的吗?我试图在Google上找到答案,但由于某些原因我找不到这个问题。

8 个答案:

答案 0 :(得分:2)

Dictionary的默认构造函数,“具有默认的初始容量”,according to MSDN

它还声明:

  

如果您可以估计集合的大小,则使用指定初始容量的构造函数消除了在向Dictionary添加元素时执行大量调整大小操作的需要。

一个这样的构造函数只需要Int32,它按如下方式初始化内部存储:

  

Dictionary可包含的元素的初始数量。

字典的“默认初始容量”实际上是该类的内部实现细节,因此未在文档或公共API中公开。

使用mscorlib反汇编ilspy并检查默认构造函数,表明它的实现方式如下:

public Dictionary() : this(0, null)
{
}

该链式构造函数实现如下:

public Dictionary(int capacity, IEqualityComparer<TKey> comparer)
{
    if (capacity < 0)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
    }

    if (capacity > 0)
    {
        this.Initialize(capacity);
    }

    this.comparer = (comparer ?? EqualityComparer<TKey>.Default);
}

即。

Initialize()是设置内部存储空间的方法。

实际上,如果您调用默认构造函数,则在您首次添加项目之前,内部存储大小甚至不会被初始化。所以它基本上是零大小。

第一次调用Initialize()时,

Initialize()最终会被调为零值, 这样可以解决问题。

.Add()

private void Initialize(int capacity) { int prime = HashHelpers.GetPrime(capacity); this.buckets = new int[prime]; for (int i = 0; i < this.buckets.Length; i++) { this.buckets[i] = -1; } this.entries = new Dictionary<TKey, TValue>.Entry[prime]; this.freeList = -1; } 返回GetPrime(0),因此3设置为包含三个整数的数组。

this.buckets分配值的行看起来有点奇怪,但我不知道100000在哪里。

简短回答
我认为你的同事错了。

答案 1 :(得分:2)

哈希码(即GetHashCode)用于将项目放在词典使用的桶中。

使用的实际容量基于字典中的元素数量。

使用GetHashCode的伪代码(可能不准确)是这样的。

List<List<KeyValuePair<T,J>>> buckets; // let's assume this get's allocated somewhere (the dictionary allocates this internally)
...
public J GetValueFromDictionary(T key)
{
    int bucketIndex = key.GetHashCode() % buckets.Length;
    return buckets[bucketIndex].Find(x => x.Key == key).Single().Value;
}

答案 2 :(得分:0)

不,不是。 Dictionary<,>类的来源证明了这一点。

答案 3 :(得分:0)

只需使用反射器对代码进行反编译并自行验证。

答案 4 :(得分:0)

不,在该示例中,字典将具有一个具有密钥100000的项目。

因此密钥不会影响字典的大小。

答案 5 :(得分:0)

不,这不是真的。如果我有

Dictionary<int, object[]> dict = new Dictionary<int, object[]>() 
{
    {10000, new object[] { 1, 2, 3, 4 }}
};

此字典将包含一个索引为10000的对象数组,而不是9999个空对象数组插槽,后跟我们在上面输入的对象。答案是否定的,你的朋友错了。

我希望这会有所帮助。

答案 6 :(得分:0)

情况并非如此,因为字典的存储比这复杂得多。此外,哈希码的值,可能是关键,不以任何方式定义词典的大小(我不知道怎么可能是制造)。

现在,让我们分解字典的存储。

  

只要将对象用作Dictionary中的键,就不能以任何影响其哈希值的方式进行更改。根据字典的相等比较器,字典中的每个键必须是唯一的。键不能是空引用(在Visual Basic中为Nothing),但如果值类型TValue是引用类型,则值可以是。

     

Dictionary需要一个相等的实现来确定键是否相等。您可以使用接受comparer参数的构造函数指定IEqualityComparer泛型接口的实现。如果未指定实现,则使用默认的通用相等比较器 EqualityComparer.Default 。如果类型TKey实现System.IEquatable泛型接口,则默认的相等比较器使用该实现。

虽然可能会使用哈希码,因为EqualityComparer.Default被定义为:

  

Default属性检查类型T是否实现System.IEquatable泛型接口,如果是,则返回使用该实现的EqualityComparer。 否则返回一个EqualityComparer,它使用由T提供的Object.Equals和Object.GetHashCode的覆盖。

绝不保证 将成为密钥的生成方式。所以,我希望这可以帮助你进行论证。

最重要的是,散列码无法确定字典的内部大小,字典是可变的,随着项目的添加而增长,如Microsoft所述:

  

Dictionary的容量是Dictionary可容纳的元素数。当元素添加到Dictionary时,通过重新分配内部数组,容量会根据需要自动增加。

你的朋友在争吵之前需要做她的研究。呼!

答案 7 :(得分:0)

作为一个更新,现在Microsoft提供了.NET实现的参考代码,这比进行反编译更容易。专门针对此问题,请参阅

https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs https://referencesource.microsoft.com/#mscorlib/system/collections/hashtable.cs

您可以看到默认容量为3,如前面的答案所述。