数据结构 哈希表

什么是哈希表

Hash表也称散列表,也有直接译作哈希表,Hash表是一种根据关键字值(key - value)而直接进行访问的数据结构。
它基于数组,通过把关键字映射到数组的某个下表来加快查找速度,但是又和数组、链表、树等数据结构不同,在这些数据结构中查找某个关键字,通常要遍历整个数据结构,也就是O(N)的时间级,但是对于哈希表来说,只是O(1)的时间级。
注意,这里有个重要的问题就是如何把关键字转换为数组的下标,这个转换的函数称为哈希函数(也称散列函数),转换的过程称为哈希化。
一般哈希表都是用来快速判断一个元素是否出现在集合中。
图片
哈希函数
它把一个大范围的数字哈希(转化)成一个小范围的数字,这个小范围的数对应着数组的下标。使用哈希函数向数组插入数据后,这个数组就是哈希表。
哈希冲突
链地址法 --(拉链法)
这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
线性探测法
优点:易于实施;总是找到一个位置(如果有);当表不是很满时,平均情况 下的性能非常好。
缺点:表的相邻插槽中会形成“集群”或“集群”键;当这些簇填满整个阵列的大部 分时,性能会严重下降,因为探针序列执行的工作实际上是对大部分阵列的穷举搜索。
哈希表的优点
可以像数组一样通过下标随机访问。
弥补了数组只能通过整数索引访问的缺陷。
哈希表的缺点
每次存取数据之前要通过散列函数计算对应的散列值,消耗了更多内存。
装载因子 是散列表性能的衡量标准之一。因为散列表实际上还是数组,所以能承载的数据是有限的,当哈希表存储的数据超过数组索引的长度时则必然会出现散列冲突。

常见的三种哈希结构
当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。
数组
set(集合)
map(映射)
在C++语言中,实现在C++中,set 和 map 分别提供了以下三种数据结构,其底层实现以及优劣如下表所示:
图片
红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

图片

std::map 和std::multimap的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。
当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。
总结
总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

本文由博客一文多发平台 OpenWrite 发布!

alex
4 声望3 粉丝

一名入门的后端工程师