'''
字典抽象数据类型
build_dict 构建一个新字典
is_empty 判定是否为空
num 计算键值对数目
search 查询是否存在
insert 插入一个键值对
delete 删除键值对
values 返回值
keys 返回键
entries 返回所有键值对
'''
from functools import total_ordering
#定义健值类
@total_ordering
class Assoc(object):
"""docstring for Assoc"""
def __init__(self, key,value):
self.key = key
self.value=value
def __lt__(self,other):
return self.key<other.key
def __str__(self): #如果要把一个类的实例变成 str,就需要实现特殊方法__str__():
return "Assoc({0},{1})".format(self.key,self.value)
##线性表实现
class Dict_list(object):
"""docstring for Dict_list"""
def __init__(self):
self._elems = []
def build_dict(self,list_of_tuple):
for t in list_of_tuple:
self.insert(t[0],t[1])
def is_empty(self):
return len(self._elems)==0
@property
def num(self):
return len(self._elems)
def search(self,key):
for k,v in self._yeild_dict():
if k==key:
return v
raise KeyError('the key %d not in the dict'%key)
def insert(self,key,value):
for i,(k,v) in enumerate(self._yeild_dict()):
if k==key:
self._elems[i].value=value
return
self._elems.append(Assoc(key,value))
def delete(self,key):
for i,(k,v) in enumerate(self._yeild_dict()):
if k==key:
self._elems.pop(i)
return
raise KeyError('the key %d not in the dict'%key)
def entries(self):
result = []
for k,v in self._yeild_dict():
result.append((k,v))
return result
def keys(self):
result=self.entries()
return list(map(lambda x:x[0],result))
def values(self):
result=self.entries()
return list(map(lambda x:x[1],result))
def _yeild_dict(self):
i = 0
while i<len(self._elems):
assoc = self._elems[i]
yield assoc.key,assoc.value
i+=1
##有序表实现
class Dict_sort_list(Dict_list):
"""docstring for Dict_sort_list"""
def build_dict(self,list_of_tuple):
for t in list_of_tuple:
self._elems.append(Assoc(t[0],t[1]))
self._elems=sorted(self._elems)
def search(self,key):
i,j = 0 ,len(self._elems)-1
middle = (i+j)//2
while i<=j:
if key<self._elems[middle].key:
j=middle-1
elif key>self._elems[middle].key:
i=middle+1
else:
return self._elems[middle].value
middle=(i+j)//2
raise KeyError('the key %d not in the dict'%key)
def insert(self,key,value):
if len(self._elems)==0:
self._elems.append(Assoc(key,value))
return
i,j = 0 ,len(self._elems)-1
middle = (i+j)//2
while i<=j:
if key<self._elems[middle].key:
j=middle-1
elif key>self._elems[middle].key: #最后j=i-1,当小于表头时 j=-1 i=0,当大于表头时j=n,i=n+1
i=middle+1
else:
self._elems[middle].value = value
return
middle=(i+j)//2
if i==0:
self._elems = [Assoc(key,value)]+self._elems
elif i<=len(self._elems)-1:
self._elems = self._elems[:i]+[Assoc(key,value)]+self._elems[i:]
else:
self._elems.append(Assoc(key,value))
def delete(self,key):
i,j = 0 ,len(self._elems)-1
middle = (i+j)//2
while i<=j:
if key<self._elems[middle].key:
j=middle-1
elif key>self._elems[middle].key:
i=middle+1
else:
self._elems.pop(middle)
return
middle=(i+j)//2
raise KeyError('the key %d not in the dict'%key)
##Dict_line_hash和Dict_double_hash的父类,实现字典的一部分功能
class Dict_base_hash(object):
"""docstring for Dict_by_hash"""
def __init__(self):
self._enum = 0
self.base_num = 5
self._elems = [None for i in range(8)]
def _hash_line(self,x):
p = len(self._elems)-1
return x%p
def _hash_trans(self,x): #用这种hash函数实现的原理是一样的就不做示例了。
r = 29
ans = 0
n=0
while x>0:
res = (x%10)*(r**n)
ans += res
n+=1
x-=res
x/=10
return ans
def _hash2(self,x): #第二步 key跳步的距离在5以内变化
return x%self.base_num+1
def is_empty(self):
return self.num==0
@property
def num(self):
return self._enum
@property
def _alpha(self):
return self._enum/len(self._elems)
def entries(self):
result=[]
for key,value in self._yeild_dict():
result.append((key,value))
return result
def keys(self):
return list(map(lambda x:x[0],self.entries()))
def values(self):
return list(map(lambda x:x[1],self.entries()))
def _yeild_dict(self):
i=0
while i<len(self._elems):
if self._elems[i] and self._elems[i].key:
yield self._elems[i].key,self._elems[i].value
i+=1
##线性探测的哈希
class Dict_line_hash(Dict_base_hash):
"""docstring for Dict_line_hash"""
def __init__(self, init=None):
self._enum = 0
self._elems = [None for i in range(8)]
if isinstance(init,list) and init and isinstance(init[0],tuple):
self.build_dict(init)
def build_dict(self,init):
#可以优化和重构这一步 避免多次分配存储空间。
# if len(init)>len(self._elems):
# self._elems = [None for i in range(int(len(init)/0.6))]
for t in init:
self.insert(t[0],t[1])
def _add_space(self):
copy = self._elems[:]
self._enum = 0
m = len(self._elems)
self._elems = [None for i in range(2*m)]
for assoc in copy:
if assoc and assoc.key:
self.insert(assoc.key,assoc.value)
def search(self,key):
index = self._hash_line(key)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
while self._elems[index].key != key:
index =self._hash_line(index+1)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
return self._elems[index].value
def insert(self,key,value):#key_value是Assoc的对象
index = self._hash_line(key)
while self._elems[index] and self._elems[index].key and self._elems[index].key !=key:
index =self._hash_line(index+1)
self._elems[index] = Assoc(key,value)
self._enum+=1
if self._alpha >= 0.7:
self._add_space()
def delete(self,key):
index = self._hash_line(key)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
while self._elems[index].key != key:
index =self._hash_line(index+1)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
self._elems[index].key = None
self._enum-=1
##双散列探测的哈希
class Dict_double_hash(Dict_base_hash):
"""docstring for Dict_double_hash"""
def __init__(self, init=None):
self._enum = 0
self._elems = [None for i in range(8)]
if isinstance(init,list) and init and isinstance(init[0],tuple):
self.build_dict(init)
self.base_num = self._generate_basenum()
def build_dict(self,init):
init = list(init)
length = len(init)
if length>len(self._elems)*0.7:
self._elems = [None for i in range(int(length/0.6))]
for t in init:
self.insert(t[0],t[1])
def _generate_basenum(self):
m = len(self._elems)
for item in range(3,m,2):
if m%item>0:
return item
def _add_space(self):
copy = self._elems[:]
self._enum = 0
m = len(self._elems)
self._elems = [None for i in range(2*m)]
for assoc in copy:
if assoc and assoc.key:
self.insert(assoc.key,assoc.value)
self.base_num = self._generate_basenum()
def search(self,key):
index = self._hash_line(key)
delta = self._hash2(key)
if not ( self._elems[index] and self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
while self._elems[index].key != key:
index =self._hash_line(index+delta)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
return self._elems[index].value
def insert(self,key,value):#key_value是Assoc的对象
index = self._hash_line(key)
delta = self._hash2(key)
while self._elems[index] and self._elems[index].key and self._elems[index].key !=key:
index =self._hash_line(index+delta)
self._elems[index] = Assoc(key,value)
self._enum+=1
if self._alpha >= 0.7:
self._add_space()
def delete(self,key):
index = self._hash_line(key)
delta = self._hash2(key)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
while self._elems[index].key != key:
index =self._hash_line(index+delta)
if (not self._elems[index]) or (not self._elems[index].key):
raise KeyError('the key %d not in the dict'%key)
self._elems[index].key = None
self._enum-=1
##为了实现拉链法我们必须重构一下Assoc类
class Assoc_zip(Assoc):
"""docstring for Assoc_zip"""
def __init__(self, key,value,nexts = None):
super(Assoc_zip, self).__init__(key,value)
self.next = nexts
##桶散列的哈希之拉链法
class Dict_hash_bucket(Dict_base_hash):
"""docstring for Dict_hash_bucket"""
def __init__(self, init=None):
self._enum = 0
self._elems = [None for i in range(8)]
if isinstance(init,list) and init and isinstance(init[0],tuple):
self.build_dict(init)
def _yeild_dict(self):
i = 0
while i<len(self._elems):
assoc = self._elems[i]
while assoc:
yield assoc.key,assoc.value
assoc=assoc.next
i+=1
def _add_space(self):
copy = self._elems[:]
self._enum = 0
m = len(self._elems)
self._elems = [None for i in range(3*m)]
for assoc in copy:
while assoc:
self.insert(assoc.key,assoc.value)
assoc=assoc.next
def build_dict(self,init):
init = list(init)
length = len(init)
if length>len(self._elems)*5:
self._elems = [None for i in range(length*3)]
for t in init:
self.insert(t[0],t[1])
def search(self,key):
index = self._hash_line(key)
assoc = self._elems[index]
while assoc:
if assoc.key == key:
return assoc.value
assoc=assoc.next
raise KeyError('the key %d not in the dict'%key)
def insert(self,key,value):#key_value是Assoc的对象
index = self._hash_line(key)
insert_flag = False
if not self._elems[index] or self._elems[index].key == key:
self._elems[index]=Assoc_zip(key,value)
else:
assoc = self._elems[index]
while assoc.next:
if assoc.next.key == key:
assoc.next.value = value
insert_flag=True
break
assoc = assoc.next
if not insert_flag:
assoc.next = Assoc_zip(key,value)
if self.num > 5*len(self._elems):
self._add_space()
self._enum+=1
def delete(self,key):
index = self._hash_line(key)
assoc=self._elems[index]
del_flag = False
if assoc and assoc.key==key:
self._elems[index] = assoc.next
del_flag =True
else:
while assoc.next:
if assoc.next.key==key:
assoc.next = assoc.next.next
del_flag = True
break
assoc = assoc.next
if del_flag:
self._enum-=1
else:
raise KeyError('the key %d not in the dict'%key)
def test(): #测试函数
dicts = Dict_hash_bucket()
print(dicts.is_empty())
dicts.build_dict(zip([1,2,3,4,5,6],[11,12,13,14,15,16]))
print(dicts.is_empty())
print(dicts.num)
print(dicts.entries())
dicts.insert(1,100)
dicts.insert(7,17)
print(dicts.entries())
print(dicts.values())
print(dicts.keys())
print(dicts.search(1))
dicts.delete(3)
print(dicts.entries())
dicts.delete(6)
print(dicts.entries())
dicts.delete(1)
print(dicts.entries())
dicts.insert(16,99)
print(dicts.entries())
try:
print(dicts.search(3))
dicts.delete(19) #异常找不到
except KeyError:
print('Error:the key not in the dict')
if __name__=='__main__':
test()