• C# 之Dictionary(字典)底层源码解析


    Dictionary是我们经常使用的,一起来看看它是如何构造的,及有哪些优缺点。

    Dictionary是一种键值对的形式存放数据,即 key值 、value 值 一 一映射的。key的类型没有限制,可以是整数、字符串甚至是实例对象。

    Dictionary的实现原理,有两个关键的算法,Hash算法 和 解决Hash 碰撞冲突 的算法。key value的映射关系用的就是Hash函数来建立的。

    Hash算法

    Hash算法是一种数字摘要算法,将不定长度的二进制数据集给映射到一个较短的二进制长度数据集。常见的MD5算法就是一种Hash算法,通过MD5算法 对任何数据生成数字摘要。实现Hash算法的函数 成为Hash函数

    对于实例对象和字符串来说,它们没有直接的数字作为Hash标准,因此它们需要通过内存地址计算一个Hash值,计算这个内存对象的函数也就是Hash函数。

    Hash函数

    Hash函数有很多种算法,最简单的就是 除留余数法【模(Mod)的操作】,取key 被某个不大于散列表 表长m的数p 除后所得余数作为散列地址。即 hash_key =  key % p  , p<=m。

    Hash函数有以下特征:

    1.相同的key 进行Hash计算,得到的结果一定是同一Hash地址。HashFunc(Key1) == HashFunc(Key1)。

    2.不相同的key 进行Hash计算,得到的结果也可能是同一Hash地址。key1 != key2  = >  HashFunc(Key1)== HashFunc(Key2)。【这种现象称之为Hash冲突

    Hash冲突

    处理Hash冲突的方法中,通常有开放定址法、再Hash法、链地址法、建立一个公共溢出区等。Dictionary使用的是 链地址法 又称 拉链法

    下图 Hash冲突示意图:

    Sandra Dee  和  John Smith 通过hash函数 运算后都落到了02的位置,产生了碰撞和冲突。

     拉链法:将产⽣冲突的元素建⽴⼀个单链表,并将头指针地址存储⾄Hash表对应桶的位置。这样定位到Hash桶的位置后可通过遍历单链表的形式来查找元素。

    数组内的元素通过next(下一个元素的索引)形成一个单链表。

    Hash桶

    是解决哈希表而引入的一个概念 ,为每一个hashCode 建立一个桶,桶里面放着一个数组(如上图 数组enteries)。

    Dictionary 接口

    1.变量定义

     从定义可知,字典的实现底层数据结构依靠的是数组。

    Add方法

          

      

    桶数量:
    if (buckets == null) Initialize(0); 初始化桶

    在初始化Hash桶数量的时候,若未自定义数量,首次分配3个。如果我们自定义了数量,自定义的值  会再根据 primes 数组进行计算,得出到底使用多大的桶数量。

    比如 实例化字典 自定义数量 3:

    System.Collections.Generic.Dictionary<int, string> dic = new System.Collections.Generic.Dictionary<int, string>(3);

    Resize();扩容

     Remove方法:

     

     ContainsKey 、TryGetValue 方法源码贴出,比较简单,不做解析。

     总结:

    Dictionary由数组构成,Hash函数作为地址构建,拉链法解决Hash冲突。Dictionary也是线程不安全的,因此在多线程访问的时候,需要自行加lock处理。

    源码地址:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs 

    参考文献:https://www.cnblogs.com/InCerry/p/10325290.html

  • 相关阅读:
    LeetCode OJ
    LeetCode OJ
    LeetCode OJ
    网页排版中的浮动和定位(学习笔记)
    在html中,<input tyle = "text">除了text外还有几种种新增的表单元素
    初学者入门web前端:C#基础知识:函数
    初学者入门web前端 C#基础知识:数组与集合
    while/for循环
    jmeter http请求与参数化
    rpm -e --nodeps
  • 原文地址:https://www.cnblogs.com/zhaolaosan/p/16244067.html
Copyright © 2020-2023  润新知