C#:字典的工作原理

    在C#中,我们可能经常用到使用非常方便的Hashtable,不知大家是否知道它的另外一个名字:散列表.事实上Hashtable使用了某种算法,通过键(key)来确定每个对象的位置,实际上,该算法并不完全是Hashtable类提供的.它有两个部分,其中的一部分的代码是有key类来完成.我们平常在使用Hashtable的时候,key我们一般使用string类(部分算法string已经提供,Microsoft已经替我们做了),所以不会有任何的问题,但是如果key类是用户自己编写的,就必须自己编写这部分算法了.

    下面我们用EmployeeID类作为key类,来讲解如何编写自己的算法.

     在计算机中.由key类执行的部分算法成为散列,Hashtable在散列算法中有特殊的地位,它提供了对象的GetHashCode()方法,该方法继承于Sysetm.Object.只要字典需要确定数据项的位置,就会条用key对象的GetHashCode()方法.所以我们如果要是我们的key类起作用的话,就必须重写GetHashCode()方法.

      GetHashCode()方法的工作方式是:返回一个int型的数据,它使用这个键的值来生成int类型的数据.Hashtable获取这个值,并对它进行其他的一些操作,其中涉及一些非常复杂的计算,最后返回一个索引,表示带有指定散列的数据项在字典中的位置.这部分算法呢据说很复杂,非我辈能力所及,就不介绍了.免得招来拍砖无数.

     重载GetHashCode()方法就可以了吗?答案是否顶的!比如:如果再字典中,两个数据项的散列有相同的索引,该怎么办?所以要确保字典的容量大于其中元素的个数.而且,如果两个对象包含相同的数据,他们就必须给出相同的散列值.所以重写System.Object的Equals()和GetHashCode()方法时,必须考虑这个.

    下面我们通过具体的例子进行讲解:

     比如A公司建立了一个员工字典,该字典用EmployeeID对象做索引,存储的数据都是一个EmployeeData对象(员工的详细数据).我们的实例创建一个字典,添加了两个员工,通过员工的id,获取相应的信息.

     首先我们看下我EmployeeID类和EmployeeData类. EmployeeID类是关键,散列的部分算法就在EmployeeID类中实现.    


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for EmployeeID
/// </summary>

public class EmployeeID
{
    
public EmployeeID()
    
{
        
//
        
// TODO: Add constructor logic here
        
//
    }

    
public EmployeeID(string id)
    
{
        Id 
= id;        
    }

    
private string Id getset; }

    
//
    public override string ToString()
    
{
        
return base.ToString();
    }

    
//必须重写,否则EmployeeID类,不能作为key类,
    public override int GetHashCode()
    
{
        
return ToString().GetHashCode();
    }

    
//重载Equals方法,确保两个相同的对象,返回相同的散列值
    public override bool Equals(object obj)
    
{
        EmployeeID employeeID 
= obj as EmployeeID;
        
if (employeeID == nullreturn false;
        
if (this.Id == employeeID.Id) return true;
        
return false;
    }

}

   上面的代码 ,我们重点看下GetHashCode()方法,我们前面讲了,如果要实现散列算法,必须满足很多苛刻的要求.但是我们知道string类可以直接作为Hashtable的key类,说明Microsoft已经为string类提供了很有效的散列算法.所以我们直接应用string.GetHashCode()去重写我们的EmployeeID类的GetHashCode()方法.当然性能可能会有损失,因为EmployeeID类转换为string的时候会损失性能.

    EmployeeData类就没有什么特别的啦,就一些数据

   

EmployeeData类

 Main 测试代码

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace HashTableTest
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            Hashtable ht 
= new Hashtable();
            ht.Add(
new EmployeeID("A0001"), new EmployeeData("Johnny""24""Man"));
            ht.Add(
new EmployeeID("A0002"), new EmployeeData("Vicky""20""female"));
            ht.Add(
new EmployeeID("A0003"), new EmployeeData("Allen""30""male"));
            Console.WriteLine(
"Please input the Employee ID");
            
string userId = Console.ReadLine();
            
//当输入ID的是否,返回员工的详细数据
            EmployeeData E1 = (EmployeeData)ht[new EmployeeID(userId)];
            
if (E1 != null)
            
{
                Console.WriteLine(
"Employee " + userId+"Data is :");
                Console.WriteLine(E1.Name);
                Console.WriteLine(E1.Age);
                Console.WriteLine(E1.Gender);
            }

            Console.ReadLine();
        }

    }

}

结果如图所示

 

 

posted @ 2008-09-02 00:01  莫贝特(MBetter)  阅读(5493)  评论(18编辑  收藏  举报