zoukankan      html  css  js  c++  java
  • 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);
    }
    这就是
  • 相关阅读:
    2251: [2010Beijing Wc]外星联络
    1500 后缀排序
    1492: [NOI2007]货币兑换Cash【CDQ分治】
    P3380 【模板】二逼平衡树(树套树)
    python opencv
    pycharm调试
    pycharm中选择python interpreter
    创建使用pycharm virtualenv
    reload函数
    python3编写发送四种http请求的脚本
  • 原文地址:https://www.cnblogs.com/zhangrCsharp/p/7695576.html
Copyright © 2011-2022 走看看