当前位置: 首页 > news >正文

C#字典

C#字典

HasTable

Hashtable 通常称为哈希表,它表示键/值对的集合,这些键/值对根据键的哈希代码进行组织。它的每个元素都是一个存储在DictionaryEntry对象中的键/值对。键不能为空引用,但值可以。
命名空间System.Collections
是一种基于哈希算法实现的键值对集合类,提供高效的查找、插入和删除操作。作为非泛型集合,Hashtable 的键和值均为 object 类型,适用于需要快速存储和检索数据的场景。

Hash算法: 对任意内容进行算法计算,返回一个整数(哈希值), 内容不相等, hash算法得到哈希值可能一样 (hash冲突,碰撞)

image

HashTable解决hash冲突, 使用开放寻址法, 计算下标处有元素, 元素key与添加元素key不一样, 下标加增量得到新的下标, 判断新下标是否有元素, 如果没有, 添加在该位置, 如果有继续往后查找

虽然 Hashtable 仍然可用,但在新项目中通常建议使用泛型的 Dictionary<K, V>,因为它避免装箱和拆箱操作,提供更好的类型安全和性能。

Dictionary<K,V>

1、Dictionary概念及特征

1.1、Dictionary概念

Dictionary<K, V>是.NET框架中的泛型集合类,属于System.Collections.Generic命名空间。它以键值对的形式存储数据,每个键必须唯一,但值可以重复。

1.2、Dictionary特征

  • 类型安全:通过泛型避免装箱拆箱操作
  • 高效查找:基于哈希表实现,平均O(1)时间复杂度
  • 动态扩容:容量不足时自动扩展
  • 键唯一性:确保每个键在字典中只出现一次

2、Dictionary底层原理

2.1、Dictionary采用哈希表架构,使用两个核心数组

image

主要由以下部分组成:

  • 桶数组(Bucket Array):存储条目的索引
  • 条目数组(Entry Array):实际存储键值对的数据结构
  • 空闲链表:管理空闲位置的链表
private struct Entry {public uint hashCode;    // 哈希码的低31位public int next;        // 指向链表中下一个条目的索引public TKey key;        // 键public TValue value;    // 值
}
private int[] _buckets; // 桶数组,存储条目索引
private Entry[] _entries; // 条目数组
private int _count; // 已存储的键值对数量
private int _freeList; // 空闲条目链表的起点
private int _freeCount;  // 空闲条目数量
private int _version; //版本   
  • buckets数组:存储指向entries的索引

  • entries数组:存储实际的KeyValuePair数据

  • 哈希计算:

    • 对键调用 GetHashCode() 获取哈希值
    • 使用 hashCode & 0x7FFFFFFF 确保为正数
    • 取模运算确定桶位置:bucketIndex = hashCode % buckets.Length
  • 冲突处理:使用链地址法(拉链法)解决哈希冲突

    • 使用链地址法解决哈希冲突
    • 每个桶中的条目通过 next 字段形成链表
  • 扩容机制:负载因子超过0.72时触发扩容

2.2、Dictionary整体架构设计解析

1、双数组存储结构
Dictionary采用数组作为底层存储,核心由桶数组(Bucket Array)与条目数组(Entry Array)协同构成。桶数组存储条目索引,条目数组存放实际键值对,分离设计实现高效寻址。

2、O(1)查询效率保障
独立的buckets数组通过哈希值直接定位下标,避免遍历整个数据集,将查询时间复杂度稳定在常数级别,即使数据量激增也能保持极速响应。

2.3、Dictionary初始化机制深度剖析

1、无参构造的懒加载策略
无参构造初始容量设为3,但数组内存延迟至首次Add操作才分配,避免空字典的内存浪费,优化启动性能。

2、指定容量的立即初始化
传入capacity参数的构造函数在实例化瞬间完成数组分配,适用于预知数据规模的场景,减少运行时扩容开销。

3、构造方法底层源码
无参
image
添加元素
image
image
有参
image

初始容量

image

