哈希表原理
哈希表初始使用 M M M个buckets存储数据,将数据对应的哈希值除以 M M M取余,根据余数存入对应的buckets中。当所有buckets中存储的数据总数 N N N超过一定限度时(如: N M ≥ 1.5 \frac{N}{M}\geq 1.5 MN≥1.5),将哈希表的buckets数量翻倍( M = 2 M M=2M M=2M),并将之前存储的数据按相同的方法重新分配。用链表存储的哈希表代码如下:
class IntNode:
def __init__(self, value, next_node, previous_node):
self.value = value
self.next = next_node
self.prev = previous_node
class DLList:
def __init__(self, value=None):
self.__sentinel = IntNode(None, None, None)
self.__sentinel.next = self.__sentinel
self.__sentinel.prev = self.__sentinel
self.__last = self.__sentinel.prev
self.__size = 0
def add_last(self, value):
self.__sentinel.prev = IntNode(value, self.__sentinel, self.__sentinel.prev)
self.__sentinel.prev.prev.next = self.__sentinel.prev
self.__last = self.__sentinel.prev
def is_contain(self, value):
p = self.__sentinel
while p.next is not self.__sentinel:
p = p.next
if p.value == value:
return True
return False
def get_values(self):
p = self.__sentinel
while p.next is not self.__sentinel:
p = p.next
yield p.value
class DataIndexedStringSet:
def __init__(self):
self.__m = 4
self.__buckets = [DLList() for _ in range(self.__m)]
self.__size = 0
def add(self, value):
if not self.is_contain(value):
self.__buckets[hash(value) % self.__m].add_last(value)
self.__size += 1
if self.__size / self.__m > 1.5:
self.__resize()
def is_contain(self, value):
return self.__buckets[hash(value) % self.__m].is_contain(value)
def __resize(self):
self.__m *= 2
new_buckets = [DLList() for _ in range(self.__m)]
for bucket in self.__buckets:
for value in bucket.get_values():
new_buckets[hash(value) % self.__m].add_last(value)
self.__buckets = new_buckets
一般来讲,数据的哈希值是平均分布的,所以每个buckets的链表长度约为
N
M
\frac{N}{M}
MN,即:每个buckets的链表长度为常数。因此,大部分操作的时间复杂度为
Θ
(
N
M
)
=
Θ
(
1
)
\Theta(\frac{N}{M})=\Theta(1)
Θ(MN)=Θ(1)。
再考虑resize
操作。实际上,resize
是一次时间复杂度为
Θ
(
N
)
\Theta(N)
Θ(N)的操作。故哈希表有少量的操作时间复杂度为
Θ
(
N
)
\Theta(N)
Θ(N)。但
N
N
N值通常非常大,所以resize
次数非常少,进一步可以证明所有操作的平均时间复杂度仍为
Θ
(
1
)
\Theta(1)
Θ(1)。
哈希表的使用大幅度的节省了内存,提升了效率。
字典的效率高于列表
字典(哈希表)查询的时间复杂度为
Θ
(
1
)
\Theta(1)
Θ(1),而列表查询的时间复杂度为
Θ
(
n
)
\Theta(n)
Θ(n)。
给定一个整数数组
n
u
m
s
nums
nums和一个目标值
t
a
r
g
e
t
target
target,在该数组中找出和为目标值的两个整数,返回他们的数组下标。
def twosum(nums, target):
hashmap = {}
for index, num in enumerate(nums):
if hashmap.get(target - num) is not None:
return [index, hashmap.get(target - num)]
hashmap[num] = index