什么是hash表?
hash表是一种数据结构,可以快速实现插入和查找。
一般是通过(key,value)
的方式来进行存储,例如python中的字典就是hash表的一个很好的例子。
设计原理
举个例子:
1.创建一个长度为4096的list,其中的元素都为None
2.插入(‘a’,1)这个数据 ---- 我们要知道应该把元素插在哪里
首先要获取key的hash值,再根据这个hash值得到索引,我们这里采用最简单的获取hash值的算法。
我们假设对应hash值的算法就是每个字母对应的ASCII码值相加
通过hash值获得数据在list中的索引,这里可以通过取余数的方式进行,保证不会越界访问数组
例如 :hash值为 1 对应的索引就为1(1%4096=1)
4098对应的索引就为2(4098%4096=2)
3.获取到索引index之后,令 list[index]=(key,value)
这样就完成了插入操作
查找时,只要知道key,计算出对应的索引,就可以直接通过访问list获取value了。
(因为list的存储是连续的,只要知道了第一个元素地址,再知道index,就可以直接算出来偏移量进行访问,不用进行遍历,复杂度大大降低,也就是O(1)的复杂度~)
抽象点的步骤:
- 创建一个长度为n的数组
- 计算key对应的hash值
- 完成插入/查找
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
if __name__ == '__main__':
data_list = [None] * MAX_HASH_TABLE_SIZE
# 插入
# 方法一
key, value = 'test1', '7878787878'
idx = get_index(data_list, key)
data_list[idx] = (key, value)
# 方法二
data_list[get_index(data_list, 'test2')] = ('test2', '9595949494')
# 测试是否成功插入
# [1]是因为存储的是key,value 要访问value
print(data_list[get_index(data_list, 'test1')][1]=='7878787878')
print(data_list[get_index(data_list, 'test2')][1]=='9595949494')
可以将上述代码封装一下,用类来实现我们的hash表
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
class MyHashTable:
def __init__(self, max_size=MAX_HASH_TABLE_SIZE):
self.data_list = [None] * max_size
def insert(self, key, value):
"""Insert a new key-value pair"""
index = get_index(self.data_list, key)
self.data_list[index] = (key, value)
def find(self, key):
"""Find the value associated with a key"""
index = get_index(self.data_list, key)
key_value = self.data_list[index]
if key_value is None:
return key_value
else:
return key_value[1]
def update(self, key, value):
"""Change the value associated with a key"""
index = get_index(self.data_list, key)
self.data_list[index] = (key, value)
def list_all(self):
"""List all the keys"""
return [key_value[0] for key_value in self.data_list if key_value is not None]
if __name__ == '__main__':
basic_table = MyHashTable(1024)
print(len(basic_table.data_list) == 1024)
# Insert some values
basic_table.insert('test1', '9999999999')
basic_table.insert('test2', '8888888888')
# Find a value
print(basic_table.find('test2') == '8888888888')
# Update a value
basic_table.update('test1', '7777777777')
# Check the updated value
print(basic_table.find('test1') == '7777777777')
# Get the list of keys
print(basic_table.list_all() == ['test1', 'test2'])
总结
这样我们就自己实现了最简单的hash表,但是细细想想,其实问题还是很多的,例如:当两个key映射的index是一样的的时候,该如何处理这种冲突问题呢?
具体的处理方法参见:实现Hash表(二)----处理index冲突问题