转帖:散列表
直接寻址
使用散列的目的是能够快速取得某个元素,那么如果能够保证每个元素都存在一个“槽”的话(类似于数组),就能够完成在O(1)
的时间内完成取元素的工作。如果一个集合的元素都是取自全域U={1, 2, ... m}
,那么通过使用数组T[1,...m]
来保证每个元素都存在与之对应的”槽“。
散列表
散列方式下,关键字k是放在h(k)
中,显然散列表方法中最主要的是如何设计散列函数,尽可能的减少散列之间的冲突。但是散列中的冲突是无法避免的,那么常见的两种解决方法是:链接法和开放寻址法。
链接法
链接法的核心思想就是冲突的元素(具有相同的h(k)
)存放在链表中。
开放寻址法
开放寻址法的核心思想如下:设具有关键字k的元素,通过散列函数h(x)
,映射到h(k)
,如果h(k)
已经被占用的话,那么尝试去试探h(k)+ i
,依次,直到找到一个合适位置去存放该元素。插入算法如下。
查找的算法也是比较简单,先查找位置h(k)
,如果不再该位置的话,通过开放寻址探查函数查找下一个位置,知道找到该元素,或者是没有找到。需要指出的是删除元素的情况,如果仅仅是简单讲该位置设为null的话,那么查找将遇到问题。如下图,如果查找5的话,首先查找到1,然后查找到3的时候,null表明已经结束,函数将返回“未找到”。解决方法就是删除时将3的位置设为特殊的标记IsDelete,然后查找时如果遇到IsDelete,那么继续向下查找。
散列函数的设计
散列函数的需求
显然如果要保证散列的高效性的话,需要将待散列的元素均匀的分布到各个槽中。
常见的散列函数
除法散列函数
h(k) = k mod m
乘法散列函数
h(k) = [m(kA mod 1)] (0<A<1)