private struct Entry
{
public int hashCode; // HashCode的低31位,低31位具有唯一性,-1表示这个Entry未占用
public int next; // 下一个Entry的索引,-1表示这个Entry是单向链表的末尾
public TKey key; // Key of entry
public TValue value; // Value of entry
}
- 数组Buckets,当添加元素时,元素Key的HashCode对Buckets长度取模,取模结果m冲突的元素使用单向链表方式存储,注意并非存在单向链表数据结构,而链表的首位Entry的Index存储在Buckets下标m的位置。
- 数组Entrys,存储实际的数据。
- Bucket命名挺有意思,木桶的每一片表示所有取模结果冲突的元素。
-
private int FindEntry(TKey key)
{
if( key == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets != null) {
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; // 计算出HashCode的低31位
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) { // i的初始值是单向链表的头部元素的index,从Buckets读取,然后遍历单向链表
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i; // 找到了元素
}
}
return -1;
}
private void Insert(TKey key, TValue value, bool add)
{
if( key == null ) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets == null) Initialize(0); // 初始化,size只能是质数,所以是1
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
int targetBucket = hashCode % buckets.Length;
#if FEATURE_RANDOMIZED_STRING_HASHING
int collisionCount = 0; // 冲突数量
#endif
for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) {
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) {
if (add) { // 如果是add,且该Key已经存在,则抛出异常
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
}
entries[i].value = value; // 不是add,赋值Value
version++;
return;
}
#if FEATURE_RANDOMIZED_STRING_HASHING
collisionCount++; // 冲突数量加1
#endif
}
int index;
if (freeCount > 0) { // 如果被移除数量大于0
index = freeList; // 被移除元素也是用单向链表存储
freeList = entries[index].next; // 链表第一个元素将被占用,将第二个元素的Index赋值给freeList
freeCount--; // 被移除数量减1
}
else { // 如果被移除数量小于或等于0
if (count == entries.Length) // 如果当前数量等于Entrys长度
{
Resize(); // 扩容,注意扩容需要重新计算TargetBucket
targetBucket = hashCode % buckets.Length;
}
index = count; // 当前实际元素数量作为Index
count++; // 将要插入元素,数量加1
}
entries[index].hashCode = hashCode;
entries[index].next = buckets[targetBucket]; // 将之前取模结果冲突的元素所在单向链表的首位修改为第二位
entries[index].key = key;
entries[index].value = value;
buckets[targetBucket] = index; // 将当前插入元素作为取模结果冲突的元素所在单向链表的首位
version++;
#if FEATURE_RANDOMIZED_STRING_HASHING
#if FEATURE_CORECLR
// In case we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
// in this case will be EqualityComparer<string>.Default.
// Note, randomized string hashing is turned on by default on coreclr so EqualityComparer<string>.Default will
// be using randomized string hashing
if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default) // 如果冲突数量大于阈值,则扩容,避免某个取模结果冲突的元素过多影响查找效率
{
comparer = (IEqualityComparer<TKey>) EqualityComparer<string>.Default;
Resize(entries.Length, true);
}
#else
if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(comparer))
{
comparer = (IEqualityComparer<TKey>) HashHelpers.GetRandomizedEqualityComparer(comparer);
Resize(entries.Length, true);
}
#endif // FEATURE_CORECLR
#endif
}