哈希表
哈希表是一种数据结构,提供快速的插入操作和查找操作。不论哈希表中有多少数据,它的插入和删除(有时候包括删除)只需要接近常量的时间:O(1)的时间级。
哈希表查找非常快,如果需要一秒钟内查找上千条记录,通常使用哈希表(例如拼写检查器)。哈希表的速度明显比树快,树的操作通常需要O(N)。
哈希表的缺点是它是基于数组的,数组创建后,容量难以扩展。某些哈希表被基本填满后,性能下降的很严重,需要定期将数据转移到更大的哈希表中,这个过程比较费时间。
而且没有一种简单的办法,可以以任何一种顺序(例如从大到小)遍历表中的数据项。如果需要这种能力,只能选择其他数据结构。
然后,如果不需要有序遍历数据,并且可以提前预测数据量的大小,那么哈希表在速度和易用性方面无与伦比。
哈希函数
首先创建一个数组,它的长度是需要存储的数据项个数的两倍。
给每一个数据项,计算一个哈希值,并且通过 数据项的哈希值除以数组长度,取余,来判断数据项在数组中,应该存储的下标位置。
arraySize = recordeLength * 2;
indexArray = recordeHashCode % arraySize;
比如需要存储的数据项有5万个,那么数组的长度就应该是10万,那么当数据项的哈希值除以10万,取余时,会发生两种情况:
一种是这个数组,最多有一半下标中是保存数据项的,另一半是空的。
另一种情况是,可能有多个数据的哈希值是相同的,他们的取余结果也相同,这种情况叫做哈希冲突。
如何存储哈希冲突的数据项,有两种方式:
一种是通过系统的方法,找到数组中的另一个空位,并将冲突的数据项放入,叫做开放地址法。
第二种是创建一个存放哈希冲突数据项链表的数组, 数组内不存放数据项,而是存放链表。当发生哈希冲突时,新的数据项不存放在数组,而存放在数组下的链表中,这种方法叫做链地址法。
开发地址法有三种实现方式,当哈希冲突时它们在找下一个空白单元存放数据项使用的方法不同:
线性探测:
在线性探测中,线性的查找空白单元。如果5421是要插入的数据的位置,它已经被占用了,那么就使用5422,然后是5423,以此类推,数组下标一直递增,直到找到空位。这就叫线性探测,因为它沿着数组的下标一步一步顺序的查找空白单元。
理论上不允许重复,不允许聚集。
二次探测:
再哈希法: