C# Dictionary的实现原理
在 C# 中,Dictionary<TKey, TValue> 是一个基于哈希表(Hash Table)实现的键值对集合。它提供了高效的插入、删除和查找操作,平均时间复杂度接近 O(1)。下面是 Dictionary 的核心实现原理:
1. Dictionary 的核心数据结构
C# 的 Dictionary<TKey, TValue> 主要由以下几个部分组成:
- 数组(buckets):存储哈希桶(Bucket)的索引。
- 数组(entries):存储键值对(哈希表中的实际数据)。
- 哈希函数(GetHashCode):将键映射到哈希桶。
- 碰撞解决(拉链法):采用 链地址法(Chaining with Linked List)。
- 负载因子(Load Factor):决定何时扩容,默认为 0.75。
数据结构
private int[] buckets; // 哈希桶数组,存储 entry 的索引
private Entry[] entries; // 存储实际的键值对
private int count; // 当前存储的元素个数
private int freeList; // 指向空闲 entry(删除后形成的空位)
private int freeCount; // 空闲 entry 的数量private struct Entry
{public int hashCode; // 计算出的哈希值public int next; // 指向下一个冲突的元素(-1 表示无冲突)public TKey key; // 键public TValue value; // 值
}
2. Dictionary 的主要操作
(1)添加元素
当调用 dictionary.Add(key, value) 时,Dictionary 执行以下步骤:
-
计算哈希值:调用
key.GetHashCode()计算哈希值hashCode。 -
计算索引:对哈希值取模,
index = hashCode % buckets.Length,确定应该存放的桶。 -
检查冲突:
- 如果该桶为空,则直接存储。此时count字段记录字典中元素个数。令bucket[index] = count,然后将内容存储到Entry[count]中,随后count++。
- 如果发生哈希冲突,则使用链地址法存储,即将
entries中的next指向旧的Entry,形成链表。
-
扩容(如有必要):
- 如果
count > capacity * 0.75,则触发扩容,通常是 2 倍扩容。
public void Add(TKey key, TValue value)
{
int hashCode = key.GetHashCode() & 0x7FFFFFFF; // 计算哈希值int index = hashCode % buckets.Length; // 计算桶的索引// 处理哈希冲突:如果桶为空,直接插入if (buckets[index] == -1){buckets[index] = count; // 将当前元素插入桶数组entries[count] = new Entry { hashCode = hashCode, key = key, value = value, next = -1 };count++;}else{// 发生哈希冲突,遍历链表int current = buckets[index];while (current >= 0){Entry entry = entries[current];if (entry.hashCode == hashCode && EqualityComparer<TKey>.Default.Equals(entry.key, key)){entries[current].value = value; // 如果找到相同的键,更新值return;}current = entry.next; // 查找下一个节点}// 如果没有找到,插入新的元素到链表头部entries[count] = new Entry { hashCode = hashCode, key = key, value = value, next = buckets[index] };buckets[index] = count; // 更新桶的索引count++;}// 扩容检查if (count > buckets.Length * 0.75){Resize(); // 扩容}}
- 如果
(2)查找元素
当调用 dictionary[key] 或 TryGetValue(key, out value) 时:
-
计算哈希值:
hashCode = key.GetHashCode()。 -
计算索引:
index = hashCode % buckets.Length。 -
遍历链表
:
- 如果桶中第一个元素匹配,则直接返回。
- 如果有哈希冲突(next != -1),遍历
entries直到找到key。
(3)删除元素
当调用 dictionary.Remove(key) 时:
- 计算哈希值,找到哈希桶索引。
- 遍历链表,找到匹配的
Entry。 - 更新链表指针:
- 如果是第一个元素,则更新
buckets指向next位置。 - 如果在链表中,则调整
next以跳过该元素。
- 如果是第一个元素,则更新
- 回收 entry:
- 将
entry记录到freeList,方便后续使用。
- 将
(4)扩容机制
当 count >= capacity * 0.75 时,Dictionary 会进行 2 倍扩容:
- 创建更大的 buckets 和 entries 数组(通常是 2 倍大小)。
- 重新计算索引,重新分配
buckets和entries。 - 重新插入所有 Entry,因为
hashCode % newCapacity结果不同,所有键值对需要重新计算索引。
3. Dictionary 的碰撞处理
C# 的 Dictionary 采用 链地址法 处理哈希冲突:
entries形成链表,每个Entry记录next指向同一个桶的下一个Entry。- 遍历链表时,检查
hashCode和key是否匹配。
示例假设 buckets 长度为 5,并插入以下键值对:
dict.Add(1, "Apple");
dict.Add(6, "Banana"); // 6 % 5 == 1,与 1 发生哈希冲突
哈希桶结构如下:
buckets: [ -1, 0 -> 1, -1, -1, -1 ] // index 1 存储链表 (1 → 6)
entries: 0: { hashCode=1, key=1, value="Apple", next=1 }1: { hashCode=6, key=6, value="Banana", next=-1 }
查找 dict[6] 时:
- 计算
index = 6 % 5 = 1。 - 遍历链表:
entries[0](key=1) 不匹配,继续遍历next=1。entries[1](key=6) 匹配,返回"Banana"。
4. Dictionary 的优缺点
优点
- 查找快:平均时间复杂度 O(1)。
- 插入删除快:平均时间复杂度 O(1)。
- 自动扩容:避免手动管理大小。
缺点
- 内存占用大:数组 + 链表可能浪费额外空间。
- 哈希碰撞影响性能:冲突越多,查找速度降至 O(n)。
- 不保证顺序:
Dictionary无序存储键值对。
5. Dictionary 的替代方案
| 数据结构 | 适用场景 |
|---|---|
SortedDictionary<TKey, TValue> | 需要按键排序(基于 红黑树,O(log n)) |
SortedList<TKey, TValue> | 适用于小数据量,查找快但插入慢 |
HashSet<T> | 仅存储键,不存储值 |
ConcurrentDictionary<TKey, TValue> | 多线程安全字典 |
相关文章:
C# Dictionary的实现原理
在 C# 中,Dictionary<TKey, TValue> 是一个基于哈希表(Hash Table)实现的键值对集合。它提供了高效的插入、删除和查找操作,平均时间复杂度接近 O(1)。下面是 Dictionary 的核心实现原理: 1. Dictionary 的核心数…...
学习笔记-人脸识别相关编程基础
通过编程实现人脸识别功能,需要掌握一定的技术基础,包括编程语言、图像处理、机器学习以及相关的库和框架: 1. 编程语言 Python:Python 是实现人脸识别最常用的语言之一,因为它有大量的库和框架支持,如 Op…...
BUU37 [DASCTF X GFCTF 2024|四月开启第一局]web1234【代码审计/序列化/RCE】
Hint1:本题的 flag 不在环境变量中 Hint2:session_start(),注意链子挖掘 题目: 扫描出来www.zip class.php <?phpclass Admin{public $Config;public function __construct($Config){//安全获取基…...
(五)Spring Boot学习——spring security +jwt使用(前后端分离模式)
一定要熟悉spring security原理和jwt无状态原理,理解了才知道代码作用。 在 Spring Security JWT 认证流程中,通常的做法是: 用户提交用户名和密码Spring Security 认证管理器 (AuthenticationManager) 进行认证如果认证成功,生…...
Java中使用EasyExcel
Java中使用EasyExcel 文章目录 Java中使用EasyExcel一:EasyExcel介绍1.1、核心函数导入数据导出数据 1.2、项目实际应用导入数据导出数据 1.3、相关注解ExcelProperty作用示例 二:EasyExcel使用2.1、导入功能2.2、导出功能 三:EasyExcel完整代…...
前沿科技改变生活新趋势
纳米技术在电子设备制造中的应用越来越广泛。这种技术能够帮助制造更小、更快、更耐用的电子产品。 举个例子,手机的处理器是其核心部件。随着纳米技术的进步,现在的处理器比以前小得多,但功能却更强。这样不仅让手机变得更轻薄,…...
不到一个月,SQLite 3.49.0来了
距离 SQLite 3.48.0 发布不到一个月,SQLite 开发团队于 2025 年 2 月 6 日发布了 SQLite 3.49.0 版本。这更新速度的确让人感动,那么这个版本又有哪些更新呢? 查询优化器 新版本改进了自动索引(query-time index)优化…...
Android车机DIY开发之软件篇(十四)编译i.mx8mplus官方kernel
1.下载 下载地址 2.安装依赖 sudo apt-get update sudo apt-get install build-essential git libncurses5-dev libssl-dev bc sudo apt-get install gcc-aarch64-linux-gnu export CROSS_COMPILEaarch64-linux-gnu- 3.配置 make ARCHarm64 defconfig 4.编译 make ARCHa…...
Mac上搭建宝塔环境并部署PHP项目
安装Docker Desktop》搭建Centos版本的宝塔环境》部署PHP项目 1. 下载Docker for mac 软件:https://www.docker.com/ 或使用终端命令:brew install --cask --appdir/Applications docker 2. 使用命令安装宝塔环境的centos7系统: docker pul…...
3.3.3 VO-O语法- 语法算子(二)
循环遍历 由于VO语言是面向数据集的,其所有隐含的语义中都已经带有了遍历并计算的数据逻辑。因此,VO语言只提供了一种支持循环语法的算子--Loop算子。 Loop算子 Loop算子是一个容器算子,其可以实现对其内部子流程的循环迭代运行。但Loop算…...
安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)
安装 Ollama 的步骤根据操作系统不同会有所差异,以下是针对不同操作系统的详细安装指南: Windows 系统 下载安装包:访问 Ollama 官方下载页面,下载适用于 Windows 的安装程序 OllamaSetup.exe。运行安装程序:双击下载的安装包,按照提示完成安装。默认安装路径为 C:\User…...
HCIA项目实践--静态路由的综合实验
八 静态路由综合实验 (1)划分网段 # 192.168.1.0 24#分析:每个路由器存在两个环回接口,可以把两个环回接口分配一个环回地址,所以是四个环回,一个骨干,这样分配,不会出现路由黑洞#19…...
Electron视图进程和主进程通讯
快速创建基于vue的electron项目:quick-start/create-electron - npm 视图线程也就index.html是无法直接访问这个api的(如果没有开启视图层访问nodejs的功能,现在几乎没法直接开启,开启了一堆警告提示) 所以需要通过r…...
Vript-Hard——一个基于高分辨率和详细字幕的视频理解算法
一、概述 多模态学习的最新进展促进了对视频理解和生成模型的研究。随之而来的是,对高分辨率视频和详细说明所建立的高质量数据集的需求激增。然而,由于时间因素的影响,视频与文本的配对不像图像那样容易。准备视频和文本配对是一项困难得多…...
react脚手架搭建react项目使用scss
1.create-react-app 创建的项目,webpack配置默认是隐藏的 ,如果要查看 或修改用npm run eject命令,因为create-react-app脚手架默认已经配置了scss、sass所以不用改webpack配置。如果用less 就需要自己添加配置 2.如果直接使用scss的文件会直接报错&…...
Vue.js 状态管理库Pinia
Pinia Pinia :Vue.js 状态管理库Pinia持久化插件-persist Pinia :Vue.js 状态管理库 Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。 要使用Pinia ,先要安装npm install pinia在main.js中导入Pinia 并使用 示例…...
【Stable Diffusion部署至GNU/Linux】安装流程
以下是安装Stable Diffusion的步骤,以Ubuntu 22.04 LTS为例子。 显卡与计算架构介绍 CUDA是NVIDIA GPU的专用并行计算架构 技术层级说明CUDA Toolkit提供GPU编译器(nvcc)、数学库(cuBLAS)等开发工具cuDNN深度神经网络加速库(需单独下载)GPU驱动包含CUDA Driver(需与CUDA …...
【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)
绪论:冲击蓝桥杯一起加油!! 每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章是算法训练的第二章----滑动窗口,它的本质是双指针算法的衍生所以我将…...
计算机毕业设计SpringBoot+Vue.js房源推荐系统 房价预测 房源大数据分析可视化(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
开源机器人+具身智能 解决方案+AI
开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...
番茄小说下载器:打造个人专属离线小说图书馆的完整指南
番茄小说下载器:打造个人专属离线小说图书馆的完整指南 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 你是否曾在通勤路上突然想读小说,却因为网络信号不佳而无法加…...
CES 2016行业转向:从酷炫到实用,安全与服务成核心
1. 从“酷炫”到“实用”:CES 2016的行业转向解析每年一月的拉斯维加斯,对于科技行业而言,都像是一场盛大的朝圣。CES(国际消费电子展)不仅是新品发布的舞台,更是行业风向的晴雨表。2016年的CES,…...
Error response from daemon: client version 1.52 is too new. Maximum supported API version is 1.43
按照习惯,输入“docker ps”查看一下容器,结果给我来个这个错误:Error response from daemon: client version 1.52 is too new. Maximum supported API version is 1.43查了一下原因:这是因为使用云构建安装的默认 Docker 守护程…...
KMS智能激活终极指南:5分钟永久激活Windows和Office全系列
KMS智能激活终极指南:5分钟永久激活Windows和Office全系列 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼吗?Office文档突然变…...
CANN/asc-devkit截断函数API文档
Truncate(ISASI) 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcod…...
基于Raspberry Pi Pico的DIY宏键盘:从矩阵扫描到KMK固件实战
1. 项目概述:ClawDeck,一个为游戏玩家打造的桌面控制中心最近在逛一些开发者社区和硬件DIY论坛时,发现一个叫“ClawDeck”的项目挺有意思。项目作者是“gaminghousenursingaide761”,这个名字看起来像是一个个人开发者的ID。ClawD…...
Claw Mentor:为OpenClaw智能体实现自动化配置同步与社区化演进
1. 项目概述:为你的AI智能体引入“导师”机制在AI智能体(Agent)开发领域,尤其是基于OpenClaw这类开源框架时,我们常常面临一个困境:如何持续地学习和迭代,跟上领域内最佳实践的发展速度…...
【实战】C#集成SM4国密算法:从原理到安全通信应用
1. SM4国密算法基础认知 第一次接触SM4算法时,我被它简洁而强大的设计所吸引。作为我国自主设计的商用分组密码标准,SM4与AES有着相似的定位,但采用了完全不同的技术路线。它的分组长度和密钥长度都是128位,这个设计让我想起平时用…...
企业知识库RAG到底有多难:实战3:向量化与存储
文章目录(零)项目位置(一)整体功能介绍(二)程序入口与参数(三)向量数据库初始化(四)文档 node 构建流程(五)为什么 debug 模式非常重要…...
[hadoop] 初识Spark
初识Spark采用的方法是:由新手不断地追问老手问题,老手给出一定的回答。 在这个过程中,新手会慢慢理解Spark 参考资料: 《Hadoop 3.x大数据开发实战》 文章目录参考资料:11.11.2233.14555.166.16.21 Spark集群的启动…...
