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时就可以先找到这些空填进去。

转载于:https://www.cnblogs.com/mcyushao/p/10629599.html

C#Dictionary源码相关推荐

  1. C# Dictionary源码解析

    Dictionary底层原理 本篇文章将介绍C#在.NET下的Dictionary的底层源码,源码都根据自己的理解加上了注释,源码直接到官网即可查看下载https://referencesource. ...

  2. C#要点技术(二) - Dictionary 底层源码剖析

    Dictionary 底层代码 我们知道 Dictionary 字典型数据结构,是以关键字Key 和 值Value 进行一一映射的.Key的类型并没有做任何的限制,可以是整数,也可以是的字符串,甚至可 ...

  3. HashTable详解、源码、扩容、深入理解HashTable、HashTable多线程并发问题

    Hashtable 简介 和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射. Hashtable 继承于Dictionary,实现了Map.Cl ...

  4. jieba分词流程及部分源码解读(一)

    首先我们来看一下jieba分词的流程图: 结巴中文分词简介 1)支持三种分词模式: 精确模式:将句子最精确的分开,适合文本分析 全模式:句子中所有可以成词的词语都扫描出来,速度快,不能解决歧义 搜索引 ...

  5. 一步一步Asp.Net MVC系列_权限管理总结(附MVC权限管理系统源码)

    TZHSWEET:请大家多多反馈问题,我已经在修改中了,已更新版本...... 如果大家遇到数据库附加问题,EF连接字符串问题,请自行配置,如果有bug反馈可以私聊,我的qq:409180955. 项 ...

  6. VVeboTableView 源码解析

    原文链接:http://www.jianshu.com/p/78027a3a2c41 最近在看一些 iOS 性能优化的文章,我找到了 VVeboTableView 这个框架.严格来说这个不属于框架,而 ...

  7. iOS WebviewJavascriptBridge 源码研读笔记

    这两天接近元旦,事情稍微少些,有些时间,索性写点什么,就从最擅长的iOS混合开发写起了,由于iOS开发经验不到四年吧,期间还搞了一年半的前端,有些知识可能还是积累的不足,能力不足,水平有限,可能有谬误 ...

  8. python3.7源码分析-字典

    python字典 Dictionary object implementation using a hash table ,通过描述可知,python的字典就是实现了一个hash表. Python字典 ...

  9. djangorestframework源码分析2:serializer序列化数据的执行流程

    djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-serial ...

最新文章

  1. 创建数据库时指定编码方式
  2. Web服务器和应用程序服务器有什么区别
  3. vue-route+webpack部署单页路由项目,访问刷新出现404问题
  4. NGUI UIRoot原理分析
  5. php对表格的处理,JavaScript_js处理表格对table进行修饰,js处理表格 1、行颜色间隔显示 - phpStudy...
  6. 从Mysql slave system lock延迟说开去
  7. linux shell结构,linux——Shell的控制结构(附shell编写代码和运行结果)
  8. Qt笔记-解决QObject::startTimer: Timers cannot be started from another thread
  9. putty连上l虚拟机中的linux要点
  10. html+css如何提升,用好这20个css技巧快速提升你的CSS技能
  11. CmemDC类 的使用方法
  12. 思博伦仪表SRV4(ISIS)测试指南
  13. 使用虚幻4开发HoloLens的准备工作
  14. 有了这个列表,程序员不愁没练手的小项目了
  15. linux系统下网络吞吐量/CPU占用率/流量控制的测试
  16. 操作系统重要知识清单:一起来搞懂进程呀!!
  17. LDPY Ghost Win7 64位 纯净自选版 V5.0
  18. Android原生Switch禁止滑动实现
  19. 微信小程序IOS sticky 兼容写法
  20. 基于STM32采集CO2(MH-Z19C)传感器数据

热门文章

  1. 百度推出飓风算法,严厉打击恶劣采集
  2. Oracle别名大小写 -----解决方案
  3. php的数组与字符串的转换函数整理
  4. 身份证号码有效性检测算法 ( js版 转 .net版 )
  5. flash,sdram 和 cpu 是 T形连接(类似于争的板子上flash和sdram的拓扑结构) --- FLASH搭上SDRAM,并不是你想象的那样不用布等长!...
  6. 你应该知道的计算机网络知识
  7. 编译glib-1.2.20-r5出错./libtool: line 297
  8. Android开发之使用SharedPreferences实现QQ登陆的选项框记忆功能(源代码分享)
  9. Android Studio -添加你见过的最牛Log*神器*
  10. (AOSP)repo checkout指定版本