本学习笔记部分内容来自网易云课堂浙江大学数据结构课程,谢谢!
1、散列表(哈希表)
已知的几种查找方法:
顺序查找 O(N)
二分查找(静态查找) O(logN)
二叉搜索树 O(h) h为二叉树高度 (动态查找:有插入有删除有查找)
平衡二叉树 O(logN)
查找的本质:已知对象找位置
1、有序安排对象:全序或半序;
2、直接算出对象位置:散列。
散列查找法的两项基本工作:
1、计算位置:构造散列函数确定关键词存储位置;
2、解决冲突:应用某种策略解决多个关键词位置相同的问题。
时间复杂度几乎为常量O(1),也就是说只要散列函数构造得好,查找时间与问题规模无关。
散列的基本思想:
1、以关键字key为自变量,通过一个确定的函数h(散列函数),计算出对应的函数值h(key),作为数据对象的存储地址;
2、可能不同的关键字会映射到同一个散列地址上,即h(keyi)=h(keyj),而(keyi不等于keyj),这称为冲突,需要某种冲突解决策略。
举例:
2、散列函数的构造方法
一个好的散列函数应该:1、计算简单,以提高转换速度;2、关键词对应的地址空间分布均匀,以减少冲突。
关键词为数字时:
a、直接定址法:取关键词的某个线性函数为散列地址,即h(key)=a*key+b;
b、除留余数法(常用):h(key)=key%p 一般p等于表达小,p一般要取素数;
c、数字分析法:分析数字关键字在各位上的变化情况,取比较随机的位作为散列地址,如电话号码、身份证号码某几位会比较随机;
d、折叠法:把关键词分割成位数相同的几个部分,然后叠加;
e、平方取中法:key取平方再取中间几位;
关键词为字符时:
a、ASCII码加和法:h(key)=(求和key[i])mod TableSize;
b、前3个字符移位法:h(key)=(key[0]*27*27+key[1]*27+key[2])mod TableSize;
c、移位法:
3、散列表的冲突处理方法
两种思路:1、开放地址法:换个位置存冲突数据;2、链地址法:同一位置的冲突对象组织在一起。
a、开放地址法:一旦产生了冲突(该地址已有其它元素),就按某种规则去寻找另一空地址。
若发生了第i此冲突,试探的下一个地址将增加di,即:hi(key)=(h(key)+di)mod TableSize;
di决定了不同的解决方案:线性探测:di=i,以增量1,2,...,TableSize-1循环试探下一个存储地址。
举例:h(key)=key mod 11;
查找某个值时,用散列函数计算完后,如果那个结果位置上的数字与关键词不一样时,并不能断定关键词不存在,还应该按照冲突解决策略继续找,直到找到空位置了还没找到,才能断定该关键词不存在。
平方探测(二次探测):di=正负i*i,以增量1方,-1方,2方,-2方,...,q方,-q方且q小于等于TableSize/2下取整,循环试探下一个存储地址。
举例:h(key)=key mod 11;
双散列:di=i*h2(key),h2(key)是另一个散列函数,h2(key)=p-(key
mod p)时效果最好。
再散列:当散列元素太多时(装填因子太大)时,查找效率会下降,实用装填因子一般取0.5到0.85.
当装填因子过大时,解决的方法是加倍扩大散列表,即再散列。
b、分离链接法:将相应位置上冲突的所有关键词存储在同一个单链表中。
举例:
4、散列表的性能分析
关键词的比较次数,取决于产生冲突的多少,如下三个因素会影响冲突的多少:
散列函数是否均匀、处理冲突的方法、装填因子
总结:选择合适的散列函数h(key),散列法的查找效率期望是O(1),它几乎与关键字的空间大小无关,也适合于关键字直接比较计算量大的问题。
散列方法是以较小的装填因子为前提的,是一个以空间换时间的方法。
散列方法的存储对关键字是随机的,不便于顺序查找关键字,不适合于范围查找或最大值最小值查找。
开放地址法:好:散列表是一个数组,存储效率高,随机查找。
不好:有聚集现象。
分离链法:散列表是顺序存储和链式存储的结合,链表部分的存储效率和查找效率都比较低。
好:关键字删除时没有存储垃圾;
不好:太小的装填因子可能会导致空间浪费,太大的装填因子又将付出更多的时间代价,不均匀的链表长度导致时间效率严重下降。
版权声明:本文为博主原创文章,未经博主允许不得转载。