Dictionary

Dictionary与hashtable的区别:dictionary支持泛型。

通常处理哈希冲突的方法有:开放地址法,再哈希法,链地址法,建立一个公共栈区等。

在哈希表上进行查找的过程和哈希造表的过程基本一致。给定k值,根据造表时设定的哈希函数求得哈希地址,若表中此位置没有记录,则查找不成功;否则比较关键字,若和给定值相等,则查找成功;否则根据冲突的方法寻找下一地址,直到哈希表中某个位置为空或者表中所填关键值等于给定值为止。

Dictionary使用的哈希函数是除留余数法 h = F(k) % m;m为哈希表长度。

Dictionary使用的解决冲突的方法是拉链法,又称链地址法

拉链法的原理:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。

private struct Entry {

public int hashCode;    //31位散列值,32最高位表示符号位,-1表示未使用

public int next;        //下一项的索引值,-1表示结尾

public TKey key;        //键

public TValue value;    //值

}

private int[] buckets;//内部维护的数据地址

private Entry[] entries;//元素数组,用于维护哈希表中的数据

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;

初始化函数

该函数用于,初始化的数据构造

private void Initialize(int capacity) {

//根据构造函数设定的初始容量,获取一个近似的素数

int size = HashHelpers.GetPrime(capacity);

buckets = new int[size];

for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;

entries = new Entry[size];

freeList = -1;

}

size 哈希表的长度是素数,可以使元素更均匀地分布在每个节点上。GetPrime(capacity)返回离>capacity最近的质数。维护了个质数数组,初始capacity为0,返回3(初始大小)

buckets 中的节点值,-1表示空值。

freeList 为-1表示没有空链表。

buckets 和 freeList 所值指向的数据其实全是存储于一块连续的内存空间(entries )之中。

//取hashcode后还与0x7FFFFFFF做了个与操作,0x7FFFFFFF这就是int32.MaxValue的16进制,换成二进制是‭01111111111111111111111111111111‬,第1位是符号位,也就是说comparer.GetHashCode(key) 为正数的情况下与0x7FFFFFFF做 & 操作结果还是它本身,如果取到的hashcode是负数,负数的二进制是取反再补码,所以结果得到的是0x7FFFFFFF-(-hashcode)+1,结果是正数。其实简单来说,它的目的就是高性能的取正数。‬‬

扩容 //Resize消耗不低,比List<T>的要大,不光要copy元素,还要重建bucket。

private void Resize() {

Resize(HashHelpers.ExpandPrime(count), false);

}

private void Resize(int newSize, bool forceNewHashCodes) {

Contract.Assert(newSize >= entries.Length);

//重新初始化一个比原来空间还要大2倍左右的buckets和Entries,用于接收原来的buckets和Entries的数据

int[] newBuckets = new int[newSize];

for (int i = 0; i < newBuckets.Length; i++) newBuckets[i] = -1;

Entry[] newEntries = new Entry[newSize];

//数据搬家

Array.Copy(entries, 0, newEntries, 0, count);

//将散列值刷新,这是在某一个单链表节点数到达一个阈值(100)时触发

if(forceNewHashCodes) {

for (int i = 0; i < count; i++) {

if(newEntries[i].hashCode != -1) {

newEntries[i].hashCode = (comparer.GetHashCode(newEntries[i].key) & 0x7FFFFFFF);

}

}

}

//单链表数据对齐,无关顺序

for (int i = 0; i < count; i++) {

if (newEntries[i].hashCode >= 0) {

int bucket = newEntries[i].hashCode % newSize;

newEntries[i].next = newBuckets[bucket];

newBuckets[bucket] = i;

}

}

buckets = newBuckets;

entries = newEntries;

}

Dictionary为了性能并没有在Remove做重建,而是把位置空出来,这样节省大量时间。freeList和bucket类似(一样喜新厌旧),总是指向最新空出来的entry的index,而entry的next又把所有空的entry连起来了。这样insert时就可以先找到这些空填进去。

