在框架中,字典的选择要比列表少得多。只有三个主流的非并发 IDictionary<TKey, TValue> 实现,此外还有 ExpandoObject (第14章已介绍过)、 ConcurrentDictionary (将 在介绍其他并发集合时介绍)和 RouteValueDictionary (用于路由Web请求,特别是在ASP.NET MVC中)也实现了该接口。

  注意,字典的主要目的在于为值提供有效的键查找。

B.3.1  Dictionary<TKey, TValue>

  如果没有特殊需求, Dictionary<TKey, TValue> 将是字典的默认选择,就像 List<T> 是 列表的默认实现一样。它使用了散列表,可以实现有效的查找(参见http://mng.bz/qTdH),虽然 这意味着字典的效率取决于散列函数的优劣。可使用默认的散列和相等函数(调用键对象本身的 Equals 和 GetHashCode ),也可以在构造函数中指定 IEqualityComparer<TKey> 作为参数。 最简单的示例是用不区分大小写的字符串键实现字典,如代码清单B-1所示。

            var comparer = StringComparer.OrdinalIgnoreCase;
var dict = new Dictionary<string, int>(comparer);
dict["Test"] = ;
Console.WriteLine(dict["test"]);

  尽管字典中的键必须唯一,但散列码并不需要如此。两个不等的键完全有可能拥有相同的散 列码;这就是散列冲突(hash collision) ① ,尽管这多少会降低字典的效率,但却可以正常工作。 如果键是易变的,并且散列码在插入后发生了改变,字典将会失败。易变的字典键总是一个坏主 意,但如果确实不得不使用,则应确保在插入后不会改变。

  散列表的实现细节是没有规定的,可能会随时改变,但一个重要的方面可能会引起混淆:尽 管 Dictionary<TKey, TValue> 有时可能会按顺序排列,但无法保证总是这样。如果向字典添加 了若干项然后迭代,你会发现项的顺序与插入时相同,但请不要信以为真。有点不幸的是,刻意 添加条目以维持排序的实现可能会很怪异,而碰巧自然扰乱了排序的实现则可能带来更少的混淆。

  与 List<T> 一样, Dictionary<TKey, TValue> 将条目保存在数组中,并在必要的时候进 行扩充,且扩充的平摊复杂度为O(1)。如果散列合理,通过键访问的复杂度也为O(1);而如果所 有键的散列码都相等,由于要依次检查各个键是否相等,因此最终的复杂度为O(n)。在大多数实 际场合中,这都不是问题。

B.3.2  SortedList<TKey, TValue> 和 SortedDictionary<TKey, TValue>

  乍一看可能会以为名为 SortedList<,> 的类为列表,但实则不然。这两个类型都是字典, 并且谁也没有实现 IList<T> 。如果取名为 ListBackedSortedDictionary 和 TreeBacked- SortedDictionary 可能更加贴切,但现在改已经来不及了。

  这两个 类有很多共 同点:比较 键时都使用 IComparer<TKey> 而 不是 IEquality- Comparer<TKey> ,并且键是根据比较器排好序的。在查找值时,它们的性能均为O(log n),并 且都能执行二进制搜索。但它们的内部数据结构却迥然不同: SortedList<,> 维护一个排序的 条 目 数 组 , 而 SortedDictionary<,> 则 使 用 的 是 红 黑 树 结 构 ( 参 见 维 基 百 科 条 目 http://mng.bz/K1S4)。这导致了插入和移除时间以及内存效率上的显著差异。如果要创建一个排 序的字典, SortedList<,> 将被有效地填充,想象一下保持 List<T> 排序的步骤,你会发现向 列表末尾添加单项是廉价的(若忽略数组扩充的话将为O(1)),而随机添加项则是昂贵的,因为 涉及复制已有项(最糟糕的情况是O(n))。向 SortedDictionary<,> 中的平衡树添加项总是相 当廉价(复杂度为O(log n)),但在堆上会为每个条目分配一个树节点,这将使开销和内存碎片比 使用 SortedList<,> 键值条目的数组要更多。

  这两种集合都使用单独的集合公开键和值,并且这两种情况下返回的集合都是活动的,因为 它们将随着基础字典的改变而改变。但 SortedList<,> 公开的集合实现了 IList<T> ,因此可以 使用排序的键索引有效地访问条目。

  我不想因为谈论了这么多关于复杂度的内容而给你造成太大困扰。如果不是海量数据,则可 不必担心所使用的实现。如果字典的条目数可能会很大,你应该仔细分析这两种集合的性能特点, 然后决定使用哪一个。

B.3.3  ReadOnlyDictionary<TKey, TValue>

  熟悉了B.2.5节中介绍的 withReadOnlyCollection<T> 后, ReadOnlyDictionary<TKey, TValue> 应该也不会让你感到特别意外。 ReadOnlyDictionary<TKey, TValue> 也只是一个 围绕已有集合(本例中指 IDictionary<TKey, TValue> )的包装器而已,可隐藏显式接口实 现后所有发生变化的操作,并且在调用时抛出 NotSupportedException 。

  与只读列表相同, ReadOnlyDictionary<TKey, TValue> 的确只是一个包装器;如果基 础集合(传入构造函数的集合)发生变化,则这些修改内容可通过包装器显现出来。

B.3 字典的更多相关文章

  1. 【DG】Oracle_Data_Guard官方直译

    [DG]Oracle Data Guard官方直译 1 Oracle Data Guard 介绍   Oracle Data Guard概念和管理10g版本2   Oracle Data Guard ...

  2. DVWA实验之Brute Force(暴力破解)- Low

    DVWA实验之Brute Force-暴力破解- Low     这里开始DVWA的相关实验~   有关DVWA环境搭建的教程请参考: https://www.cnblogs.com/0yst3r-2 ...

  3. Oracle错误览表

    Oracle 错误总结及问题解决 ORA     本文转自:https://www.cnblogs.com/zhangwei595806165/p/4972016.html  作者@承影剑 ORA-0 ...

  4. Javacript实现字典结构

    字典是一种用[键,值]形式存储元素的数据结构.也称作映射,ECMAScript6中,原生用Map实现了字典结构. 下面代码是尝试用JS的Object对象来模拟实现一个字典结构. <script& ...

  5. python 数据类型 ----字典

    字典由一对key:value 组成的 python中常用且重量级的数据类型 1. key , keys, values 字典由一对key:value 组成的 python中常用且重量级的数据类型 1. ...

  6. 增强版字典DictionaryEx

    代码 public class DictionaryEx<TKey, TValue> : IDictionary<TKey, TValue> { /// <summary ...

  7. python学习笔记(字符串操作、字典操作、三级菜单实例)

    字符串操作 name = "alex" print(name.capitalize()) #首字母大写 name = "my name is alex" pri ...

  8. python之最强王者(8)——字典(dictionary)

    1.Python 字典(Dictionary) 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包 ...

  9. python序列,字典备忘

    初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...

  10. PowerDesigner从Sqlserver中反转为带注释的字典及快捷键操作

    PowerDesigner的操作经常忘记,所以把常用的功能记录下来备忘. 1.修改反转过来的字段 PowerDesigner从数据库反转的时候,默认不带注释,需要先进行修改. 输入如下脚本: {OWN ...

随机推荐

  1. js 实现对ajax请求面向对象的封装

             AJAX 是一种用于创建高速动态网页的技术.通过在后台与server进行少量数据交换.AJAX 能够使网页实现异步更新.这意味着能够在不又一次载入整个网页的情况下,对网页的某部分进行 ...

  2. 表格属就用treegrid

    http://maxazan.github.io/jquery-treegrid/ 如果想ajax后台动态添加表格数据然后再形成treegrid,那么可以通过后台给一个对应行索引的数组, 进行动态改变 ...

  3. LeetCode 246. Strobogrammatic Number (可颠倒数字) $

    A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...

  4. android 4.0主线程訪问网络问题

    在4.0下面,在主线程中訪问网络,假设请求超过6s的话,就会报ANR,那么这就会带来一个问题,假设网络慢或者请求的数据过大时,界面会卡顿,造成界面灵敏性非常差,因此网络请求一般不能放在主线程中操作,g ...

  5. ALSA声卡驱动中的DAPM详解之三:如何定义各种widget

    上一节中,介绍了DAPM框架中几个重要的数据结构:snd_soc_dapm_widget,snd_soc_dapm_path,snd_soc_dapm_route.其中snd_soc_dapm_pat ...

  6. 收集主机OS相关数据

    #!/usr/bin/ksh touch hostinfo$(date +%Y%m%d).csv filename=hostinfo$(date +%Y%m%d).csv >${filename ...

  7. codevs4511信息传递(Tarjan求环)

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  8. Java中的管道流 PipedOutputStream和PipedInputStream

    我们在学习IO流的时候可能会学字节流.字符流等,但是关于管道流的相信大部分视频或者教程都是一语带过,第一个是因为这个东西在实际开发中用的也不是很多,但是学习无止境,存在既有理.JDK中既然有个类那说明 ...

  9. Java中多个线程交替循环执行

    有些时候面试官经常会问,两个线程怎么交替执行呀,如果是三个线程,又怎么交替执行呀,这种问题一般人还真不一定能回答上来.多线程这块如果理解的不好,学起来是很吃力的,更别说面试了.下面我们就来剖析一下怎么 ...

  10. array_column()函数兼容低版本

    array_column 用于获取二维数组中的元素(PHP 5.5新增函数),但我们有时候需要在低版本的 function i_array_column($input, $columnKey, $in ...