4. Dictionary HashTable
struct KeyValuePair<TKey,TValue>
public TKey Key{get;}
public TValue Value{get;}
public string ToString(){return [Key,Value]}
IDictionary<TKey,TValue>:ICollection<KeyValuePair<TKey,TValue>>
TValue this[TKey key]{get;set}
ICollection<TKey> keys{get;}
ICollection<TValue> values{get;}
bool ContainsKey(TKey key);
void Add(TKey key,TValue value);
bool Remove(TKey key);
bool TryGetValue(TKey key,out TValue value);
IDictionary:ICollection
Object this[Object key]{get;set;}
ICollection Keys{get;}
ICollection Values{get;}
bool Contains(Object key);
void Add(Object key,Object value);
void Clear();
bool IsReadonly{get;}
bool IsFixedSize{get;}
new IDictionaryEnumerator GetEnumerator();
void Remove(Object key);
IReadOnlyDictionary<TKey,TValue>:IReadOnlyCollection<KeyValuePair<TKey,TValue>>
对比IDictionary<TKey,TValue>的没有Add,Remove两个方法
IEqualityComparer
bool Equals(T x,T y);
int GetHashCode(T obj);
KeyCollection:ICollection
new Enumerator(Dictionary)
因为key其实是保存在entries[]中的entry.key
ValueCollection:ICollection
new Enumerator(Dictionary)
因为value其实是保存在entries[]中的entry.value
Dictionary<TKey,TValue> 1170行,中等水平
private struct Entry{
public int hashCode;
public int next;
public TKey key;
public TValue value;
}
private int[] buckets; //key数组
private Entry[] entries; //value数组
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;
两个集合
int[] buckets; //居然是int[],int应该是综合来看最好的选择
Entry[] entries;
内部两个数组的大小变化
是[3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521,...] 按素数去增长,是为了取余的时候能够不重复,保证key在buckets中是不冲突的,但是为什么没有5呢
insert方法解析
1. 计算key的hashcode
2. 计算targetbucket= hashcode % buckets.Length //计算在第一个数组桶中的索引
3. 在entries中设置数据
next=buckets[targetBucket] //用来连接相同的hashcode的对象的
hashcode=hashcode //记录key的hashcode,是为了在Resize时反向操作,获取key在buckets中的index
key=key, //dict中插入的key
value=value //dict中插入的数据
buckets的值是entries的索引
private void Insert(TKey key,TValue value,bool add){
if(key==null){
throw new ArgumentMentNullException("key");
}
if(buckets==null) Initialize(0); //初始化为3个长度
int hashCode = comparer.GetHashCode(key) & ox7fffffff; //获取正的hashcode
int targetBucket = hashCode % buckets.Length; //求出在buckets中的索引
for(int i=buckets[targetBucket];i>=0;i=entries[i].next){ //
if(entries[i].hashCode == hashCode && comparer.Equals(entries[i].key,key)){ //判断key是否存在
if(add){
throw new ArgumentException();
}
entries[i].value=value;
version++;
return;
}
}
int index;
if(freeCount>0){
index=freeList;
freeList=entries[index].next;
freeCount--;
}
else{
if(count==entries.Length){
Resize();
targetBucket = hashCode % buckets.Length;
}
index = count; //在entries中顺序插入数据的
count ++;
}
entries[index].hashCode = hashCode;
entreis[index].next = buckets[targetBucket];
entries[index].key = key;
entries[index].value = value;
buckets[targetBucket]=index;
}
Insert 实例
这是一种特殊的情况,所有的数据的hashcode都相同但是key本身不同,然后在entries中通过next构成了一个链表,所以本身dictionary中就利用这种方式来解决冲突
count | targetBucket | i=buckets[targetBucket] | freeCount | index=count | entries[index].next | buckets[targetBucket]=index |
---|---|---|---|---|---|---|
1 | 2 | -1 | 0 | 0 | -1 | 0 |
2 | 2 | 0 | 0 | 1 | 0 | 1 |
3 | 2 | 1 | 0 | 2 | 1 | 2 |
4 | 2 | 2 | 0 | 3 | 2 | 3 |
private FindEntry(Tkey key) 方法解析:返回entries中数据索引
containskey(key),this["key"]这些方法都要通过FindEntry()获取
1. 获取key的hashcode
2. hashcode%buckets.length 得到具体的在buckets中的位置,然后其值就是entries中value的索引
3. 根据索引获取value,判断两个数据是否相等
1. hashcode
2. key
4. 如果entries中的Entry的hashcode和key都相等,就表示这个key存在,entries中的的索引了
private Resize():扩展buckets的容量的
这个方法是在需要扩展容量时调用,比如当前容器是3,需要扩展到7时
1. 先得到能否扩展,以及扩展后的容量
2. copy entries到新的newentries中
3. 循环newentries,根据hashcode 计算key的index,然后重建buckets
1. 根据hashcode % 当前容量 得到一个index
2. buckets[index]=i ; //i 就是entries中当前数据的index,这样就完成了 buckets和entris的关联,是逆向重建
4. 将new对象覆盖旧对象
最大的疑问是Entry中next是起什么作用
暂时不知道
Prop
public int Count{get{return count - freeCount;}}
public KeyCollection Keys {get {return new KeyCollection(this);}}
public ICollection<TKey> Keys {get {return new KeyCollection(this);}}
public ValueCollection Values {get {return new ValueCollection(this);}}
public ICollection<TValue> Values {get {return new ValueCollection(this);}}
public TValue this[Tkey key]{
get {
int i = FindEntry(key);
if(i>=0) return entries[i].value;
throw new KeyNotFoundException();
}
set {Insert(key,value,false)}
}
private method
//初始化
private void Initialize(int capacity){
int size = HashHelper.GetPrime(capacity); //return size;
buckets = new int[size];
for(int i=0;i<buckets.Length;i++)buckets[i]=-1;
entries=new Entry[size];
freeList=-1;
}
private void ICollection<KeyValuePair<TKey,TValue>>.Add(KeyValuePair<TKey,TValue> keyValuePair){
Add(KeyValuePair.Key,KeyValuePair.Value);
}
private bool ICollection<KeyValuePair<TKey,TValue>>.Contains(KeyValuePair<TKey,TValue> keyValuePair){
int i = FindEntry(keyValuePair.Key);
if(i>=0 && EqualityComparer<TValue>.Deafult.Equals(entries[i].value,keyValuePair.Value)){
return true;
}
return false;
}
private bool ICollection<KeyValuePair<TKey,TValue>>.Remove(KeyValuePair<TKey,TValue> keyValuePair){
int i = FindEntry(keyValuePair.Key);
if( i >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, keyValuePair.Value)) {
Remove(keyValuePair.Key); //移除key
return true;
}
return false;
}
//复制所有的key,value到数组KeyValuePair<TKey,TValue>[]中
private void CopyTo(KeyValuePair<TKey,TValue>[] array,int index){
Entry[] entries = this.entries;
for(int i=0;i<count;i++){
if(entries[i].hashCode>=0){
array[index++]=new KeyValuePair<TKey,TValue>(entries[i].key,entries[i].value);
}
}
}
private int FindEntry(TKey key){
if(buckets != null){
int hashCode = comparer.GetHashCode(key) & 0x7fffffff;
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;
}
//bool 控制新增和修改
private void Insert(TKey,key,TValue,value,bool add){
if(buckets == null)Initialize(0);
int hashCode = comparer.GetHashCode(key) & 0x7fffffff; //计算key的hash值
int targetBucket = hashCode % buckets.Length;
for(int i=buckets[targetBucket];i>=0;i=entries[i].next){
if(entries[i].hashCode == hashCode && comparer.Equals(entries[i].key,key)){
if(add){
throw new ArgumentException();
}
//修改数据
entries[i].value = value;
version++;
return;
}
}
int index;
if(freeCount>0){
index = freeList;
freeList = entries[index].next;
freeCount--;
}else{
if(count==entries.Length){
Resize();
targetBucket = hashCode % buckets.Length;
}
inex = count;
count++;
}
entries[index].hashCode = hashCode;
entries[index].next = buckets[targetBucket];
entries[index].key = key;
entries[index].value = value;
entries[targetBucket] = index;
}
public method
public void Add(TKey key,TValue value){
Insert(key,value,true);
}
public void Clear(){
if(count>0){
for(int i=0;i<buckets.Length;i++)buckets[i]=-1;
Array.Clear(entries,0,count);
freeList = -1;
count = 0;
freeCount = 0;
version ++;
}
}
public bool ContainsKey(TKey key){
return FindEntry(key)>=0;
}
public bool ContainsValue(TValue value){
if (value == null){
for(int i=0;i<count;i++){
if(entries[i].hashCode>=0&&entries[i].value==null)return true;
}
}else{
EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
for(int i=0;i<count;i++){
if(entries[i].hashCode>=0&&c.Equals(entries[i].value,value))return true;
}
}
return false;
}
public Enumerator GetEnumerator(){
return new Enumerator(this,Enumerator.KeyValuePair);
}
这就是