Dictionary, SortedDictionary, SortedList 比较

《C#零基础入门之百识百例》(八十九)SortedList和SortedDictionary介绍 --对比解析 排序列表是数组和哈希表的组合。它包含一个可使用键或索引访问各项的列表。如果您使用索引访问各项,则它是一个动态数组(ArrayList),如果您使用键访问各项,则它是一个哈希表(Hashtable)。集合中的各项总是按键值排序。 阅读详情

Dictionary, SortedDictionary, SortedList 是 .NET Framework 的三个支持泛型和关键字查找的类, 都属于 System.Collections.Generic 命名空间. 它们无论是名字还是功能都十分相似, 以至于实际运用的时候我们会经常混淆. 因此有必要比较一下它们.

1. 实现
查阅 MSDN 得到如下资料:
Dictionary<(Of <(TKey, TValue>)>) 泛型类提供了从一组键到一组值的映射。字典中的每个添加项都由一个值及其相关联的键组成。通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary<(Of <(TKey, TValue>)>) 类是作为一个哈希表来实现的。
检索速度取决于为 TKey 指定的类型的哈希算法的质量。

可见, Dictionary 基本上就是一个 Hashtable. 不过它比 Hashtable 类快, 因为它支持泛型~ (稍后我们会用实验证明, 即使使用 Object 类型的 Dictionary 也比 Hashtable 稍快).

--- 华丽的分割线 ---

SortedDictionary<(Of <(TKey, TValue>)>) 泛型类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数。就这一点而言,它与 SortedList<(Of <(TKey, TValue>)>) 泛型类相似。这两个类具有相似的对象模型,并且都具有 O(log n) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度:

SortedList<(Of <(TKey, TValue>)>) 使用的内存比 SortedDictionary<(Of <(TKey, TValue>)>) 少。

SortedDictionary<(Of <(TKey, TValue>)>) 可对未排序的数据执行更快的插入和移除操作:它的时间复杂度为 O(log n),而 SortedList<(Of <(TKey, TValue>)>) 为 O(n)。

如果使用排序数据一次性填充列表,则 SortedList<(Of <(TKey, TValue>)>) 比 SortedDictionary<(Of <(TKey, TValue>)>) 快。

每个键/值对都可以作为 KeyValuePair<(Of <(TKey, TValue>)>) 结构进行检索,或作为 DictionaryEntry 通过非泛型 IDictionary 接口进行检索。

只要键用作 SortedDictionary<(Of <(TKey, TValue>)>) 中的键,它们就必须是不可变的。SortedDictionary<(Of <(TKey, TValue>)>) 中的每个键必须是唯一的。键不能为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),但是如果值类型 TValue 为引用类型,该值则可以为空。

SortedDictionary<(Of <(TKey, TValue>)>) 需要比较器实现来执行键比较。可以使用一个接受 comparer 参数的构造函数来指定 IComparer<(Of <(T>)>) 泛型接口的实现;如果不指定实现,则使用默认的泛型比较器 Comparer<(Of <(T>)>)..::.Default。如果类型 TKey 实现 System..::.IComparable<(Of <(T>)>) 泛型接口,则默认比较器使用该实现。

C# 语言的 foreach 语句(在 C++ 中为 for each,在 Visual Basic 中为 For Each)需要集合中每个元素的类型。由于 SortedDictionary<(Of <(TKey, TValue>)>) 的每个元素都是一个键/值对,因此元素类型既不是键的类型,也不是值的类型。而是 KeyValuePair<(Of <(TKey, TValue>)>) 类型。

可见, SortedDictionary 类似一个平衡二叉查找树 (AVL). 既然是 BST, 我们当然可以对其进行中序遍历. 有两种方法:
1. For Each
2. Object.GetEnumerator

小实验:

  1. Dim TestObject As New SortedDictionary(Integer, Integer)
  2. With TestObject
  3.     .Add(7,2)
  4.     .Add(0,1)
  5.     .Add(5,3)
  6.     .Add(1,1)
  7.     .Add(4,4)
  8. End With
  9. For Each kvp As Collections.Generic.KeyValuePair(Of Integer, Integer) In TestObject
  10.     MsgBox kvp.Key
  11. Next
复制代码

得到的顺序是 0, 1, 4, 5, 7 (SortedList 同样)
但是如果把 SortedDictionary 换成 Dictionary, 结果就是 7, 0, 5, 1, 4.

