C# Dictionary的底層實現解析


前言:很多文章描述過於復雜故整理之。

1C# Dictionary設計思想:

1.1 數據結構

  • 創建大小為size的數組entries(用來存放字典元素--以下稱:entry)
  • 創建桶buckets數組記錄entry的index(大小和entries保持一致)
  • entry結構體:hash、nextIndex(下個entry的index)、key、value

1.2 數據維護(邏輯)

  • 添加entry時,計算該entry hashCode落在桶的位置(規則是hashCode對桶求余)
  • 當出現落在的位置(桶)里已經有別的“index”了,那么這些沖突的index根據先來后到建立單鏈表(即鏈地址法--開放地址法、鏈地址法、建立溢出區、再哈希法4大方法之一) 可以發現,最理想的狀態是,每個entry一一對應的落在buckets數組上是最划算的(查詢等消耗最低)。
  • 當entries數組長度不夠用時擴容,buckets也需要同步擴容。
  • 記錄freeCount,freeCount == count(entries的)-Count(字典的)
  • 字典有個版本字段,增刪改都會導致+1。(意義:比如遍歷的過程是否版本被修改--增刪)(freeList;//記錄最近一次remove的實體的idx)

1.3 鏈地址圖示--桶沖突

1.4 部分源碼例子

      private void Resize(int newSize, bool forceNewHashCodes) {
            Contract.Assert(newSize >= entries.Length);
            //創建新的桶數組
            int[] newBuckets = new int[newSize];
            for (int i = 0; i < newBuckets.Length; i++) newBuckets[i] = -1;
            //創建新的實體數組
            Entry[] newEntries = new Entry[newSize];
            //拷貝實體數組
            Array.Copy(entries, 0, newEntries, 0, count);
            //強制重新計算hashCode
            if(forceNewHashCodes) {
                for (int i = 0; i < count; i++) {
                    if(newEntries[i].hashCode != -1) {
                        newEntries[i].hashCode = (comparer.GetHashCode(newEntries[i].key) & 0x7FFFFFFF);
                    }
                }
            }
            for (int i = 0; i < count; i++) { 
                if (newEntries[i].hashCode >= 0) {
                    //當hashCode大於-1(該元素有值),賦值桶的值
                    int bucket = newEntries[i].hashCode % newSize;
                    newEntries[i].next = newBuckets[bucket];
                    newBuckets[bucket] = i;
                }
            }
            buckets = newBuckets;
            entries = newEntries;
        }

Find操作

       private int FindEntry(TKey key) {
            ...
           int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
           //對應的桶拿到該桶位置最近一次的實體的idx, 遍歷桶位置的單鏈表,如果對應的key和參數key相等,則return
           for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
               if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
            }
            ...
            return -1;
        }

建議查看源碼深入理解

擴展:
https://www.cnblogs.com/InCerry/p/10325290.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM