字典

本文介绍了C#中的字典数据结构,强调其通过键进行快速访问的特点。字典要求键类型实现GetHashCode()和Equals()方法以确保高效查找。文章讨论了散列代码的重要性,以及如何实现均匀分布以优化性能。通过EmployeeId和Employee类的示例,展示了如何正确实现键和值,以及如何使用字典初始化器和TryGetValue()方法进行操作。
摘要由CSDN通过智能技术生成

 字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。字典的主要特征是能根据键来快速查找值。也可以自由地添加和删除元素,这有点像List<T>类,但没有在内存中移动后续元素的性能开销。

键会转化为一个散列。利用散列创建一个数字,它将索引和值关联起来。然后索引包含一个到值的链接。一个索引项可以关联多个值,索引可以存储为一个树形结构。

.NET Framework提供了几个字典类。可以使用的最主要的类是Dictionary<TKey,TValue>。

字典初始化器

C#提供了一个语法,在声明时初始化字典。带有int键和string值的字典可以初始化如下:

            var dict = new Dictionary<int, string>()
            {
                [3] = "three",
                [7] = "seven"
            };

这里把两个元素添加到字典中。第一个元素的键是3,字符串值是three;第二个元素的键是7,字符串值是seven。这个初始化语法易于阅读,使用的语法与访问字典中的元素相同。

键的类型

用作字典中键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法。GetHadhCode()方法返回的int由字典用于计算在对应位置放置元素的索引。这里不介绍这个算法。我们只需要知道,它涉及素数,所以字典的容量是一个素数。

GetHashCode()方法的实现代码必须满足如下要求:

  • 相同的对象应总是返回相同的值。
  • 不同的对象可以返回相同的值。
  • 它不能抛出异常。
  • 它应至少使用一个实例字段。
  • 散列代码最好在对象的生存期中不发生变化。

除了GetHashCode()方法的实现代码必须满足的要求之外,最好还满足如下要求:

  • 它应执行得比较快,计算的开销不大。
  • 散列代码值应平均分布在int可以存储的整个数字范围上。

注:字典的性能取决于GetHashCode()方法的实现代码。

为什么使散列代码值平均分布在整数的取值范围内?如果两个键返回的散列代码值会得到相同的索引,字典类就必须寻找最近的可用空闲位置来存储第二个数据项,这需要进行一定的搜索,以便以后检索这一项。显然这会降低性能,如果在排序时许多键都有相同的索引,这类冲突就更可能出现。根据Microsoft的算法的工作方式,当计算出来的散列代码值平均分布在int.MinValue和int.MaxValue之间时,这种风险会降低到最小。

除了实现GetHashCode()方法之外,键类型还必须实现IEquatable<T>.Equals()方法,或重写Oject类的Equals()方法。因为不同的键对象可能返回相同的散列代码,所以字典使用Equals()方法来比较键。字典检查两个键A和B是否相等,并调用A.Equals(B)方法。这表示必须确保下述条件总是成立:

如果A.Equals(B)方法返回true,则A.GetHashCode()和B.GetHashCode()方法必须总是返回相同的散列代码。

这似乎有点奇怪,但它非常的重要。如果设计出某种重写这些方法的方式,使上面的条件并不总是成立,那么把这个类的实例用作键的字典就不能正常工作,而是会发生有趣的事情。例如,把一个对象放在字典中后,就再也检索不到它,或者试图检索某项,却返回了错误的项。

注:如果为Equals()方法提供了重写版本,但没有提供GetHashCode()方法的重写版本,C#编辑器就会显示一个编译错误。

对于System.Object,这个条件为true,因为Equals()方法只是比较引用,GetHashCode()方法实际上返回一个仅基于对象地址的散列代码。这说明,如果散列表基于一个键,而该键没有重写这些方法,这个散列表就能正常工作。但是,这么做的问题是,只有对象完全相同,键才被认为是相等的。也就是说,把一个对象放在字典中时,必须将它于该键的引用关联起来。也不能在以后用相同的值示例化另一个键的对象。如果没有重写Equals()方法和GetHashCode()方法,在字典中使用类型时就不太方便。

另外,System.String实现了IEquatable接口,并重载了GetHashCode()方法。Equals()方法提供了值的比较,GetHashCode()方法根据字符串的值返回一个散列代码。因此,在字典中把字符串用作键非常的方便。

数字类型(如Int32)也实现了IEquatable接口,并重载了GetHashCode()方法。但是这些类型返回的散列代码只映射到值上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值