news 2026/9/2 6:29:55

【Unity小白学习日记8】C# 集合学习合集3——Dictionary

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Unity小白学习日记8】C# 集合学习合集3——Dictionary

目录

一、Dictionary 常规使用

1. 基础声明与初始化

2. 高频API速查

3. 取值的三种方式与坑点

4. 遍历 Dictionary

二、基本概念

1. 什么是 Dictionary

2. KeyValuePair 结构

3. 键的哈希与相等性

4. 常用初始化技巧

三、散列表(哈希表)

1. 散列表核心思想

2. 哈希冲突

3. 装填因子与扩容

4. 时间复杂度分析

5. 哈希函数的质量决定性能

6. Dictionary vs Hashtable

面试回答精简版

总结

一、Dictionary 常规使用

Dictionary<TKey, TValue>是C#中最常用的键值对泛型集合,命名空间为System.Collections.Generic。它以「键-值」形式存储数据,键唯一不可重复,通过键可以O(1)快速查找对应值,是缓存、映射、配置管理场景的首选容器。

1. 基础声明与初始化

//声明空的Dictionary,键为string,值为int Dictionary<string, int> scoreDict = new Dictionary<string, int>(); //初始化直接填充键值对 Dictionary<string, string> configDict = new Dictionary<string, string>() { { "PlayerName", "张三" }, { "Level", "10" }, { "Hp", "100" } };

2. 高频API速查

方法/属性功能说明
Add(key, value)添加一个键值对,键重复会抛异常
Remove(key)根据键删除对应键值对,返回是否删除成功
Clear()清空所有键值对
ContainsKey(key)判断是否存在指定键,返回bool
ContainsValue(value)判断是否存在指定值,返回bool
TryGetValue(key, out value)安全取值,键存在返回true并输出值,不存在返回false
Count当前键值对总数
Keys获取所有键的集合
Values获取所有值的集合

示例代码:

Dictionary<string, int> score = new Dictionary<string, int>(); //添加 score.Add("数学", 95); score.Add("语文", 88); //安全取值(推荐) if (score.TryGetValue("数学", out int mathScore)) { Console.WriteLine($"数学成绩:{mathScore}"); } //判断键是否存在 if (score.ContainsKey("英语")) { score["英语"] = 90; //键存在则修改值 } else { score.Add("英语", 90); //不存在则添加 } //删除 score.Remove("语文"); //遍历所有键 foreach (string key in score.Keys) { Console.WriteLine($"{key}:{score[key]}"); } score.Clear();

3. 取值的三种方式与坑点

//方式1:索引器直接取值 —— 键不存在会抛 KeyNotFoundException int s1 = score["数学"]; //方式2:先判断再取值 —— 安全但查了两次字典 if (score.ContainsKey("数学")) { int s2 = score["数学"]; } //方式3:TryGetValue —— 只查一次,最推荐 ✅ if (score.TryGetValue("数学", out int s3)) { Console.WriteLine(s3); }

重要坑点:用索引器dict[key]取值时,如果键不存在会直接抛异常。生产环境优先使用TryGetValue,只做一次哈希查找,性能更好且安全。

4. 遍历 Dictionary

//遍历键值对(KeyValuePair) foreach (KeyValuePair<string, int> kvp in score) { Console.WriteLine($"{kvp.Key}:{kvp.Value}"); } //只遍历键 foreach (string key in score.Keys) { Console.WriteLine(key); } //只遍历值 foreach (int value in score.Values) { Console.WriteLine(value); }

注意:和List一样,foreach遍历过程中不能Add/Remove,会抛出集合被修改异常。需要遍历删除时,先把Keys转成List再遍历。

//✅正确:遍历删除 foreach (string key in score.Keys.ToList()) { if (score[key] < 60) { score.Remove(key); } }

二、基本概念

1. 什么是 Dictionary

Dictionary 是基于散列表(Hash Table)实现的键值对集合。它不按插入顺序存储,而是通过键的哈希值计算存储位置,从而实现接近O(1)的查找、插入、删除效率。

