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);
}
posted @ 2017-10-19 21:40  给我一个理由  阅读(241)  评论(0编辑  收藏  举报