1. 程式人生 > >C#Dictionary源碼

C#Dictionary源碼

codes 表數據 長度 空間 hashtable capacity 初始 obj 素數

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源碼