哈希表(hash table,又称散列表)是一种数据集,其中数据项的存储方式尤其是有利于将来快速的查找定位。
散列表的每一个存储位置,成为槽,可以用来保存数据项,每个槽有一个唯一的名称。
实现从数据项到存储名称的转换的,称为散列函数(哈希函数)。
有一种常见的散列方法是‘求余数’,将数据项厨艺散列表的大小,得到的余数作为槽号。
不过这很明显会存在一个问题,要保存的数据需要存到同一个槽中,会产生冲突。
完美散列函数;给定一组数据项,如果一个散列函数能把每个数据项都映射到不同的槽中,那么这个散列函数就称为‘完美散列函数’。
完美散列函数应用:
数据的一致性校验;(压缩性、易计算性、抗修改性、抗冲突性)
散列函数:
MD5、SHA
python的散列函数库hashlib;自带MD5和SHA系列的散列函数。
包括了md5 / sha1 / sha224 等六种散列函数。
>>> import hashlib
>>> m = hashlib.md5('hello'.encode('utf-8')).hexdigest()
>>> m
'5d41402abc4b2a76b9719d911017c592'
散列函数的最酷应用;
区块链技术
我们知道数组的特点是寻址容易,插入和删除数组困难。而链表的特点是寻址困难,插入和删除数据容易。
可以看到哈希表的上面是数组,数组的每个成员包括一个指针,指向一个链表的头节点,当然链表可能为空,也可能链接多个节点。
我们存储键值对(key-value pair)的方式主要依靠键的特征,通过键的哈希值找到对应的数组下标,然后将其键值对添加到对应的链表中,寻找元素时,也是根据其键的哈希值,找到特定链表其对应的值。
我们可以对比python中的字典,字典是一种可以保存key- value键值对的数据类型,这种键值关联的方法称作‘映射Map’。
哈希表支持的操作:
开放定址,就是为冲突的数据项再找一个开放的空槽来保存。
向后逐个槽寻找的方法则是开放定址技术中的线性探测。
线性探测法的一个缺点就是聚集的趋势。避免聚集的一种方法就是将线性探测扩展,从逐个探测改为跳跃式探测。
考虑到冲突解决算法,散列表大小应该选择素数。
class Hash_Table(object):
def __init__(self):
self.size = 11
self.slots = [None] * self.size
self.val = [None] * self.size
def hash_function(self,key):
return key % self.size
def rehash(self,oldhash):
return (oldhash + 1) % self.size
def add(self, key, val):
hash_value = self.hash_function(key)
if self.slots[hash_value] == None:
self.slots[hash_value] = key
self.val[hash_value] = val
else:
if self.slots[hash_value] == key:
self.val[hash_value] = val
else:
nextslot = self.rehash(hash_value)
while self.slots[nextslot] != None and self.slots[nextslot] != key:
nextslot = self.rehash(nextslot)
if self.slots[nextslot] == None:
self.slots[nextslot] = key
self.val[nextslot] = val
else:
self.data[nextslot] = val
def get(self, key):
startslot = self.hash_function(key)
val = None
stop = False
found = False
position = startslot
while self.slots[position] != None and not found and not stop:
if self.slots[position] == key:
found = True
val = self.val[position]
else:
position = self.rehash(position)
if position == startslot:
stop = True
return val
def __getitem__(self, key):
return self.get(key)
def __setitem__(self, key, val):
self.add(key,val)
from ADT_CLASS import Hash_Table
h = Hash_Table()
h[54] = 'cat'
h[26] = 'dog'
h[93] = 'lion'
h[26] = 'pig'
print(h.slots)
print(h.val)
print(h[26])
输出:
[None, None, None, None, 26, 93, None, None, None, None, 54]
[None, None, None, None, 'pig', 'lion', None, None, None, None, 'cat']
pig