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 keys{get;}
ICollection 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 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 Keys {get {return new KeyCollection(this);}}
public ValueCollection Values {get {return new ValueCollection(this);}}
public ICollection 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.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.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 c = EqualityComparer.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  给我一个理由  阅读(275)  评论(0)    收藏  举报