推荐: 数据规模确定则使用有参构造指定容量;数据规模不确定则使用无参构造

2.4、Entry节点结构与哈希冲突解决

2.4.1、Entry节点结构

image

2.4.2、为什么会有hash冲突?

image

image

2.4.3、处理hash冲突

Dictionary采用链地址法解决冲突,将哈希值相同的Entry以链表形式存储于同一桶位置。相较于开放寻址法,链表结构在冲突严重时仅需遍历短链,删除操作无需重新探测,实现更简洁高效。

image
即:
image

链表长度直接影响查询性能,当元素数量超过容量与负载因子乘积时触发扩容。扩容后重新哈希所有元素,分散链表长度,将平均查找时间恢复至O(1)水平,维持字典高效运转。

image

3、基础语法与操作

3.1、创建与初始化

// 基本声明与实例化
Dictionary<string, int> dict1 = new Dictionary<string, int>();
// 集合初始化器 (C# 3.0+)
Dictionary<string, int> dict2 = new Dictionary<string, int>
{{ "Alice", 30 },{ "Bob", 25 }
};
// 索引器初始化 (C# 6.0+)
Dictionary<string, int> dict3 = new Dictionary<string, int>
{["Alice"] = 30,["Bob"] = 25
};
// 指定初始容量优化性能
Dictionary<string, int> dict4 = new Dictionary<string, int>(100);

性能提示: 预估数据量并指定初始容量可以减少扩容次数,提升性能。

3.2、添加元素

Dictionary<TKey, TValue> 中,可以通过 Add() 方法 或 索引器 [] 向字典中添加键值对。

1、使用Add()方法添加

Dictionary<int, string> dict = new Dictionary<int, string>();dict.Add(1, "Apple");
dict.Add(2, "Banana");

特点:

  • 用于向字典中添加新的键值对。
  • 键必须唯一。
  • 如果添加的键已经存在,则会 抛出异常 ArgumentException。

2、使用索引器 [] 添加

dict[1] = "Apple";
dict[2] = "Banana";
dict["alice"] = 18;

特点:

  • 如果键 不存在 → 添加新的键值对。
  • 如果键 已经存在更新对应的值。

3.3、访问元素

Dictionary<TKey, TValue> 中,可以通过 键(Key) 来访问对应的值(Value)。

1、使用索引器 [] 访问

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "Apple");
dict.Add(2, "Banana");
string value = dict[1];
Console.WriteLine(value);

特点:

  • 使用 dict[key] 获取对应的值。
  • 如果 键不存在,程序会抛出 KeyNotFoundException 异常

2、使用 TryGetValue() 方法

string value;
if (dict.TryGetValue(1, out value))
{Console.WriteLine(value);
}
else
{Console.WriteLine("键不存在");
}

特点:

  • 返回值是 bool
    • true → 找到键
    • false → 没找到
  • 如果找到,值会通过 out 参数返回。

3、检查键值是否存在,ContainsKey() ContainsValue()

 bool hasAlice = dict1.ContainsKey("Alice");bool hasAge30 = dict1.ContainsValue(30);

3.4、修改与删除

Dictionary<TKey, TValue> 中,可以通过 Remove()Clear() 方法以及索引器 [] 来修改或删除元素。

1、修改元素

通过 索引器 [] 根据键修改对应的值。

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "Apple");
dict.Add(2, "Banana");
// 修改 value
dict[1] = "Orange";

说明:

  • 如果 key 存在 → 修改对应的 value
  • 如果 key 不存在 → 会新增一个键值对

2、删除元素

使用 Remove() 方法根据键删除元素。

dict.Remove(1);

说明:

  • 根据 key 删除对应的键值对。
  • 返回值是 bool
    • true → 删除成功
    • false → 键不存在

3、清空字典

使用 Clear() 方法删除字典中的所有元素。

dict.Clear();

说明:

  • 清空整个 Dictionary
  • 删除所有键值对

3.5、遍历字典

