散列表是一种通过元素(关键值)的散列码直接进行数据存取操作的数据结构。
散列码是通过散列函数获取的,一般好的散列函数很重要,可以把元素均匀的散列到数据表中,将有利于数据的存取操作。但是物理空间毕竟是有限的,所以会有不同的元素被散列到同一个位置,这是就涉及到了冲突的问题。这次的数据结构采用的则是分离链接的方式来解决冲突的问题的:具有相同散列码的元素存储在散列码对应的位置的链表中。
变量
- private List
[] theLists; //链表头的数组 - private int currentSize; //散列表中的元素个数
- private static int DEFAULT_SIZE = 101; //默认散列表大小
- private static float LOADFACTOR = 0.75f; //加载因子
构造器
|
|
散列函数
hash()
:散列函数,计算元素x的散列表,从而得到元素所在的链表的位置。计算散列值是可能会出现溢出的情况,这里做了一个小处理。
这里的散列函数只是简单的实现,可以通过实现一些更有效的散列函数使得元素在散列表中的分布更均匀。
|
|
rehash():
重散列函数。当散列表中的元素比例超过加载因子后,为了保证散列表的存取效率,需要对散列表进行扩容操作,然后进行元素的重散列。这样子可以避免具有相同散列码的元素过多,导致相应链表太长,降低了元素的查询效率。
重散列函数主要就是进行两项工作:
- 进行散列表大小的扩展;
- 重新散列原散列表中的元素。
|
|
函数
clear()
:重置哈希表为空表。
|
|
nextPrime()
:获取比n大的最小素数。
isPrime()
:判断n是否为素数。
这里使用了一个技巧,据研究表明散列表大小为素数的话,元素散列后的分布较均匀。(具体可以参考stackoverflow上的一些解释)
|
|
contains()
:查询表中是否包含元素x。通过散列码获取到对应的链表,通过链表的contains方法可以实现查找元素功能。
|
|
insert()
:插入元素x。插入元素的操作大部分时候的花销是很小的(O(1)),因为只要计算出散列码,并在对应的链表里追加元素即可。只有很少的情况下,表的元素比例达到了加载因子的界限,需要对表进行重散列操作,这时候不可避免的花销就大了(O(N))。
|
|
remove()
:删除元素x。删除元素x是很简单,只需要计算散列码后,从对应的链表中查找是否存在元素x,存在则删除。
|
|
源代码
|
|
参考资料
- 《数据结构与算法分析-java语言描述 第2版》Mark Allen Weiss. 机械工业出版社.