C#Dictionary源码的更多相关文章

  1. C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法、再哈希法、链地址法、建立一个公共溢出区等

    C# Dictionary源码剖析 参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/ ...

  2. java.util.Dictionary源码分析

    Dictionary是一个抽象类,Hashtable是它的一个子类. 类的声明:/** The <code>Dictionary</code> class is the abs ...

  3. C# Dictionary源码剖析

    参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/wangjun1234/p/3719 ...

  4. 从Dictionary源码看哈希表

    一.基本概念 哈希:哈希是一种查找算法,在关键字和元素的存储地址之间建立一个确定的对应关系,每个关键字对应唯一的存储地址,这些存储地址构成了有限.连续的存储地址. 哈希函数:在关键字和元素的存储地址之 ...

  5. .net源码分析 - ConcurrentDictionary<TKey, TValue>

    List源码分析 Dictionary源码分析 ConcurrentDictionary源码分析 继上篇Dictionary源码分析,上篇讲过的在这里不会再重复 ConcurrentDictionar ...

  6. Java 容器源码分析之Map-Set-List

    HashMap 的实现原理 HashMap 概述 HashMap 是基于哈希表的 Map 接口的非同步实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.此类不保证映射的顺序 ...

  7. Java基础——HashTable源码分析

    HashTable是基于哈希表的Map接口的同步实现 HashTable中元素的key是唯一的,value值可重复 HashTable中元素的key和value不允许为null,如果遇到null,则返 ...

  8. .net源码分析 – Dictionary<TKey, TValue>

    接上篇:.net源码分析 – List<T> Dictionary<TKey, TValue>源码地址:https://github.com/dotnet/corefx/blo ...

  9. 源码分析之Dictionary笔记

    接下来我们一步步来熟悉 Dictionary的底层结构实现,下面的MyDictionary等同于源码中的Dictionary看待. 首先我们定义一个类 MyDictionary,类中定义一个结构Ent ...

随机推荐

  1. oracle数据库组件列表及相关的数据字典视图

    Component Data dictionary tables and views Database V$DATABASE, V$VERSION, V$INSTANCEShared server V ...

  2. LSTM/RNN中的Attention机制

    一.解决的问题 采用传统编码器-解码器结构的LSTM/RNN模型存在一个问题,不论输入长短都将其编码成一个固定长度的向量表示,这使模型对于长输入序列的学习效果很差(解码效果很差). 注意下图中,ax ...

  3. Vue 双向数据绑定、事件介绍以及ref获取dom节点

    vue是一个MVVM的框架 M model V view MVVM  model改变会影响视图view,view改变会影响model 双向数据绑定必须在表单里面使用 //我发现在谷歌浏览器翻译后的网页 ...

  4. Fiddler手机抓包软件简单使用--将h5效果显示在手机

    此文章是博主自己所写,转载请注明出处 一.简介 Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据. ...

  5. redis-单线程架构

    单线程模型: redis中的数据结构并不全是简单的kv,还有list.hash等复杂的结构,这些结构很可能会进行细粒度的操作,比如在很长的列表偶棉添加一个元素,在hash当中或者删除一个对象,这样的一 ...

  6. win10 64位,家庭版,C++,ini配置说明

      #include<windows.h> #include<iostream> #include <atlstr.h> using namespace std; ...

  7. input输入限制

    1:只能输入两位小数点:function keepTwoPointNum(that){ var val=that.value; if(isNaN(val)){ $(that).val(''); ret ...

  8. 第四篇、Python文件处理

    1.文件操作 1) 文件操作流程 a. 打开文件,得到文件句柄并赋值给一个变量 b. 通过句柄对文件进行操作 c. 关闭文件 f=open('a.txt','r',encoding='utf-8') ...

  9. Delphi TXLSReadWriteII导出Excel

    TXLSReadWriteII导出Excle (有点复杂,可以自己简化一下,直接从项目中抓取的) procedure TformSubReport.DataToExcel(_Item: Integer ...

  10. SVG绘制太极图

    思路:先画一整个圆,填充颜色为黑色,再用一个边框和填充颜色均为白色的长方形覆盖右半边的半圆,再以同一个圆心,相同半径绘制一整个圆,该圆的边线颜色为黑色,没有填充颜色,最后常规操作再画四个小圆 源代码: ...