配合前置文章食用更佳,传送门如下:
实现Hash表(一)----手写一个简单hash表
问题描述
在上一篇文章中,我们已经实现了自己的hash表结构,但是当两个key映射同一个value时,就会发生冲突,我们应该对冲突进行处理,使得发生冲突时也可以正常添加和删除。
解决办法
这里我们采用最简单的方法,实际算法可能要比这个复杂得多,但是原理是相同的
解决办法:当冲突发生的时候,向后遍历,找到第一个为None的位置,返回对应的index
所以在计算index的时候,会遇到如下几种情况:
- index所在位置为None,无冲突,可以直接返回
- index所在位置已经被占据,向后遍历,遇到key和所要插入的key相同的项,返回对应的index
- index所在位置已经被占据,向后遍历,遇到第一个None,返回对应的index
- index所在位置已经被占据,向后遍历,但是超出了最大长度,这时需要从头继续遍历
具体参照下面的
get_valid_index
的实现
python的实现
MAX_HASH_TABLE_SIZE = 4096
def get_index(data_list, a_string):
# 存储hash值
result = 0
for a_character in a_string:
# 获取ASCII码
a_number = ord(a_character)
# 更新hash值
result += a_number
# 通过取余数获取索引值
list_index = result % len(data_list)
return list_index
def get_valid_index(data_list, a_string):
"""
:param data_list:
:param a_string: 输入的key
:return: 处理冲突后的索引
当有冲突发生时(也就是两个字符串对应一个key),先映射,如果有值了那个位置
就向后寻找第一个非none值对应的索引,对其进行更新
"""
index = get_index(data_list, a_string)
while True:
key_value = data_list[index]
if key_value is None:
return index
key, value = key_value[0], key_value[1]
if key == a_string:
return index
index += 1
if index == len(data_list):
index = 0
class HashTable:
"""
处理过冲突的hashtable
两个key对应一个索引,也可以正常运行
"""
def __init__(self, max_size=MAX_HASH_TABLE_SIZE):
self.data_list = [None] * max_size
def insert(self, key, value):
# 1. Find the index for the key using get_valid_index
index = get_valid_index(self.data_list, key)
# 2. Store the key-value pair at the right index
self.data_list[index] = (key, value)
def find(self, key):
# 1. Find the index for the key using get_valid_index
index = get_valid_index(self.data_list, key)
# 2. Retrieve the data stored at the index
kv = self.data_list[index]
# 3. Return the value if found, else return None
return None if kv is None else kv[1]
def update(self, key, value):
# 1. Find the index for the key using get_valid_index
index = get_valid_index(self.data_list, key)
# 2. Store the new key-value pair at the right index
self.data_list[index] = (key, value)
def list_all(self):
# 1. Extract the key from each key-value pair
return [kv[0] for kv in self.data_list if kv is not None]
if __name__ == '__main__':
# listen和silent是冲突的,计算出来对应的index都为655
# silent后插入,索引会变为656
# Create a new hash table
table = HashTable()
# Insert a value
table.insert('listen', 99)
# Check the value
print(table.find('listen') == 99)
# Insert a colliding key
table.insert('silent', 200)
# Check the new and old keys
print(table.find('listen') == 99 and table.find('silent') == 200)
# Update a key
table.insert('listen', 101)
# Check the value
print(table.find('listen') == 101)
print(table.list_all() == ['listen', 'silent'])
总结
我们的hash表变得更完善了,接下来,让我们用我们已经实现的hash表来实现python中的字典吧~