参考-高薪面试必备:浅析C# Dictionary实现原理_Hash
字典内部有两个主要的数组,一个是Entry结构体数组-其中存储hash值、键值对、发生冲突指向的上一个Entry位置,一个是buckets数组-存放对应Entry下标
Add操作时
我们假设dictionary.Add("a","b") ,其中 a的hash值为6,桶的长度为4,根据hash算法hashCode % buckets.Length,求出index=2,即落在buckets[2],更新值buckets[2]=0,Entry[0]存入对应数据
继续执行一个 Add操作, dictionary.Add("c","d") ,假设 GetHashCode(“c”)=6 ,最后 6 % 4 = 2 。最后桶的 index 也是2,则更新buckets[2]=1,Entry[1]存入对应数据,并且Entry[1].next=0;
Find操作时
假设我们查找关键字a,由前面得出index=2,找到buckets[2]的值为1,去到Entry[1]中查找键为b,不是我们要找的a,由next查找下标为0的Entry[0],至此找到键为a的数据
Remove操作
// 1. 通过key获取hashCode
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
// 2. 取余获取bucket位置
int bucket = hashCode % buckets.Length;
// last用于确定是否当前bucket的单链表中最后一个元素
int last = -1;
// 3. 遍历bucket对应的单链表
for( int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next)
{
if(entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
{
if(last < 0)
{
buckets[bucket] = entries[i].next;
}
else
{
entries[last].next = entries[i].next;
}
}
}
扩容操作:字典扩容取小于2*当前长度的最小质数,最大程度减少哈希冲突发送