另一种遍历方法:

  1. With TestObjectx.GetEnumerator()
  2.     While .MoveNext()
  3.         MsgBox(.Current.Key)
  4.     End While
  5. End With
复制代码

--- 华丽的分割线 ---

SortedList<(Of <(TKey, TValue>)>) 泛型类是具有 O(log n) 检索的二进制搜索树,其中 n 是字典中元素的数目。就这一点而言,它与 SortedDictionary<(Of <(TKey, TValue>)>) 泛型类相似。这两个类具有相似的对象模型,并且都具有 O(log n) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度:

SortedList<(Of <(TKey, TValue>)>) 使用的内存比 SortedDictionary<(Of <(TKey, TValue>)>) 少。

SortedDictionary<(Of <(TKey, TValue>)>) 可对未排序的数据执行更快的插入和移除操作,它的运算复杂度为 O(log n),而 SortedList<(Of <(TKey, TValue>)>) 的运算复杂度为 O(n)。

如果使用排序数据一次性填充列表,则 SortedList<(Of <(TKey, TValue>)>) 比 SortedDictionary<(Of <(TKey, TValue>)>) 快。

SortedDictionary<(Of <(TKey, TValue>)>) 类和 SortedList<(Of <(TKey, TValue>)>) 类之间的另一个区别是:SortedList<(Of <(TKey, TValue>)>) 支持通过由 Keys 和 Values 属性返回的集合对键和值执行高效的索引检索。访问此属性时无需重新生成列表,因为列表只是键和值的内部数组的包装。

二叉树的插入操作怎么是 O(n)?

网上有一种说法, 就是 SortedList 内部就是两个数组, 插入的时候类似 O(n^2) 的插入排序 (每个动作为 O(n)), 不过插入有序数据特别快 (每个动作变成 O(1)). 同样的情况出现在删除数据.

  1. Dim TestObject As New SortedList(Of Integer, Integer)
  2. For i As Integer = 1 To 1000000
  3.     TestObject.Add(i, RandomGenerator.Next())
  4. Next
复制代码

当然, RandomGenerator 是我们的随机数发生器:

  1. Dim RandomGenerator As New Random
复制代码

上述代码执行速度相当快, 因为插入的数据的 Key 值是有序的.
如果把 i 换成 1000000 - i, 则速度立刻慢得惨不忍睹.
同样的情况出现在把 i 替换成随机数. 在一段时间的等待后出错: 因为 Key 值不能重复.
这样说来, SortedList 不太像二叉树结构.

SortedList 还有一个功能, 就是直接访问 Key 值大小排名为 k 的 Key 和 Value.
方法是 Object.Keys(k) 和 Object.Values(k).
这更加印证了网上的说法.

我认为 SortedList 没什么用 - 除非是对基本有序的数据, 或者对内存非常吝啬. 如果仅仅需要在 BST 上加上查找排名为 k 的节点的功能, 可以使用一个经典算法: 在每个节点上加上一个 leftsize, 储存它左子树的大小. (当然也可以用 CQF 的 SBT. 那个 SB maintain... 扯远了~)

2. 功能
这三个类的功能上面都讲得差不多了. 因为实现就决定了功能. 这里小结一下.
Dictionary 的功能:
Add<K,V>, Clear, Contains<K/V>, GetCount, Enumerator (无序), GetItem<K>, Remove<K>
SortedDictionary 新增的功能:
Enumerator 为有序 - 对应 BST 的中序遍历.
SortedList 新增的功能:
Capacity(Set/Get) - 毕竟人家是数组
IndexOfKey, IndexOfValue (返回 Value 对应 Key 的排名而不是 Value 的排名)
Keys(k), Values(k) - 返回按照 Key 排序的数组的第 k 个元素

3. 速度
实践出真知 - 某名人.
理论和实践不符就是错的 - Thity.

