哈希表经常会在面试中问道。这是因为它的确很重要。哈希表有很多应用,比如memcached的核心就是在内存中维护一张大的哈希表。
哈希表是如何实现的?如何解决地址冲突?
便于大家理解,我们倒着讲,先讲实现后讲概念。
哈希表有多种不同的实现方法,下面说的是由数组+链表组成的哈希表,也叫链地址法。
![ac1fd6264effe445dd45c0f5c2fd97f8.png](https://i-blog.csdnimg.cn/blog_migrate/ae7e61d8a3f943dc0731682e1db2f44c.jpeg)
哈希表
先说点简单易懂的。
首先分配一个指针数组,数组的每个元素是一个链表的头指针。
每个链表称为一个槽(Slot)。哪个数据应该放入哪个槽中由哈希函数决定,上图中我们简单地选取哈希函数h(x) = x % 11,这样任意数据 都可以映射成0~10之间的一个数,就是槽的编号,将数据放入某个槽的操作就是链表的插入操作。
如果每个槽里至多只有一个数据,这种情况下search、insert和delete操作的时间复杂度都是O(1)。
如果有多个数据放到同一个槽中,这称为碰撞(Collision),设计一个好的哈希函数可以把数据比较均匀地分布到各个槽中,尽量避免碰撞。
如果能把n个数据比较均匀地分布到m个槽中,每个糟里约有n/m个数据,则search、insert和delete和操作的时间复杂度都是O(n/m),如果n和m的比是常数,则时间复杂度仍然是O(1)。
一般来说,要处理的数据越多,构造哈希表时分配的槽也应该越多,所以n和m成正比这个假设是成立的。
不同数据结构 的时间复杂度:
![e48fef329ecff0ec490d34ba2b7599cc.png](https://i-blog.csdnimg.cn/blog_migrate/2f993f6eeb29623097d3af29fdd3a973.jpeg)
概念
哈希表(hash table)也叫散列表。
是根据关键码值(Key value)而直接进行访问的数据结构。
它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数(又叫哈希函数),比如上面例子的h(x) = x % 11,存放记录的数组叫做散列表。
哈希表的实现主要需要解决两个问题,哈希函数和冲突解决。
哈希函数 对不同的输出值得到一个固定长度的消息摘要。
哈希函数 当两个不同的输入值对应一个输出值时,就会产生“碰撞”,这个时候便需要解决冲突。
常见的冲突解决方法有开放定址法,链地址法,建立公共溢出区等。实际的哈希表实现中,使用最多的是链地址法。
链地址法的基本思想是,为每个 Hash 值建立一个单链表,当发生冲突时,将记录插入到链表中。 上面刚开始讲的就是这种方式。
![e00982345c5e9f1bfd8f421f99be4494.png](https://i-blog.csdnimg.cn/blog_migrate/b94e2a174eb6a8304fe6a9096a61b8ed.jpeg)