.Net之Dictionary

  • 数据结构实现
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
}
  1. 数组Buckets,当添加元素时,元素Key的HashCode对Buckets长度取模,取模结果m冲突的元素使用单向链表方式存储,注意并非存在单向链表数据结构,而链表的首位Entry的Index存储在Buckets下标m的位置。
  2. 数组Entrys,存储实际的数据。
  3. Bucket命名挺有意思,木桶的每一片表示所有取模结果冲突的元素。
  • 核心成员
  1. 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
     
    }

     

  • 使用场景(未完待续。。。)
posted @ 2020-08-15 22:25  MatrixRuler  阅读(311)  评论(0)    收藏  举报