核心特征:

  • 键唯一:同一个键只能存在一个,重复Add会抛异常
  • 键不可变:作为键的对象,其哈希值在存入后不能改变,否则找不到数据
  • 无序:遍历顺序不等于插入顺序(.NET Core 3.0+ 实际保持插入顺序,但这是实现细节,不应依赖)
  • 泛型强类型:编译期确定键和值的类型,无需装箱拆箱

2. KeyValuePair 结构

Dictionary 中每个元素都是一个KeyValuePair<TKey, TValue>结构体,包含两个属性:

  • Key:键
  • Value:值
KeyValuePair<string, int> kvp = new KeyValuePair<string, int>("年龄", 20); Console.WriteLine($"{kvp.Key} = {kvp.Value}");

3. 键的哈希与相等性

Dictionary 判断两个键是否「相同」,依赖两个方法:

  • GetHashCode():计算哈希值,决定存储桶位置
  • Equals():哈希冲突时,判断两个键是否真的相等

自定义类作为键时,必须同时重写GetHashCode()Equals(),否则可能出现「逻辑上相等的两个对象被当成不同键」的问题。

//自定义类作为键的正确写法 public class Player { public int Id { get; set; } public string Name { get; set; } public override bool Equals(object obj) { return obj is Player player && Id == player.Id; } public override int GetHashCode() { return HashCode.Combine(Id); //用Id计算哈希 } }

4. 常用初始化技巧

//集合初始化器(C# 6+) var dict1 = new Dictionary<string, int> { ["A"] = 1, ["B"] = 2 }; //从现有集合创建 var dict2 = list.ToDictionary(item => item.Id, item => item.Name);

三、散列表(哈希表)

Dictionary 的底层数据结构就是散列表(Hash Table),理解散列表是掌握 Dictionary 性能的关键。

1. 散列表核心思想

散列表的核心是**「键 → 哈希值 → 数组下标 → 存储位置」**的映射:

  1. 对键调用GetHashCode()得到一个整数(哈希值)

  2. 用哈希值对数组长度取模,得到存储位置(桶,Bucket)

  3. 将键值对存入该位置对应的桶中

理想情况下,每个键对应唯一桶,查找只需一次计算,时间复杂度O(1)

2. 哈希冲突

不同的键可能计算出相同的哈希值(或取模后落到同一个桶),这就是哈希冲突

Dictionary 解决冲突的方式:拉链法(Separate Chaining)

  • 每个桶不只是存一个元素,而是一个链表(或数组)

  • 冲突的元素都挂在同一个桶的链表里

  • 查找时:先算哈希定位到桶,再在桶内链表中用Equals()逐个比较找到目标

桶数组 [0] → (键A,值1) → (键D,值4) ← 哈希冲突,挂在同一桶 [1] → (键B,值2) [2] → (键C,值3) [3] → null

3. 装填因子与扩容

  • 装填因子(Load Factor)= 元素数量 / 桶数组长度

  • 装填因子越大,冲突概率越高,查找越慢

  • .NET Dictionary 默认装填因子阈值约为1.0,超过后触发扩容

扩容机制

  1. 新建一个长度约为原来2倍的桶数组

  2. 重新计算所有元素的哈希值和新桶位置(rehash)

  3. 将所有元素迁移到新数组

  4. 旧数组交给GC回收

✨性能优化:预知数据量时,初始化指定容量,减少扩容和rehash开销Dictionary<string, int> dict = new Dictionary<string, int>(1000);

4. 时间复杂度分析

操作平均情况最坏情况
查找(通过键)O(1)O(n),所有键冲突到一个桶
插入O(1)O(n),触发扩容时为O(n)
删除O(1)O(n)
遍历O(n)O(n)

最坏情况O(n)极少出现,只要哈希函数分布均匀,实际性能始终接近O(1)。

5. 哈希函数的质量决定性能

