根据数据结构书上的讲解,查找包括暴力遍历、折半查找以及二叉树查找。其中顺序查找和折半查找适合静态查找,折半查找前提线性表必须是有序的。三种查找算法的时间复杂度分别是 O ( n ) , O ( l o g n ) , O ( l o g n ) O(n),O(logn),O(logn) O(n),O(logn),O(logn)。线性表和树表都是通过比较关键字的方法,查找的效率取决于关键字的次数。有没有一种方法可以不进行关键字比较,直接找到目标?那就是散列表的查找,也称哈希表。是通过散列函数将关键字映射到存储地址,建立了关键字和存储地址的一种直接映射关系。
- 哈希表包括哈希函数,处理冲突的方法和查找性能等三个方面。
这里主要讲解python中dict使用的哈希表,最低能在
O
(
1
)
O(1)
O(1)时间内完成搜索!python中dict在处理冲突的时候采用的是开放寻址法,开放寻址法是在线性存储空间上的解决方案,也称为闭散列。当发生冲突时,采用冲突处理方法在线性存储空间上探测其他位置:
h
a
s
h
,
(
k
e
y
)
=
(
h
a
s
h
(
k
e
y
)
+
d
i
)
hash^,(key) = (hash(key)+d_i)%m
hash,(key)=(hash(key)+di)
开放寻址法又分为线性探测法、二次探测法、随机探测法和再散法。
开放寻址法
- 线性探测法
线性探测法是最简单的开发地址法,线性探测的 d i d_i di每次增加1,即:
d i d_i di = 1,…,m-1。
线性探测法比较简单,只要有空间就会一直探测直到探测到位置为止。但是处理冲突的过程中,会出现非同义词对同一个散列地址争夺的现象,称为“堆积”。 - 二次探测法
二次探测法采用前后跳跃式探测的方法,即以增量平方的形式进行探测,避免堆积。增量序列如下:
d i = 1 2 , − 1 2 , 2 2 , − 2 2 , . . . k 2 , − k 2 ( k < = m / 2 ) d_i = 1^2,-1^2,2^2,-2^2,...k^2,-k^2(k<=m/2) di=12,−12,22,−22,...k2,−k2(k<=m/2)
注意:二次探测法是跳跃式探测,效率较高,但是会出现有存储空间但是探测不到的情况,因而存储失败,而线性探测是只要有空间就一定能够探测成功。 - 随机探测法
采用伪随机数进行探测,利用伪随机数避免堆积。随机探测的增量序列为:
d i = d_i= di=伪随机序列 - 再散列法
当通过散列函数得到的地址发生冲突时,再利用第二个散列函数处理,称为双散列法。其增量序列为: d i = h a s h 2 ( k e y ) d_i = hash_2(key) di=hash2(key)
注意:开放地址法处理冲突时,不能随便删除表中的元素,若删除元素会截断其他后续元素的查找。因为在查找过程中,遇到空就会返回查找失败,因此要删除一个元素式,可以做一个删除标记,表示该元素已经删除。
LeetCode刷题
该题链接:https://leetcode-cn.com/problems/contains-duplicate/
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
t_dict = {}
for num in nums:
if num not in t_dict.keys():
t_dict[num] = 1
else:
return True
return False