哈希表:
概念:构造一种存储结构,通过某种函数关系使元素的存储位置与它的关键码之间建立一种一一对应的映射。
插入:
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
搜索元素:
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若
关键码相等,则搜索成功
哈希方法中使用的转换函数称为哈希函数,构造出来的结构称为哈希表。
冲突:
不同关键码通过相同的哈希函数计算出得到相同的哈希地址,称为哈希冲突或者哈希碰撞。
哈希函数设计原则:
①哈希函数的定义域必须包括需要存储的全部关键码。
②哈希函数计算出来的地址均匀分布在整个空间中。
③哈希函数应该比较简单。
常见的哈希函数:
直接定制法:取关键字的某个线性函数为散列地址:Hash(Key)=A*Key+B;
优点:简单,均匀。
缺点:需要事先知道关键字的分布情况
使用场景:适合查找比较小且连续的情况。
除留取余法:设散列表中允许的地址数为m,取一个不大于m,但是最接近或者等于m的质数p作为除数,按照哈希函数:
Hash(Key)=key%p(p<=m),将关键码转换为哈希地址。
冲突避免:负载因子调节
散列表的载荷因子:m=填入表中的元素个数/散列表的长度
m是散列表装满程度的标志因子,表长是定值,m与填入表中的元素个数成正比,m越大表明填入表中的元素越多,产生冲突的可能性就越大,m越小表明产生冲突的可能性就越小,负载因子越小越好,冲突率越低,数据个数不能动,把数组长度变大,事先控制好一个阈值,控制resize.
冲突解决:闭散列:①线性探测法②二次探测法
闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被填满,说明在哈希表中必然还有空位置,那么可以把Key存放到冲突位置的“下一个”空位置处。
线性探测法:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
开散列:哈希桶
开散列法又叫链地址法(开链法):首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一子集合称为一个桶,各个桶中的元素通过一个单链表连接起来,各链表的头节点存储在哈希桶中。
关于自定义类型作为HashMap的Key,HashSet的element 要保证:①覆写hashCode和equals()方法②
if (p.equals(q)){
p.hashCode()==q.hashCode();
}