我们的测试程序:

  1. Module DictionarySpeedTest
  2.     Dim RandomGenerator As New Random
  3.     Dim ArrayListData As New List(Of Key_N_Data)
  4.     Dim TestObject As New Dictionary(Of Long, Long)
  5.     Structure Key_N_Data
  6.         Dim Key As Int64
  7.         Dim Data As Int64
  8.     End Structure
  9.     Const ITEM_COUNT As Integer = 1000000
  10.     Const TEST_COUNT As Integer = 500000
  11.     Dim LastTick As Long
  12.     Sub TimerStart(ByVal Text As String)
  13.         Console.Write(Text)
  14.         LastTick = Now.Ticks
  15.     End Sub
  16.     Sub TimerEnd()
  17.         Dim t As Integer = Now.Ticks - LastTick
  18.         Console.WriteLine(((t) \ 10000).ToString() & " ms")
  19.     End Sub
  20.     Sub Main()
  21.         Process.GetCurrentProcess.PriorityClass = ProcessPriorityClass.High
  22.         Console.WriteLine(TestObject.GetType().ToString())
  23.         TimerStart("Generating data... ")
  24.         For i As Integer = 1 To ITEM_COUNT
  25.             Dim ThisKeyData As Key_N_Data
  26.             ThisKeyData.Key = (CLng(RandomGenerator.Next()) << 31) or RandomGenerator.Next()
  27.             ThisKeyData.Data = (CLng(RandomGenerator.Next()) << 31) or RandomGenerator.Next()
  28.             ArrayListData.Add(ThisKeyData)
  29.         Next
  30.         TimerEnd()
  31.         TimerStart("Test 1: add data test... ")
  32.         For Each Item As Key_N_Data In ArrayListData
  33.             TestObject.Add(Item.Key, Item.Data)
  34.         Next
  35.         TimerEnd()
  36.         TimerStart("Test 2: find data test... ")
  37.         For i As Integer = 1 To TEST_COUNT
  38.             With ArrayListData.Item(RandomGenerator.Next(0, ITEM_COUNT))
  39.                 If Not Equals(TestObject(.Key), .Data) Then MsgBox("Error!")
  40.             End With
  41.         Next
  42.         TimerEnd()
  43.         TimerStart("Test 3: remove data test...")
  44.         For i As Integer = 1 To TEST_COUNT
  45.             TestObject.Remove(ArrayListData.Item(RandomGenerator.Next(0, ITEM_COUNT)).Key)
  46.         Next
  47.         TimerEnd()
  48.     End Sub
  49. End Module
复制代码

通过更改 TestObject 的类型, 我们可以很方便地比较这三个类的速度. 测试结果:

                 ADD    FIND   REMOVE
Dictionary       265ms  203ms  187ms
SortedDictionary 1843ms 828ms  1234ms
SortedList       N/A

我们把 ITEM_COUNT 和 TEST_COUNT 都减小 10 倍:

                 ADD    FIND   REMOVE
Dictionary       15ms   31ms   15ms
SortedDictionary 93ms   46ms   38ms
SortedList       8031ms 15ms   6046ms

SortedList 的随机查找居然比 Dictionary 和 SortedDictionary (Hashtable 和 BST) 还要快. 这样说来, SortedList 似乎又不是简单的数组了. (不过我仍然觉得它没什么用)

4. 小结
如果只是当作索引使用, 请用 Dictionary.
如果需要查找最小的几个元素, 或者需要按顺序遍历元素, 就用 SortedDictionary.
如果输入/删除的元素是基本增序的, 或者访问次数远多于修改次数, 或者需要访问第 k 大的元素, 或者对内存吝啬得 BT 的情况, 用 SortedList 吧. (它居然成使用情况最多的了... orz)

PS: 微软似乎也很吝啬, SortedDictionary 居然只支持增序 (默认的比较器), 如果要降序的话, 我们得自己写一个比较器.

  1. Class MyComparer
  2.     Inherits Comparer(Of Long)
  3.     Public Overrides Function Compare(ByVal x As Long, ByVal y As Long) As Integer
  4.         Return Comparer(Of Long).Default.Compare(y, x)
  5.     End Function
  6. End Class
  7. Dim TestObject As New SortedList(Of Long, Long)(New MyComparer)
复制代码

现在我们可以来进行一下刚开始的时候提到的 Dictionary vs Hashtable 对决.

  1. Const ITEM_COUNT As Integer = 1000000
  2. Const TEST_COUNT As Integer = 500000
复制代码

ADD   FIND  REMOVE
Dictionary(Of Long, Long)     271ms 203ms 187ms
Dictionary(Of Object, Object) 468ms 312ms 234ms
Hashtable                     859ms 390ms 218ms

结论: 最好用 Dictionary 代替 Hashtable.

C# Dictionary和SortedDictionary的简介 1、SortedDictionary 泛型类 SortedDictionary 泛型类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数。就这一点而言,它与 SortedList 泛型类相似。这两个类具有相似的对象模型,并且都具有 O(log n) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度: SortedList 使用的内存比 SortedDictionary 少。 SortedDictionary 可对未排序的数据执行更快的插入和移除操作:它的时间复杂度为 O(log n),而SortedList 为 O(n)。 如果使用 立即下载

