解析 C# Dictionary 代码
entries用于存储当前每个节点的数据,其中四个字段分别表示:
hashCode:key对应的hash值next:处理hash冲突,可以理解为是一个链表结构,邻接表key:存储的keyvalue:存储的value
buckets存储桶,用于存储hash映射
设计的巧妙之处在这个桶buckets,每个hashCode取模(当前size最近的大于size的素数),这里用素数是为了减少hash冲突的频率,key取hash再取模=index,就放入存储桶中,buckets[index]记录的是当前key对应的第一个entries的下标位置,entries不管是增加还是删除,会优先连续的放在数组中,举例删了index[2]的数据,这个时候加入一个数据,会无脑放在这个index[2]的位置,同理[.next]也维护了删除的单向链表的数据,所有删掉的index下标数据,也是存在链中等待新的数据插入,这里是反向链表获取index,所以可以理解为最早清理的index,最晚被用到。
具体可以看看代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Text;namespace DictionaryTest
{public static class MHashHelpers{public const int MaxPrimeArrayLength = 0x7FEFFFFD;public static readonly int[] primes = {3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};public static bool IsPrime(int candidate){if ((candidate & 1) != 0){int limit = (int)Math.Sqrt(candidate);for (int divisor = 3; divisor <= limit; divisor += 2){if ((candidate % divisor) == 0)return false;}return true;}return (candidate == 2);}public static int GetPrime(int min){for (int i = 0; i < primes.Length; i++){int prime = primes[i];if (prime >= min) return prime;}for (int i = (min | 1); i < Int32.MaxValue; i += 2){if (IsPrime(i) && ((i - 1) % 101 != 0))return i;}return min;}public static int ExpandPrime(int oldSize){int newSize = 2 * oldSize;// Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.// Note that this check works even when _items.Length overflowed thanks to the (uint) castif ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize){Contract.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");return MaxPrimeArrayLength;}return GetPrime(newSize);}}public class MDictionary<TKey, TValue>{private struct Entry{public int hashCode; // 存储 Key 对应的 hashCodepublic int next; // 指向上一个存储的对象的indexpublic TKey key; // 存储的 Keypublic TValue value; // 存储的 Value}private IEqualityComparer<TKey> comparer;private int[] buckets; // 定长的存储桶private Entry[] entries; // 定长的存储元素的数组private int count; // 当前元素个数private int freeList; // 删掉元素之后,还空余的位置,最新的一个,根据entries链表指向上一个private int freeCount; // 空余的个数public MDictionary() : this(0) { }public MDictionary(int capacity){if (capacity > 0){Initialize(capacity);}this.comparer = EqualityComparer<TKey>.Default;}private void Initialize(int capacity){int size = MHashHelpers.GetPrime(capacity);buckets = new int[size];entries = new Entry[size];for (int i = 0; i < buckets.Length; i++){buckets[i] = -1;entries[i].hashCode = -1;entries[i].next = -1;entries[i].key = default(TKey);entries[i].value = default(TValue);}count = 0;freeList = -1;freeCount = 0;}private void Resize(){Console.WriteLine($"[Resize]");int newSize = MHashHelpers.ExpandPrime(count);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);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 != -1){int bucket = newEntries[i].hashCode % newSize;newEntries[i].next = newBuckets[bucket];newBuckets[bucket] = i;}}buckets = newBuckets;entries = newEntries;PrintAll();}public void Insert(TKey key, TValue value){Console.WriteLine($"[Insert] {key} {value}");int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;int targetBucket = hashCode % buckets.Length;for (int i = buckets[targetBucket]; i != -1; i = entries[i].next){if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)){entries[i].value = value;PrintAll();return;}}int index;if (freeCount > 0){index = freeList;freeList = entries[index].next;freeCount--;}else{if (count == buckets.Length){Resize();targetBucket = hashCode % buckets.Length;}index = count;count++;}entries[index].hashCode = hashCode;entries[index].next = buckets[targetBucket];entries[index].key = key;entries[index].value = value;buckets[targetBucket] = index;PrintAll();}public bool Remove(TKey key){Console.WriteLine($"[Remove] {key}");int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;int bucket = hashCode % buckets.Length;int last = -1;for (int i = buckets[bucket]; i != -1; last = i, i = entries[i].next){if (comparer.Equals(key, entries[i].key) && entries[i].hashCode == hashCode){if (last == -1){buckets[bucket] = entries[i].next;}else{entries[last].next = entries[i].next;}entries[i].hashCode = -1;entries[i].next = -1;entries[i].key = default(TKey);entries[i].value = default(TValue);freeList = i;freeCount++;PrintAll();return true;}}PrintAll();return false;}public bool TryGetValue(TKey key, out TValue value){Console.WriteLine($"[TryGetValue] {key}");int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;int targetBucket = hashCode % buckets.Length;for (int i = buckets[targetBucket]; i != -1; i = entries[i].next){if (comparer.Equals(key, entries[i].key) && entries[i].hashCode == hashCode){value = entries[i].value;return true;}}value = default(TValue);return false;}public void Clear(){Console.WriteLine($"[Clear]");if (count > 0){for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;Array.Clear(entries, 0, count);count = 0;freeList = -1;freeCount = 0;}PrintAll();}public void PrintAll(){Console.WriteLine($"[PrintAll]");StringBuilder bucketInfo = new StringBuilder();StringBuilder entriesInfo = new StringBuilder();for (int i = 0; i < buckets.Length; i++){bucketInfo.Append($"{i} [{buckets[i]}]").Append("\n");}Console.WriteLine("buckets: " + buckets.Length);Console.Write(bucketInfo);for (int i = 0; i < entries.Length; i++){entriesInfo.Append($"{i} [{entries[i].hashCode}={entries[i].next}={entries[i].key}={entries[i].value}]").Append("\n");}Console.WriteLine("entries: " + entries.Length);Console.Write(entriesInfo);}}class Program{static void Main(string[] args){Console.WriteLine("Hello World!");MDictionary<int, string> dict = new MDictionary<int, string>(2);dict.Clear();dict.Insert(0, "000");dict.Insert(1, "111");dict.Remove(0);dict.Insert(2, "222");dict.Insert(3, "333");dict.Insert(4, "444");dict.Remove(2);dict.Insert(5, "555");dict.Insert(6, "666");dict.Remove(1);dict.Insert(7, "777");dict.Insert(14, "1414");dict.Insert(21, "2121");dict.Remove(14);dict.Insert(28, "2828");dict.Insert(35, "3535");dict.Insert(42, "4242");dict.Insert(55, "5555");dict.Remove(21);}}
}
一些参考:
https://zhuanlan.zhihu.com/p/96633352
Reference Source
https://www.cnblogs.com/pengze0902/p/17830689.html
相关文章:
解析 C# Dictionary 代码
entries用于存储当前每个节点的数据,其中四个字段分别表示: hashCode:key对应的hash值next:处理hash冲突,可以理解为是一个链表结构,邻接表key:存储的keyvalue:存储的value bucket…...
如何利用人工智能提升工作效率
在当今这个信息爆炸的时代,我们每天都被大量的工作任务所困扰。然而,随着人工智能技术的不断发展,我们可以通过一些智能工具来提升我们的工作效率。在这篇文章中,我将分享一些关于如何利用人工智能提升工作效率的建议。 首先&…...

Linux驱动开发—Linux内核定时器概念和使用详解,实现基于定时器的字符驱动
文章目录 内核定时器概念在Linux驱动模块中使用定时器软定时器(Soft Timers)jiffies 含义高精度定时器(High Resolution Timers) 实现倒计时字符设备驱动 内核定时器概念 在 Linux 内核中,定时器是用来管理和调度延迟…...
mysql数据库:数据库,表和列的基本概念
mysql:数据库,表和列的基本概念以及导入和导出文件 数据库的概念和用途 数据库是一个有组织的数据集合,它们被存储在计算机上以便于管理和访问。数据库的主要目的是为了存储和管理数据,同时使数据能够被高效地访问、检索和更新。数…...
Nextjs 使用 graphql,并且接入多个节点
写在前面 随着区块链技术的流行,也促进了 subgraph 工具的兴起。那么如何在前端接入 graphql 节点就成了关键,其接入方式既存在与 restful 接口相类似的方式,也有其独特接入风格。本文将介绍如何接入 graphql 以及如何应对多个 graphql 节点…...
小结——知识注入
所谓知识注入,其实不该脱离于LLM的基础工作原理,然后空谈抽象概念。 知识,也就是你问他问题,他能输出正确的回答,这只是一个简单的输出token的过程。输出得准了,就是知识,输出不准了,…...

科普文:微服务之Spring Cloud Alibaba组件Nacos一致性协议Distro+Raft概叙
一、概要 Nacos是阿里开放的一款中间件,它主要提供三种功能:持久化节点注册,非持久化节点注册和配置管理。 二、一致性协议 - AP/CP Nacos不是纯粹的AP服务,也不是纯粹的CP服务,而是两者同时支持。 这要从服务注册…...

python合并音视频-通过ffmpeg合并音视频
🌈所属专栏:【python】✨作者主页: Mr.Zwq✔️个人简介:一个正在努力学技术的Python领域创作者,擅长爬虫,逆向,全栈方向,专注基础和实战分享,欢迎咨询! 您的…...

Yolov8添加ConvNetV1和V2模块
Yolov8添加ConvNet模块 1 ConvNet系列相关内容 (1)2022 论文地址:A ConvNet for the 2020s Code Link 如下图所示,精度、效率、尺寸都很不错。 论文的摘要如下: 视觉识别的“咆哮的 20 年代”始于视觉注意力 &…...
十个常见的 Python 脚本 (详细介绍 + 代码举例)
1. 批量重命名文件 介绍: 该脚本用于批量重命名指定目录下的文件,例如将所有 ".txt" 文件重命名为 ".md" 文件。 import osdef batch_rename(directory, old_ext, new_ext):"""批量重命名文件扩展名。Args:directory: 要处理…...

【C语言】详解feof函数和ferror函数
文章目录 前言1. feof1.1 feof函数原型1.2 正确利用函数特性读写文件1.2.1 针对文本文件1.2.2 针对二进制文件 1.3 feof函数的原理1.4 feof函数实例演示 2. ferror2.1 ferror函数原型 前言 或许我们曾在网络上看过有关于feof函数,都说这个函数是检查文件是否已经读…...
ValueListenableBuilder 和 addListener 在 ChangeNotifier的区别
1、前言 ValueListenableBuilder 和 addListener 在 ChangeNotifier 中有不同的用途和用法,适用于不同的场景。它们的主要区别在于它们如何监听和响应状态变化,以及它们的用法和特性。 2、ValueListenableBuilder用法 ValueListenableBuilder 是一个 …...

ScriptEcho:AI赋能的前端代码生成神器
ScriptEcho:AI赋能的前端代码生成神器 在前端开发中,如果你总是觉得写代码太费时费力,那么 ScriptEcho 将成为你的救星。这个 AI 代码生成平台不仅能帮你省下大量时间,还能让你轻松愉快地写出生产级代码。本文将带你了解 ScriptEc…...

TypeError: ‘float’ object is not iterable 深度解析
TypeError: ‘float’ object is not iterable 深度解析与实战指南 在Python编程中,TypeError: float object is not iterable是一个常见的错误,通常发生在尝试对浮点数(float)进行迭代操作时。这个错误表明代码中存在类型使用不…...
灵茶八题 - 子序列 +w+
灵茶八题 - 子序列 w 题目描述 给你一个长为 n n n 的数组 a a a,输出它的所有非空子序列的元素和的元素和。 例如 a [ 1 , 2 , 3 ] a[1,2,3] a[1,2,3] 有七个非空子序列 [ 1 ] , [ 2 ] , [ 3 ] , [ 1 , 2 ] , [ 1 , 3 ] , [ 2 , 3 ] , [ 1 , 2 , 3 ] [1],[…...
为什么美元债务会越来越多?
美元债务规模持续膨胀,其背后原因复杂多样,可归结为以下几个主要因素: 财政赤字和刺激政策是导致美元债务增加的重要原因。美国政府长期面临财政赤字问题,支出远超收入,为弥补这一缺口,政府不得不大量发行…...
二维凸包算法 Julia实现
问题描述:给定平面上 n n n 个点的集合 Q Q Q,求其子集 P P P 构成 Q Q Q 的凸包,即 ∀ p ∈ Q , ∃ p 0 , p 1 , p 2 ∈ P \forall p \in Q, \exist p_0, p_1, p_2 \in P ∀p∈Q,∃p0,p1,p2∈P 使得点 p p p 在以点 p 0 , p 1 …...

python dash框架
Dash 是一个用于创建数据分析型 web 应用的 Python 框架。它由 Plotly 团队开发,并且可以用来构建交互式的 web 应用程序,这些应用能够包含图表、表格、地图等多种数据可视化组件。 Dash 的特点: 易于使用:Dash 使用 Python 语法…...

2.外部中断(EXTI)
理论 NVIC:嵌套向量中断控制器(解释教程) 外部通用中断线(EXTI0~EXTI15):每个GPIO设置成中断模式,与中断控制器连接的线 外部中断触发方式 上升沿触发、下降沿触发、双边沿触发 外部中断触发函数 在stm32f1xx_it.c文件…...

Python | SyntaxError: invalid syntax 深度解析
Python | SyntaxError: invalid syntax 深度解析 在Python编程中,SyntaxError: invalid syntax是一个常见的错误,它表明Python解释器在尝试解析代码时遇到了语法问题。这个错误通常是由于代码中存在拼写错误、缺少符号(如括号、冒号或逗号&a…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀” 在JavaScript中,我们经常需要处理文本、数组、对象等数据类型。但当我们需要处理文件上传、图像处理、网络通信等场景时,单纯依赖字符串或数组就显得力不从心了。这时ÿ…...