可以使用foreach循环遍历字典中的所有键值对,或者分别遍历键和值。

 // 遍历键值对foreach (KeyValuePair<string, int> kvp in dict1)  Console.WriteLine($"{kvp.Key}: {kvp.Value}");// 简化写法foreach (var kvp in dict1)  Console.WriteLine($"{kvp.Key}: {kvp.Value}");// 只遍历键foreach (string name in dict1.Keys)  Console.WriteLine(name);// 只遍历值foreach (int age in dict1.Values)  Console.WriteLine(age);

4、与Hashtable的区别

image

5、了解扩展方法

扩展方法是 C# 的一个特性,它允许在不修改原有类源码的情况下,为已有类型添加新的方法
也就是说,可以像调用实例方法一样调用这个新方法,但实际上它是一个 静态方法

基本特点

  • 必须定义在静态类(static class)中
  • 方法必须是 static
  • 第一个参数必须使用 this 修饰
  • 第一个参数表示要扩展的类型
// OrderBY() 扩展方法 升序
// 根据key进行升序
var items = dict.OrderBy(kv => kv.Key);
foreach (var item in items)  Console.WriteLine($"{item.Key}:{item.Value}");
// OrderByDescending() 扩展方法 降序
// 根据Value进行降序
items = dict.OrderByDescending(kv => kv.Value);
foreach (var item in items)  Console.WriteLine($"{item.Key}:{item.Value}");
http://www.jsqmd.com/news/450756/

相关文章:

  • SiameseAOE模型效果惊艳展示:多领域评论文本抽取案例集
  • 新手零基础入门:通过快马平台轻松完成openclaw安装与环境配置
  • Qwen-Image-2512-Pixel-Art-LoRA实操指南:Gradio界面中‘停止生成’与显存自动释放机制
  • Qwen3-ASR-0.6B老人语音识别效果展示
  • AI辅助开发实战:使用charCodeAt高效解码PCM音频数据
  • springboot微信小程序的旧衣回收系统(源码+文档+调试+vue+前后端分离)
  • HDBSCAN实战指南:从环境搭建到生产部署
  • 利用快马平台AI快速生成JWT Token认证系统原型
  • AI转型破局:跨越“研发鸿沟“的组织进化论
  • Proteus数码管仿真避坑指南:如何用STM32 HAL库实现动态扫描(含Keil5工程文件)
  • Mac Terminal必备技能:高效管理文件夹的7个实用命令
  • yz-bijini-cosplay智能助手:基于Z-Image的Cosplay角色换装+换景方案
  • 手把手教你用MambaOut复现论文结果:从环境配置到性能测试
  • Qwen-Image-Edit实战:电商换季图、人像精修,一句话指令全搞定
  • FastAPI进阶开发:ORM
  • Ostrakon-VL-8B镜像免配置:start.sh一键拉起Gradio服务,省去环境踩坑
  • MT5 Zero-Shot中文增强镜像实操手册:从安装到批量生成全流程
  • [ARM原生加速]:M1/M2开发者的Android模拟器性能优化指南
  • 用Obsidian-Git构建知识安全网:从数据防护到协作管理的完整指南
  • DCT-Net人像卡通化效果提升:输入图像分辨率与输出质量关系
  • GLM-OCR模型Typora伴侣工具开发:自动识别图片并插入Markdown
  • RMBG-2.0GPU算力优化:梯度检查点+内存映射减少峰值显存
  • 7天精通REINVENT4:AI驱动分子设计全流程指南
  • 通义千问3-Reranker-0.6B效果惊艳展示:中英文混合查询下Top-1准确率实录
  • AIGlasses_for_navigation高清展示:盲道与人行横道交界处像素级分割边界
  • 3步永久保存QQ空间回忆:GetQzonehistory数据备份工具全解析
  • 从手写代码到日提 30 个 PR:Claude Code 缔造者的 AI 编程启示录
  • 加密MCP保险库:人工智能系统中安全凭证管理的关键
  • 如何借助ChanlunX实现缠论技术分析的可视化与实战应用
  • 南北阁Nanbeige 4.1-3B代码生成效果:Java面试算法题一键解答