一,字典的底层数据结构
Python字典主要功能是存储键值对形式的数据,底层实现为哈希表,
同样实现的编程语言还有Java,JavaScript等。
python字典通过唯一key值找到value的时间复杂度为O(1),这得益于哈希表的特性。
二,哈希表(散列表)
哈希函数
首先介绍哈希函数,他可以将任意长度的数据映射为128位的编码,
是实现各种索引加速的强有力手段,
常见哈希函数包括MD5,SHA-1,SHA-256等,主要应用场景有安全加密,唯一标识,数据校验,
散列函数也就是接下来要介绍的哈希表的实现。
哈希表
用顺序表存储键值对,通过哈希函数计算出key对应的索引,将值存到索引对应的数据区中。
获取数据时,通过哈希函数计算出key对应的索引,取出索引位置对应的数据。
由于需要哈希函数计算,所以key值必须是可哈希的,也就是说key值必须是不可变的类型
python中不可变数据类型为:字符串,数字,元组(元素为不可变类型),函数,类对象
哈希表存储
hash表利用hash函数计算出Key的哈希值,与数组长度求余,取余结果index作为数组下标
list[hash(key)%len(list)]=value
三,哈希冲突与扩容
只要样本足够大,任何哈希函数一定会出现两个不同的key得出同一个哈希值,此时会出现两个不同key存入同一个数组位置,这种就称为哈希冲突。
可以利用开链法和开发寻址法解决冲突。
开链法:哈希表中的顺序表的每个位置存储的是链表,如果发生冲突时,冲突的元素会被加在链表的后面
开发寻址法:如果发现index位置上有数据,则探查新的位置来存储,index有值,则探查index+n 以此类推
主流编程语言的哈希冲突算法为开链法,比如java,python。
负载因子 表示散列表的装满程度 元素个数/散列表长度
当哈希表的存储位置存满后将会自动扩容,但是会在负载因子达到一定阈值时,
就会开始扩容,每次扩容大小为原来的两倍,java,python哈希表负载因子默认为0.75。
四,手写字典
简单版字典
class myDict:
def __init__(self,max):
self.max=max
self.hashTable=[None for _ in range(max)]
def addItem(self,key,value):
"""增加"""
index=hash(key)%self.max
self.hashTable[index]=value
def getValue(self,key):
index=hash(key)%self.max
return self.hashTable[index]
mydict=myDict(20)
mydict.addItem("key1",100)
mydict.addItem("key1",200)
mydict.addItem("key2",300)
print(mydict.getValue("key1"))
print(mydict.getValue("key2"))
print(mydict)
模拟哈希冲突
class myDict:
def __init__(self,max):
self.max=max
self.hashTable=[None for _ in range(max)]
self.capacity=0
def addItem(self,key,value):
"""增加"""
if self.capacity==self.max:
raise Exception("超出容量")
index=hash(key)%self.max
if self.hashTable[index]:
raise Exception(f"哈希冲突")
self.hashTable[index]=value
self.capacity+=1
def getValue(self,key):
index=hash(key)%self.max
return self.hashTable[index]
"""模拟哈希冲突"""
mydict=myDict(100)
temp=['q','w','e','r','t','y','u','i','o']
result=[]
for x in temp:
for y in temp:
for z in temp:
result.append(f"{x}{y}{z}")
for item in result:
mydict.addItem(item,f"{item}-value")
解决哈希冲突版字典
#编写链表数据结构
class Node:
"""一个简单的链表子节点"""
def __init__(self,key,value):
self.key=key
self.value=value
self.next=None
class myDict:
def __init__(self,max):
self.max=max
self.hashTable=[None for _ in range(max)]
self.capacity=0
def addItem(self,key,value):
"""增加"""
if self.capacity==self.max:
raise Exception("超出容量")
index=hash(key)%self.max
if self.hashTable[index]:
print(f"hash冲突 {key} {value}")
node=self.hashTable[index]
while node.next:
node=node.next
node.next=Node(key,value)
else:
self.hashTable[index]=Node(key,value)
self.capacity+=1
def getValue(self,key):
flag=False
index=hash(key)%self.max
node=self.hashTable[index]
if not node:
raise Exception("key error 1 ")
elif node.key==key:
return node.value
else:
while node.next:
node = node.next
if node.key==key:
flag=True
break
if not flag:
raise Exception("key error 2 ")
return node.value
mydict=myDict(20)
temp=['q','w','e','r','t','y','u','i','o','a','s','d','f','g','h','j','k','z','x','c','v','b','n']
result=[]
for x in temp:
for y in temp:
for z in temp:
result.append(f"{x}{y}{z}")
for item in result:
mydict.addItem(item,f"{item}-value")
print(mydict)
自动扩容版字典
class Node:
"""一个简单的链表子节点"""
def __init__(self,key,value):
self.key=key
self.value=value
self.next=None
class myDict:
def __init__(self,max):
self.max=max
self.hashTable=[None for _ in range(max)]
self.capacity=0
def addItem(self,key,value):
"""增加"""
"""判断是否需要扩容"""
factor=self.capacity/self.max
if factor>0.75:
self.hashTable.extend([None for _ in range(self.max)])
self.max=self.max*2
index=hash(key)%self.max
if self.hashTable[index]:
print(f"hash冲突 {key} {value}")
node=self.hashTable[index]
while node.next:
node=node.next
node.next=Node(key,value)
else:
self.hashTable[index]=Node(key,value)
self.capacity+=1
def getValue(self,key):
flag=False
index=hash(key)%self.max
node=self.hashTable[index]
if not node:
raise Exception("key error 1 ")
elif node.key==key:
return node.value
else:
while node.next:
node = node.next
if node.key==key:
flag=True
break
if not flag:
raise Exception("key error 2 ")
return node.value
mydict=myDict(20)
temp=['q','w','e','r','t','y','u','i','o','a','s','d','f','g','h','j','k','z','x','c','v','b','n']
result=[]
for x in temp:
for y in temp:
for z in temp:
for k in temp:
for t in temp:
result.append(f"{x}{y}{z}{k}{t}")
for item in result:
mydict.addItem(item,f"{item}-value")
print(mydict)