相关推荐

Unity Animancer插件(一)基本使用

Animancer是什么?资源商店主页我们来通过Animancer实现一个最基本的动画播放效果。首先创建一个脚本,编写如下代码 很容易理解,就是在时播放一个指定的动画片段。接下来为角色添加、和刚刚编写的,并为字段赋值 接下来运行游戏就可以看到效果了 此时角色身上的组件可以看到当前动画的各项参数 下面我们来实现通过按键控制角色在于之间转换。新创建一个脚本。在代码中监听Y轴上的输入。然后根据监听到的数值判断角色状态,并播放相应的动画 给对应字段赋值后,启动游戏看下效果 下面来实现一个开枪效果。在默认状态下,角色

夜槿笙歌的博客 1万+

字典排序_【c# .net】排序字典(SortedDictionary)

排序字典(SortedDictionary)1.简介SortedDictionary<TKey,TValue> 类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数。它与 SortedList<T> 泛型类相似。这两个类具有相似的对象模型,并且都具有 O(log n) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度:1)S...

weixin_42392689的博客 5735

window下迁移SVN仓库到新的windows服务器

window下迁移SVN仓库到新的windows服务器

Bertram的博客 4692

【C#】 SortedDictionary,查找字典中是否存在给定的关键字

最近有小伙伴咨询C#相关基础知识点SortedDictionary, 说实在的,这个类我也很少用,从字面上理解就是一个键值对,并且是含自动排序的键值对。 如果直接查询不存在的关键词,那么会直接报错,因此本篇文章来简单讲讲关键词判断

小5聊的博客 2342

similarity network fusion for aggregating data types on a genomic scale

基因组规模上的聚合数据类型的相似性网络融合 摘要:         近期的技术已经使收集不同类型的全基因组数据十分划算,结合这些数据去创建一个给定的疾病或生物过程的一个全面视图的计算方法是有必要的。相似网络融合(SNF:similarity network fusion)通过创建每一个可利用的数据类型的样本(如,患者)的网络可以解决这个问题。例如,创建一个给定一群患者疾病的全面视图,SNF计算

augustar学习笔记 7869

Ubuntu20.04 安装 MATLAB R2023b 常见问题及解决方案

本文提供了Ubuntu20.04系统上安装MATLAB R2023b的完整指南,包括系统要求检查、依赖项安装、详细安装步骤及常见问题解决方案。特别针对GTK模块加载失败、OpenGL图形加速问题和中文显示乱码等常见问题提供了有效解决方法,帮助用户顺利完成安装并优化使用体验。

weixin_42619061的博客 483

C# Dictionary和SortedDictionary简介

SortedDictionary泛型类是检索运算复杂度为 O(logn) 的二叉搜索树,其中n是字典中的元素数。就这一点而言,它与SortedList泛型类相似。这两个类具有相似的对象模型,并且都具有 O(logn) 的检索运算复杂度。这两个类的区别在于内存的使用以及插入和移除元素的速度: SortedList使用的内存比SortedDictionary少...

陈言必行 -- Unity游戏开发领域优质博主 1万+

别再瞎调参数了!分子动力学模拟新手必看的力场选择与验证实战指南

本文为分子动力学模拟新手提供力场选择与验证的实战指南,详细解析主流力场特性及适用场景,并通过水分子案例演示完整的验证流程。文章重点对比SPC/E、TIP3P和OPLS-AA三种力场在GROMACS中的表现,帮助读者避免常见参数调整误区,提升模拟准确性。

weixin_26934905的博客 425

c# SortedList、SortedDictionary、Dictionary、Hashtable比较

测试: 10万条数据,环境net4.0,耗时为毫秒 优劣势对比: 4种都属于key-Value键值对,SortedList、SortedDictionary、Dictionary都是泛型的,Hashtable值属于object类型,也就涉及到装箱和拆箱,所以可以看到插入、查询、删除耗时都比Dictionary长,但Hashtable为线程安全的。 有序集合SortedList和Sor...

czjnoe的博客 1624

接口操作MySQL跟MongoDB事务回滚问题

通常使用的事务注解:@Transactional 是不会对MongoDB生效的,但是在一些生产接口中无法避免同时使用MySQL跟MongoDB的操作。

weixin_45932023的博客 1578

YOLOv11知识蒸馏,实现无损涨点,包含逻辑蒸馏和特征蒸馏中的不同蒸馏方法,适用专栏内的所有模型

