知其所以然~字典的数据结构
Dictionary和hashtable用法有点相似,他们都是基于键值对的数据集合,但实际上他们内部的实现原理有很大的差异,
先简要概述一下他们主要的区别,稍后在分析Dictionary内部实现的大概原理。
区别:
- Dictionary支持泛型,而Hashtable不支持。
- Dictionary没有装填因子(Load Facto)概念,当容量不够时才扩容(扩容跟Hashtable一样,也是两倍于当前容量最小素数,比如当前数组长度是3,那么新数组长度为7(2x3=6,比6大的最小素数是7),Hashtable是“已装载元素”与”bucket数组长度“大于装载因子时扩容。
- Dictionary内部的存储value的数组按先后插入的顺序排序,Hashtable不是。
- 当不发生碰撞时,查找Dictionary需要进行两次索引定位,Hashtable需一次,。
Dictionary采用除法散列法来计算存储地址,想详细了解的可以百度一下,简单来说就是其内部有两个数组:buckets数组和entries数组(entries是一个Entry结构数组),entries有一个next用来模拟链表,该字段存储一个int值,指向下一个存储地址(实际就是bukets数组的索引),当没有发生碰撞时,该字段为-1,发生了碰撞则存储一个int值,该值指向bukets数组.
内部实现
下面跟上次一样,按正常使用Dictionary时,看内部是如何实现的。
- 实例化一个Dictionary
Dictionary<string,string> dic=new Dictionary<string,string>();
- 调用Dictionary默认无参构造函数。
- 初始化Dictionary内部数组容器:buckets int[]和entries<T,V>[],分别分配长度3。(内部有一个素数数组:3,7,11,17....如图:);
- 向dic添加一个值,dic.add("a","abc");
- a, 将bucket数组和entries数组扩容3个长度。
- b, 计算"a"的哈希值,
- c, 然后与bucket数组长度(3)进行取模计算,假如结果为:2
- d, 因为a是第一次写入,则自动将a的值赋值到entriys[0]的key,同理将"abc"赋值给entriys[0].value,将上面b步骤的哈希值赋值给entriys[0].hashCode,
entriys[0].next赋值为-1,hashCode赋值b步骤计算出来的哈希值。 - e, 在bucket[2]存储0。
- 通过key获取对应的value, var v=dic["a"];
- a, 先计算"a"的哈希值,假如结果为2,
- b,根据上一步骤结果,找到buckets数组索引为2上的值,假如该值为0.
- c, 找到到entriys数组上索引为0的key,
- 如果该key值和输入的的“a”字符相同,则对应的value值就是需要查找的值。
- 如果该key值和输入的"a"字符不相同,说明发生了碰撞,这时获取对应的next值,根据next值定位buckets数组(buckets[next]),然后获取对应buckets上存储的值在定位到entriys数组上,......,一直到找到为止。
- 如果该key值和输入的"a"字符不相同并且对应的next值为-1,则说明Dictionary不包含字符“a”。
Dictionary里的其他方法就不说了,各位可以自己去看源码,下面来通过实验来对比Hashtable和Dictionary的添加和查找性能,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2017-07-12 DotNetCore跨平台~服务总线_事件总线的重新设计
2017-07-12 DotNetCore跨平台~问题~NETCoreAPP, Version=v1.0' compatible with one of the target runtimes: 'win10-x64
2017-07-12 DotNetCore跨平台~EFCore连接Mysql的方式
2017-07-12 DotNetCore跨平台~文章索引~永久更新
2016-07-12 Lind.DDD.IoC(大叔推荐)~在服务定位器中引入IoC容器~容器的适配器
2013-07-12 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常
2012-07-12 爱上MVC3系列~使用@需要注意的地方