字典(C#)之字典的工作原理
来源:互联网 发布:淘宝卖家id是什么 编辑:程序博客网 时间:2024/06/05 15:38
字典的使用非常方便,但这里有一个问题:Hashtable(和其它字典类)使用某种算法,根据键来确定每个对象的位置,实际上,该算法并不完全是由Hashtable提供的.它有两个部分,其中一部分的代码必须由key类来提供.如果使用一个Microsoft提供的类,并把这个类用作键(例如字符串),就不会有任何问题但如果自己编写的key,就必须自己编写这部分算法.
在计算机中,由key类执行的部分算法称为散列(因此字典也称为表),Hashtable在散列算法中有非常特殊的地位:它在对象的GetHashCode()方法中,继承了System.Object.只要字典类需要定位条目的位置,就会调用键对象的GegHashCode()方法.(感兴趣的同学可以查一下System.Object中的GetHashCode()).
其工作方式是GetHashCode()返回一个int,它应使用这个键的值来生成该int.Hashtable获取这个int,并对它进行其它的一些操作,其中涉及到一引起复杂的数学计算,最后返回一个索引,表示带有给定散列的条目在字典中的存储的位置.我们不详细介绍这部分算法,Microsoft 已经为这部分算法编写好了代码,所以不需要详细了解,但该算法用素数,而且这是散列表容量为什么应是一个素数的原因了.
为了使GetHashCode()重写方法正常工作,有一些相当严格的要求.这引起要求听起来相当抽象,难以理解,但不必太担心编写一个满足要求的key类也不是那么困难(如果有时间,再写出来后面的例子):
- 该方法应比较快(因为在字典中旋转或获取条目要求比较快)
- 该方法应比较一致,如果两个键表示相同的值,那么它们必须为散列提供相同的值.
- 该方法给出的原因是有一个潜在的问题:如果在字典中,两个条目的散列有相同的索引,该怎么办?
如果发生这种情况,字典就必须寻找最近的可利用的自由单元来存储第二个条目,必须进行一定的搜索,以便以后猎取这个条目.这显然会降低性能,如果许多键都有相同的索引,就有可能出现崩溃.根据Microsoft的部分算法工作的方式,在计算出来的散列值平均分布在int.MinValue和int.MaxValue之间时,这种崩溃的危险会被降低到最小.
字典的元素最多,键之间的崩溃危险也就越大,所以最好确保字典的容量大于其中的元素个数.因此,在字典被填满之前,Hashtable会自动重新分配内存,增大其容量.表被填满的比例称为负载(load),可以为这个负载设置一个最大值,在另一个Hashtable构造函数中给Hashtable重新分配内存前,该负载会达到这个最大值:
//capacity = 50,MaxLoad=0.5
Hashtable Employees = new Hashtable(50,0.5)
负载的最大值越小,散列表的工作次序就越高,但它占据的内存也越大.当散列表为了增大其容量而重新分配内存时,总会选择一个素数作为其新容量.
上面列出的另一个要点是,散列算法必须一致.如果两个对象包含相同的数据,它们就必须给出相同的散列值,这就是System.Object的Equals()和GetHashCode()方法时必须遵循的重要限制,Hashtable确定两个键A和B是否相等的方式就是调用A.Equals(B),即必须确保下述条件总是true:
如果A.Equals(B)是true,则A.GetHashCode()和B.GetHashCode()必须返回相同的散列.
这看起来可能非常微妙,但非常重要.如果采用重写这引起方法的方式不能保证上述语句为true,用这个类实例作为键的散列表就不可能正常工作.例如,把一个对象放在散列表中,但从来没有猎取过它,或者试图获取一个条目,但会返回错误的条目.
因此,如果为Equals()提供了一个重写方法,但没有为GetHashCode()提供重写方法,C#编译器就会显示一个编译警告.
对于System.Object,这个条件为true,因为Equals()仅比较引用,GetHashCode会根据对象的地址返回一个散列,则基于健步如飞的散列表没有重写这些方法,将正常工作.但是,这种方式也有问题,只有键是相同的对象时,才是相等的.当把一个对象放在字典中时,就必须挂起键的引用.以后也不能实例化另一个有相同值的键对象,国为相同的什被定义为表示相同的实例.如果没有重写Equals()和GetHashCode()和Object版本,类就不能在散列表中方便的使用因此,应根据键的值来执行GetHashCode(),生成一个散列,而不是根据内存中的地址来执行该方法,这就是必须为要用作键的类重写Equals()的原因.
System.String有三个重载方法,重载Equals()提供了值的对比,GetHashCode()也被相应地重载,根据字符串的值返回一个散列.因此,字典中把字符串用作键是非常方便的.
- 字典(C#)之字典的工作原理
- System.Collections中字典的介绍及其工作原理
- 字典(C#)之现实中的字典
- 字典(C#)之.NET中的字典
- Object-c之可变字典
- Objective-C基础之字典
- 【C#】之字典泛型
- 字典(C#)
- c# 字典
- #Objective-C 之 省市区 (数组-字典-数组-字典-数组)
- C#Dictionary 字典的用法
- Redis之四的字典
- python之字典的学习
- 字典
- 字典
- 字典
- 字典
- 字典
- 安装VMware Workstation后启动XP变慢
- java中-classpath和路径的使用
- c#备份数据库
- 在不同浏览器用不同css 解决IE和其他浏览器问题
- 工作中积累的一些名词解释
- 字典(C#)之字典的工作原理
- 学习笔记
- The VC++6.0 C++ source code for playing wave file
- i fi had a dollar for every time someone said that i would have my own web site
- 这些名词你不知道?!祝贺你被时代淘汰了?(图)
- C语言知识列表
- Hibernate入门
- 何谓Open-Relay?
- http://www.gpcarreon.com/