知识蒸馏(Knowledge Distillation)是由 Hinton 等人在 2015 年提出来的,主要是用一个复杂的教师模型去指导一个简单的学生模型训练,这样能让学生模型在保持高精度的同时,还能减少计算量。本文便是讲解如何针对的原始模型以及改进后的模型进行知识蒸馏,轻松实现无损涨点。知识蒸馏的核心在于利用已训练好的复杂模型(教师模型)去指导一个更简单的模型(学生模型)进行训练,以此让学生模型在保留较高精度的同时,降低计算成本。特征蒸馏(Feature Distillation)是知识蒸馏的一种形式,

Limiiiing的博客 4961

Hashtable、Dictionary、SortedDictionary、SortedList的比较应用

学习下解析Hashtable、Dictionary、SortedDictionary、SortedList的比较应用。 下面深入地分析如题的4个字典的原理。 我们先看Hashtable。 MSDN的解释:表示键/值对的集合,这些键/值对根据键的哈希代码进行组织。 Hash算法是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出

totty2006的专栏 2792

PCL 从LAS文件中获取点云的颜色【2026最新版】

PCL从LAS文件中获取点云的RGB信息(pcl::PointXYZRGB)并进行可视化。博客长期更新,本文最新更新时间为:2026年5月4日。

点云侠的博客 1720

[转载]SortedList实现排序 Dictionary, SortedDictionary, SortedList 比较

SortedList类默认是升序的,要改成降序要怎么改呢?通过实现IComparer:    public class ReverserSort : IComparer&lt;string&gt;    {        private bool Asc=true;        int IComparer&lt;KeyValueItem&gt;.Compare(string x, strin...

weixin_33720956的博客 185

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

GPU驱动植被GI:球谐函数与环境探针的底层实现

球谐函数(SH)是实时全局光照中低频辐射度建模的核心数学工具,其本质是在GPU上构建辐射度采样-投影-重建的计算流水线;环境探针(Ambient Probe)则承担着空间光照插值载体的关键角色,直接影响显存带宽与更新效率。二者协同构成动态GI的技术基座,支撑开放世界中植被等大规模实例的物理一致光照。在移动级GPU(如RTX 4060 Laptop)或异构多GPU环境下,需突破引擎封装层,直面内存布局、wavefront调度、compute queue优先级等硬件约束。本文聚焦SH系数手写优化、Probe数据

weixin_34356555的博客 380

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C#的Dictionary值排序和SortedDictionary键排序

对一个Dictionary&lt;TKey, TValue&gt;进行键排序可以直接用SortedDictionary SortedDictionary&lt;TKey, TValue&gt; 泛型类是检索运算复杂度为 O(log n) 的二叉搜索树,其中 n 是字典中的元素数。 就这一点而言,它与 SortedList&lt;TKey, TValue&gt; 泛型类相似。 这两个类具有相似的对...

杨镇宇的博客 902

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C# Dictionary, SortedDictionary, SortedList

就我个人觉得Dictionary, SortedDictionary, SortedList 这几个类的使用是比较简单的,只要稍微花点时间在网上查找一点资料,然后在阅读以下源码就理解的很清楚了。为什么要写这一片文章了,看一下code吧: Dictionary dict = new Dictionary(); //load data to dict int key = 1; object o

dz45693的专栏 8847

操练List - SortedList - Dictionary - SortedDictionary

基础准备 先人于网络对List - StoredList - Dictionary - StoredDictionary述之可谓备矣,然着墨点至高,如下是我对它们的实践。 首先,建一个工程项目,有个Form1,在Form1上放个Button1。然后,写个简单的类 Teacher public class Teacher { private readonly string name = ""; private readonly string sex = "";...

weixin_45707491的博客 216

深入解析Hashtable、Dictionary、SortedDictionary、SortedList

在《在线用户实体缓存解决方案》方案中使用Dictionary来存储,评论里同事说SortedDictionary采用二分法查找比Dictionary快,于是我们都做了测试,最后发现Dictionary是比SortedDictionary快的,前者用的是Hash算法,而后者是RB-Tree算法。于是想深入地分析如题的4个字典的原理。 我们先看Hashtable。MSDN的解释:表示键/值对...

weixin_30729609的博客 302
上一篇: emeditor12.0.4注册码
下一篇: ISAPI_Rewrite3.1 教程(一)
江南野鹤
博客等级 码龄23年 54粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值