`
javatgo
  • 浏览: 1192677 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

用哈希表搜索对象

阅读更多
.NET Framework中的大多数容器都是序列式容器(sequence containers):它们按顺序存储对象。这种类型的容器功能很多——你可以以任何特殊的顺序来存储任意数量的对象。

然而,这种多功能性是以一定的性能为代价的。在一个序列中查找一个特殊的对象所需要的时间取决于容器中对象的数量。如果我们没有对容器中元素进行排序,那么随着元素数量的增加,你所需要的查找时间也就直线增加了:如果容器中元素的数量增加了一倍,那么你用来查找一个特殊元素的时间也就增加了一倍。然而,如果我们对容器中的元素进行了排序,那么查找时间就是随着元素数量的对数而增加的了:要使查找一个元素的时间增加一倍,你必须使集合中的元素数量增加四倍。如果你用一个key来搜索对象,你可以用比序列式容器更好的方法来存储你的对象。你可以用哈希表(hash table)。

哈希表根据一个叫做hash的数字关键字(key)将对象存储在buckets中。hash value是从对象中的值计算得来的一个数字。每个不同的hash value都会创建一个新的bucket。要查找一个对象,你只需要计算这个对象的hash value并搜索相应的bucket就行了。通过快速地找到相应的bucket,就可以减少你需要搜索的对象数量了。

例如,设想在一个数据结构中有一些客户记录,你想通过信用卡号来搜索那些记录。一个简单的哈希函数将运用信用卡号的后两位数字,这会形成100个buckets——从00到99的每个两位数的数字都会创建一个bucket。(同样,运用后三位数字会创建1000个buckets。)只需要查询一个bucket,你就可以找到任何记录了,而不需要查询所有的buckets。

然而,同任何事情一样,并不是一切都这么简单的。如果你用信用卡号创建了一个哈希函数,而你想通过姓名来查找客户,你就需要查询整个哈希表,这样会花很多时间。这是因为哈希表是用一个不同的字段作为key的。而且,如果你查询整个哈希表,那么元素就没有必要按你期望的顺序来排列了。元素是根据hash value来排列的,而不是根据keys排列的。

在本篇文章中,我将详述我在前面的文章(“为更好的集合创建类”)中的样例,让你修改一条员工记录。假设有一个很大的公司,公司里有上千位员工,你想用最快的方法来找到一条记录。所有员工的一个哈希表可以使搜索在最短的时间完成。

一个哈希函数需要有一定的属性。对于初学者来说,哈希函数必须是不变的。这就是说相同的key必须生成相同的hash value,一旦创建了对象,hash value就不能改变了。如果hash value改变了,你在哈希表中就再也找不到相应的对象了。


<!--l version="1.0" encoding="utf-16-->

哈希函数需要的第二个属性就是能够平均分配buckets。如果所有的对象都生成相同的hash value,那么就需要更多的时间来查找一个特殊的对象。

实际上,这两个原则是很容易遵循的。在.NET Framework中有178个类重载了GetHashCode(),从而更好地发挥它们的作用。所有的.NET FCL(Framework Class Library)中类的实现都确保了hash value的更好的分配,并遵循了唯一性的原则。你应该确定你自己的类和结构是否需要重载GetHashCode()方法。最简单的(通常也是最好的)方法就是在key中选取一个不变的成员,并运用那个成员所生成的hash value。

员工数据库的一个明显的hash key就是社会保险号(Social Security Number)。它不仅不会改变,而且九位数的这个号码也可以让你任意运用以得到你期望的性能。你可以下载样例,看看运用hash keys进行搜索和运用序列式容器进行搜索有什么不同。

要把员工添加到一个哈希表中,你可以创建一个九位数的号码并把它作为key:

int hash = 111223333;
for (int i = 0; i < 100; i++)
{
   string lastname = "Person" + i.ToString();
   e = new Employee ("Employee", lastname, (200-i)*200);
   members.Add(hash++, e);
}

社会保险号满足了一个好的hash key的要求:它不会改变,它可以合理地分配、value取决于号码而不是reference。(你需要运用基于value的hash key而不是基于reference的hash key以避免我以前提到过的问题。)

运用这个hash key来查找对象也很简单:

 int ssn = Int32.Parse(this.SSN.Text);
currentEmp = (Employee)members[ssn];
if (currentEmp != null)
{
  LastName.Text = currentEmp.LastName;
  FirstName.Text = 
    currentEmp.FirstName;
  Salary.Text = 
    currentEmp.Salary.ToString ();
} else
  LastName.Text = "Not Found";

在C#中,你可以用数组语法在哈希表中查找对象。该语法强调了恒定时间搜索的概念:你可以把数组访问看做是一个快速的操作,而不是一个代价很高的函数调用。

关于哈希表最后的一个重点是,同所有的集合一样,它们也存储引用(references)。你不需要任何额外的工作来更新哈希表中的对象。一旦你引用了哈希表中的一个对象,你可以随意修改它。记住,同样的原则不适用于keys。你可以编写代码来改变keys,但如果那个代码修改了hash value,你就会丢失你的集合中的对象。

哈希表是很有用的、有效的容器。但是,要有效地运用它们,你需要了解容器和容器中对象的状态之间的关系。当你可以用从对象计算得来的不变的value来搜索对象时,哈希表就很有用。如果你用不同的顺序(通过姓名、社会保险号、或年龄)在对象中搜索,那么哈希表就不那么有用了。

分享到:
评论

相关推荐

    e语言-易语言哈希表对象

    7. **项目是否存在**:通过键来判断某个项目是否存在于哈希表中,这是快速检查数据是否已存储的关键操作,避免了不必要的搜索。 8. **保存数据到文件**:哈希表对象可以将其中的数据序列化并保存到文件,便于持久化...

    C++源代码:哈希表算法

    哈希函数是哈希表的核心,它的作用是将输入(通常是字符串或对象的键)转换为数组的索引。理想的哈希函数应该能够均匀地分布输入,避免冲突,即不同的输入不会映射到相同的索引。C++标准库提供了一个容器`std::...

    哈希表搜索算法介绍和java代码实现

    哈希表搜索算法是计算机科学中一种非常重要的数据结构和算法,它主要依赖于哈希函数来实现快速的查找、插入和删除操作。哈希表(Hash Table)以键-值对的形式存储数据,其中键(Key)是用于查找的标识,而值(Value...

    哈希表应用C++_STL_hash

    - **字典查找**:哈希表常用于字典和搜索引擎的关键词索引,实现快速定位。 - **缓存**:在内存有限的情况下,哈希表可以用来实现LRU(最近最少使用)缓存策略。 - **唯一性验证**:例如在处理大量数据时,快速找...

    哈希表的设计与实现 数据结构课程设计

    在数据结构课程设计中,理解和掌握哈希表的设计与实现至关重要,因为它广泛应用于软件工程的多个领域,如数据库索引、缓存系统、字符串搜索等。 1. **哈希函数**:哈希函数是哈希表的核心,它的目标是将键转化为数...

    chapter_10_映射、哈希表和跳跃表.zip

    哈希表是一种通过计算对象的哈希码来确定其存储位置的数据结构,它使得查找操作的时间复杂度接近O(1)。在Python字典中,键必须是不可变类型,如字符串、数字或元组,而值可以是任意类型。字典的操作包括创建、访问、...

    严蔚敏 数据结构 ppt 哈希表 数 图

    哈希表是一种高效的数据结构,主要用于快速查找和存储数据。它通过哈希函数将数据映射到一个固定大小的数组中,以达到快速访问的目的。哈希冲突是哈希表面临的主要挑战,解决冲突的方法有开放寻址法、链地址法等。 ...

    aaa.rar_哈希表的创建

    例如,在JavaScript中,对象的本质就是一个哈希表,键被转换为字符串后作为哈希表的键,而对应的值则存储在对应的索引位置。 `aaa.cpp` 文件可能包含了一个简单的哈希表实现,你可以通过阅读源代码来理解上述概念...

    关于哈希表、Python100道题

    哈希函数是哈希表的核心,它将输入(通常是字符串或者对象)转化为数组的索引。理想的哈希函数应具备以下特点:均匀分布性,避免冲突,以及快速计算。当不同的键通过哈希函数映射到相同的索引位置时,就发生了冲突。...

    单词备忘录的创建(哈希表)

    在本主题中,我们将深入探讨如何使用C++创建一个单词备忘录,它利用哈希表的特性来快速查找和管理词汇。哈希表的核心思想是通过哈希函数将数据(在这里是单词)映射到一个固定大小的数组中,实现快速访问。 首先,...

    lol-hash:英雄联盟的哈希表

    或者,在内存有限的情况下,数组型的哈希表可能会占用过多空间,此时可以考虑使用平衡二叉搜索树等替代数据结构。 在“lol-hash-master”这个压缩包中,很可能包含了用于《英雄联盟》哈希表实现的相关代码或示例。...

    算法面试通关40讲完整课件 14-17 哈希表(HashTable)

    - **分组字母异位词**:LeetCode的`Group Anagrams`问题,可以使用哈希表存储经过排序后的字符串,快速找出所有字母异位词。 在面试中,理解和熟练运用哈希表及其相关概念是至关重要的,因为它们是解决许多复杂...

    易语言哈希表对象源码-易语言

    在易语言中,哈希表对象允许开发者使用自定义哈希函数,也可以选择系统提供的默认哈希函数。 "易语言哈希表对象源码"是易语言社区中一份珍贵的资源,它可能为易语言学习者或是项目开发者提供了一个学习哈希表实现的...

    Hash-table-JS-simplified:在计算中,哈希表(哈希表)是一种实现关联数组抽象数据类型的数据结构,该结构可以将键映射到值。 哈希表使用哈希函数来计算存储桶或插槽数组的索引,从中可以找到所需的值

    哈希表,又称为散列表,是计算机科学中一种高效的数据结构,用于实现关联数组,它能够通过键...通过学习和实践这个项目,开发者可以提升对哈希表原理的理解,以及在JavaScript中如何高效地使用对象作为哈希表的能力。

    C#中哈希表(HashTable)用法实例详解(添加/移除/判断/遍历/排序等)

    - 当你需要频繁查询数据时,哈希表的查找速度通常比线性搜索快得多。 - 当数据量较大时,哈希表的效率优势更为明显。 - 当查询字段包含字符串类型时,哈希表的键可以是字符串,方便查找。 - 当数据类型不唯一,...

    轻松学习C#的哈希表

    在C#语言中,还有一种用于快速搜索而组织的键/值组合的数组,这种数组叫做关联数组,也叫做哈希表(Hashtable)。  哈希表也在System.Collection命名空间下,用于处理和表现类似key/value的键值对,其中key通常用来...

    C#算法实现(哈希表 图 二叉树 KMP prim 最短路径 各种排序)

    1. **哈希表**:哈希表是一种数据结构,它提供了快速的插入、删除和查找操作,通常实现为散列表。在C#中,`Dictionary, TValue&gt;`是哈希表的一个常见实现,通过键值对存储数据,平均时间复杂度为O(1)。哈希表在处理...

    C语言实现数据结构(栈,双向链表,十字链表,平衡树,图,哈希表).zip

    本资源“C语言实现数据结构(栈,双向链表,十字链表,平衡树,图,哈希表)”提供了一系列C语言编写的关于经典数据结构的实现代码,对于学习和理解这些数据结构的底层工作原理非常有帮助。 1. **栈(Stack)**:栈是一种...

    C语言实现部分数据结构和算法,包括链表,栈,队列,哈希表,树,排序算法,图算法等等.zip

    4. **哈希表**:哈希表是一种通过哈希函数将键映射到索引的数据结构,提供快速的查找、插入和删除操作。冲突解决方法有开放寻址法和链地址法。C语言实现哈希表通常需要自定义哈希函数和处理冲突的策略。 5. **树**...

    C++股票信息查询系统源代码,实现多种查询排序算法KMP算法、二叉树、哈希表等,C++课程设计

    这个系统采用了一系列高级编程技术,如KMP算法、二叉树和哈希表,以高效地处理股票信息查询。下面我们将详细探讨这些关键知识点。 1. **KMP算法**: KMP(Knuth-Morris-Pratt)算法是一种字符串匹配算法,用于在一...

Global site tag (gtag.js) - Google Analytics