hash(散列、杂凑)函数:将任意长度的数据映射到有限长度的域上。对一串数据m进行杂糅,输出一段固定h长度的数据,作为这个数据的特征(指纹)。hash 函数返回的值被叫做哈希值、哈希码、哈希。
hash表:一种实现关联数组的抽象数据结构,能把很多键映射到很多值上,使用哈希函数计算索引,一个索引一个值。哈希表与其他数据结构在新增、查找操作上的执行性能如下:
数组:采用一段连续的存储单元来存储数据。对于指定下标的查找,时间复杂度为O(1);通过给定值进行查找,需要遍历数组,逐一比对给定关键字和数组元素,时间复杂度为O(n),当然,对于有序数组,则可采用二分查找,插值查找,斐波那契查找等方式,可将查找复杂度提高为O(logn);对于一般的插入删除操作,涉及到数组元素的移动,其平均复杂度也为O(n)。数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;
线性链表:对于链表的新增,删除等操作(在找到指定操作位置后),仅需处理结点间的引用即可,时间复杂度为O(1),而查找操作需要遍历链表逐一进行比对,复杂度为O(n)。链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。
二叉树:对一棵相对平衡的有序二叉树,对其进行插入,查找,删除等操作,平均复杂度均为O(logn)。
哈希表:相比上述几种数据结构,在哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1),接下来我们就来看看哈希表是如何实现达到惊艳的常数阶O(1)的。
数据结构的物理存储结构有:顺序存储、链式存储(栈、队列、树、图从逻辑结构去抽象映射到内存中也是这俩种方式)哈希表的主干是数组(根据数组下标查找某个元素、一次定位就能达到)。
查找操作同理,先通过哈希函数计算出实际存储地址,然后从数组中对应地址取出即可。
比如我们要新增或查找某个元素,我们通过把当前元素的关键字 通过某个函数映射到数组中的某个位置,通过数组下标一次定位就可完成操作。存储位置 = f(关键字),其中,这个函数f一般称为哈希函数,这个函数的设计好坏会直接影响到哈希表的优劣。
hash碰撞:对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了。其解决方案有:开放定址法、再散列函数法、链地址法(HashMap采用的方法,即:数组+链表
p1:拉链法哈希表 p2从P2我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。
网友评论