以下为学习笔记,来源于《数据结构与算法分析——C语言描述》
散列的插入、删除、查找时间为O(1),因为其不是像树一样通过比较来进行上面的操作,而是直接进行。
理想的散列表结构:一个包含有关键字的具有固定大小的数组。
表的大小记为TableSize,index从0到TableSize-1。
散列函数
(1)散列函数:每个关键字通过散列函数映射到0~TableSize-1这个范围的某个数,并且关键字被放到散列表适当的单元中。
(2)理想散列函数的要求:两个不同的关键字被映射到不同的单元;在TableSize大小的散列表里均匀地分配关键字。
(3)如果输入的关键字为整数,则一般合理的方法是返回“key mod TableSize”的结果;
通常,关键字是字符串,一种方法是把字符串中字符的ASCII码值加起来,再对TableSize求余。
冲突
(1)冲突:当一个元素插入散列表时,其插入的单元已经存在另一个元素时,就产生冲突,冲突需要消除。
(2)解决冲突的常用方法:分离链接法和开放定址法
分离链接法
其做法是将散列到同一个单元的所有元素保留到一个表中(即建立个链表保存这些冲突的元素),为了方便,这些表都有表头。
开放定址法
分离链接法缺点是需要指针,且给新单元分配地址需要时间,这使得算法的速度较慢。开放定址法,在发生冲突时尝试在原来的散列表里选择空的单元(而不是建新的空间),直到找到空的单元。单元的选择依据(Hash(X)+F(i))%TableSize,i=0,1,2,3……(遇到冲突时i才加1,没冲突时则不再加),Hash(X)为散列函数,即开始时映射出的关键字在散列表的位置。根据F(i)的不同可以分为线性探测法、平方探测法、双散列。
1)线性探测法
F(i)=i。
只要表够大,总能找到一个空间,但是如此花费的时间是较多的;即使表较空,元素占据的单元也会形成一些区块,称为一次聚集,这使得散列到区块的关键字要多次选单元才能解决冲突。
2)平方探测法
F(i)=i^2。
消除线性探测的一次聚集问题
一旦散列表被填了超过一半,当表的大小不是素数时甚至在表被填满一般之前,就不能保证一次找到一个空的单元了。
定理:使用平方探测,且表的大小时素数,那么当表至少有一般是空的时候,总能插入一个新的元素。
3)双散列
F(i)=i*hash2(X)。hash2(X)是新的散列函数,一般hash2(X)=R-(X%R)
再散列
当散列表快要填满时,操作的运行时间会变长,且insert操作会失败,此时一种解决放啊发是建立另外一个大约两倍大的表,扫描整个原始散列表,(使用新的散列函数)映射到到新表中。
可以在以下情况时开始再散列:
1)表满一半时即开始再散列
2)插入失败时开始
3)达到装填因子(散列表中元素个数/散列表的大小)时开始
来源:https://www.cnblogs.com/cs0915/p/12182255.html