哈希表概述

基本概念

通过记录的存储位置和它的关键字之间建立一个确定的对应关系f以及处理冲突的方法,使得每个关键字和结构中一个唯一的位置相对应。这样对于关键字K根据对应关系f,就可以得到存储位置f(K)。称这种对应关系f为哈希函数。

与二叉树不同,哈希表中存储的数据是无序的,对于查找任意数据高效,二叉树查找某一范围的一些数据比较高效。

为了方便读者阅读后面的内容,这里列举一下HashTable实现中出现的基本概念。哈希表是一种通过哈希函数将特定的键映射到特定值的一种数据结构,他维护者键和值之间一一对应关系。

  • 键(key):又称为关键字。唯一的标示要存储的数据,可以是数据本身或者数据的一部分。
  • 槽(slot/bucket):哈希表中用于保存数据的一个单元,也就是数据真正存放的容器。
  • 哈希函数(hash function):将键(key)映射(map)到数据应该存放的槽(slot)所在位置的函数。
  • 哈希冲突(hash collision):哈希函数将两个不同的键映射到同一个索引的情况。

哈希表可以理解为数组的扩展或者关联数组,数组使用数字下标来寻址,如果关键字的范围较小且是数字的话,可以直接使用数组来完成哈希表,而如果关键字范围太大,如果直接使用数组我们需要为所有可能的key申请空间。很多情况下这是不现实的。即使空间足够,空间利用率也会很低,这并不理想。同时键也可能不是数字,所以人们使用一种映射函数(哈希函数)来将关键字映射到特定的域中。

数组:寻址容易,插入和删除困难;链表:寻址困难,插入和删除容易。

理想情况下,哈希表的插入和查找操作的时间复杂度均为O(1),任何一个数据项可以在一个与哈希表长度无关的时间内计算出一个哈希值,然后在常量时间内定位到一个桶。

使用哈希表的查找主要有如下两个步骤:

1.使用哈希函数将被查找的键转换为数组的索引。这个过程是将长度不同的字符串映射为固定长度的整数值。根据键的类型和哈希表的大小选择不同的哈希函数。

2.处理哈希冲突。因为键是所有任意长度的字符串,数量是无穷的,而哈希值长度固定的常数,数量是有限的,同时根据生日悖论,必然有不同的键映射到同一个哈希值,这就产生了哈希冲突。


哈希表是一个时间和空间做权衡的数据结构。如果没有内存限制,那么可以直接将键作为数组的索引,此时所有查找的时间复杂度是O(1);如果没有时间限制,将键无序存放,查找是顺序查找,时间复杂度是O(n)。而哈希表是在少量空间上实现约为O(1)时间复杂度的查找。

可以通过设计和使用不同的哈希函数和冲突解决方案在时间和空间性能上做取舍。

根据关键字的哈希值而直接进行访问。

哈希表在实践中使用的非常广泛,例如编译器通常会维护一个符号表来保存标记,很多高级语言中也显式的支持哈希表。哈希表通常提供查找(search),插入(insert),删除(delete)等操作,这些操作在最坏的情况下和链表的性能一样为O(n)。不过通常并不会那么坏,合理设计的哈希算法能有效地避免这类情况,通常哈希表的这些操作的时间复杂度为O(1)。这也是它被钟爱的原因。正是因为哈希表在使用上的便利性及效率上的表现,目前大部分动态语言的实现中都使用了哈希表。


参考

1.https://en.wikipedia.org/wiki/Hash_table

2.浅谈算法和数据结构: 十一 哈希表

3.深入理解PHP内核-哈希表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值