一个好的哈希函数应该:

  • 分布均匀:不同键的哈希值尽量分散,减少冲突

  • 计算快:哈希计算本身不能太慢

  • 一致性:相同的键必须返回相同的哈希值

字符串的GetHashCode()在 .NET Core 中使用了改进的哈希算法,分布均匀且每次进程启动不同(防止哈希碰撞攻击)。

6. Dictionary vs Hashtable

对比项Dictionary<TKey,TValue>Hashtable
类型安全泛型,编译期检查非泛型,存储object
性能无装箱拆箱,更快有装箱拆箱开销
线程安全非线程安全部分线程安全(已过时)
推荐度✅现代开发首选❌已被Dictionary替代

面试回答精简版

Dictionary底层是散列表,通过键的哈希值取模定位存储桶,哈希冲突用拉链法解决,每个桶挂一个链表。查找、插入、删除平均O(1),最坏O(n)。装填因子超过阈值会触发2倍扩容并rehash。自定义类做键必须同时重写GetHashCode和Equals。生产环境取值优先用TryGetValue,避免键不存在抛异常。

总结

  1. 常规使用:掌握增删改查API,牢记键唯一、取值优先用TryGetValue,遍历删除需先转Keys为List。

  2. 基本概念:理解键值对结构、KeyValuePair、键的哈希与相等性,自定义类做键必须重写两个方法。

  3. 散列表原理:哈希映射定位桶,拉链法解决冲突,装填因子控制扩容,平均O(1)查找;预估容量减少rehash,是性能优化关键。

小何同学:路漫漫其修远兮,吾将上下而求索!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 6:29:29

Epho:用curl命令调用Claude Code的AI编程助手命令行工具

这次我们来看一个能让你用一条curl命令就能运行 Claude Code 的项目&#xff1a;Epho。对于经常在终端里工作、需要快速调用 AI 编程助手&#xff0c;但又不想打开完整 IDE 或 Web 界面的开发者来说&#xff0c;这绝对是个值得关注的工具。它的核心思路是把 Claude Code 的能力…

作者头像 李华
网站建设 2026/9/2 6:28:06

微信小程序云开发实战:校园食堂点餐系统全栈开发指南

最近在开发校园服务类小程序时&#xff0c;发现很多同学都想做一个集点餐、支付、评价于一体的食堂服务平台&#xff0c;但苦于找不到完整、可运行的项目源码参考。网上的资料要么过于零散&#xff0c;要么只讲理论没有代码&#xff0c;从环境搭建到前后端联调&#xff0c;每一…

作者头像 李华
网站建设 2026/9/2 6:27:37

TVA具身智能架构:TVA-World协同感知-动作耦合机制

前沿技术探索&#xff1a;TVA智能体&#xff08;简称TVA&#xff09; TVA智能体&#xff08;亦称“AI智能体视觉”或“TVA视觉智能体”&#xff09;是依托Transformer架构与“因式智能体”理论构建的通用视觉技术体系。它有机融合深度强化学习&#xff08;DRL&#xff09;、卷…

作者头像 李华
网站建设 2026/9/2 6:25:47

NotebookLM实测:把资料变成可对话的AI工作台

最近我在准备一份跨城市的交通规划调研材料&#xff0c;电脑里堆了十几个 PDF、网页摘要和访谈记录。以前遇到这种情况&#xff0c;我的流程基本是&#xff1a;建一个文件夹&#xff0c;把资料塞进去&#xff0c;然后……就没有然后了。等真正要写综述时&#xff0c;还得重新一…

作者头像 李华
网站建设 2026/9/2 6:25:12

从 FAQ 到 AI 机器人:搭建 WhatsApp 私有知识库的完整思路

把几十份产品文档上传给大模型&#xff0c;并不等于拥有了一个可靠的客服或销售机器人。真正困难的部分&#xff0c;是让它知道应该引用哪条知识、什么时候不能回答&#xff0c;以及答案出错后由谁修正。FAQ 和 AI 机器人之间&#xff0c;还隔着一套系统 传统 FAQ 是给人阅读的…

作者头像 李华