C#Dictionary源碼
Dictionary
Dictionary與hashtable的區別:dictionary支持泛型。
通常處理哈希沖突的方法有:開放地址法,再哈希法,鏈地址法,建立一個公共棧區等。
在哈希表上進行查找的過程和哈希造表的過程基本一致。給定k值,根據造表時設定的哈希函數求得哈希地址,若表中此位置沒有記錄,則查找不成功;否則比較關鍵字,若和給定值相等,則查找成功;否則根據沖突的方法尋找下一地址,直到哈希表中某個位置為空或者表中所填關鍵值等於給定值為止。
Dictionary使用的哈希函數是除留余數法 h = F(k) % m;m為哈希表長度。
Dictionary使用的解決沖突的方法是拉鏈法,又稱鏈地址法
拉鏈法的原理:將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數 組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。
private struct Entry {
public int hashCode; //31位散列值,32最高位表示符號位,-1表示未使用
public int next; //下一項的索引值,-1表示結尾
public TKey key; //鍵
public TValue value; //值
}
private int[] buckets;//內部維護的數據地址
private Entry[] entries;//元素數組,用於維護哈希表中的數據
private int count;//元素數量
private int version;
private int freeList;//空閑的列表
private int freeCount;//空閑列表元素數量
private IEqualityComparer<TKey> comparer;//哈希表中的比較函數
private KeyCollection keys;//鍵集合
private ValueCollection values;//值集合
private Object _syncRoot;
初始化函數
該函數用於,初始化的數據構造
private void Initialize(int capacity) {
//根據構造函數設定的初始容量,獲取一個近似的素數
int size = HashHelpers.GetPrime(capacity);
buckets = new int[size];
for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
entries = new Entry[size];
freeList = -1;
}
size 哈希表的長度是素數,可以使元素更均勻地分布在每個節點上。
buckets 中的節點值,-1表示空值。
freeList 為-1表示沒有空鏈表。
buckets 和 freeList 所值指向的數據其實全是存儲於一塊連續的內存空間(entries )之中。
擴容
private void Resize() {
Resize(HashHelpers.ExpandPrime(count), false);
}
private void Resize(int newSize, bool forceNewHashCodes) {
Contract.Assert(newSize >= entries.Length);
//重新初始化一個比原來空間還要大2倍左右的buckets和Entries,用於接收原來的buckets和Entries的數據
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);
//將散列值刷新,這是在某一個單鏈表節點數到達一個閾值(100)時觸發
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) {
int bucket = newEntries[i].hashCode % newSize;
newEntries[i].next = newBuckets[bucket];
newBuckets[bucket] = i;
}
}
buckets = newBuckets;
entries = newEntries;
}
C#Dictionary源碼