我不确定这是否是正确的问题,但请不要杀我:)
我和一位朋友争论过C#的字典...... 她告诉我,如果我让一个元素说字典。并且密钥的哈希码是100000,那么字典的内部数组将是100000的大小!
这是真的吗?我试图在Google上找到答案,但由于某些原因我找不到这个问题。
答案 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);
}
即。 1}}根本没有被默认构造函数直接或间接调用。
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,如前面的答案所述。