- 1 基本数据结构
- 2 栈的概念
- 3 栈的抽象数据类型
- 4 栈的实现
- 5 栈的应用之圆括号平衡
- 6 栈的应用之符号平衡(通用)
- 7 栈的应用之进制转换
- 8 栈的应用之中缀前缀后缀
- 9 中缀后前缀、后缀的转换思路
- 10 栈的应用之中缀转后缀表达式算法的实现
- 11 后缀表达式求值
- 12 队列的概念
- 13 队列的抽象数据类型
- 14 队列的 python 实现
- 15 队列应用之烫手的山芋
- 16 队列应用之 打印任务
- 17 列表
- 18 无序列表的实现
- 19 有序列表 ADT 及实现
- 20 递归和递归三定律
- 21 递归的实现和应用
- 22 递归图形
- 23 宾斯基三角形
- 24 汉诺塔问题(河内塔问题)
- 25 探索迷宫
- 26 动态规划
- 27 排序与查找 顺序查找
- 28 二分查找
- 30 冒泡排序
- 31 选择排序
- 29-1 哈希查找
- 29-2 冲突解决
- 29-3 用哈希表实现映射
- 32 插入排序
- 33 希尔排序
- 34 归并排序
- 35 快速排序
- 36 树的基本概念
- 37 树的实现
- 38 分析树
- 39 树的遍历
29-3 用哈希表实现映射
实现 map 抽象数据类型
字曲是 python 里最有用的数据集合之一,回想一下,字典是一对键值-数据的组合,键值是用来查找相应的数据,我们把这种思想称为“映射”
映射的抽象数据类型定义如下,这是一个无序的键-值对集合,键值总是唯一的以便建立与数据的对应关系。映射的操作方法如下:
· Map() 创建一个新的空的映射,返回一个空集合。
· put(key,val) 在映射中增加一对新的键-值对,如果键值已经存在,用新的数据值代替原来的。
· get(key) 根据给定的键值,返回对应的数值,找不到时返回 None。
· Del 从映射中删除键-值对,形式 del map[key]
· len() 返回映射中键-值对的数量
· In 如果 key 值在映射中,key in map 返回 True,否则返回 False
字典的好处之一,是给一个键值可以很快返回相关的数据,为了提供这样快速查询的能力,我们需要引入一个高效的查找功能。可以对列表使用顺序或二分查找,但是最好是用哈希表,因为它能提供接近O(1) 的性能
在 listing2 中,我们用两个列表创建 HashTable 类来实现映射的抽象数据类型。一个列表,名为 slots 来保存键值元素,另一个平行的列表,名为 data,保存数据。当查询键值的时候,data 列表相应的位置上就保存有数据。我们将键值列表处理成哈希表,注意哈希表的初始大小为是 11,虽然这个大小是随意的,但是选择为质数特别重要,因为这样一来后面处理冲突的效率就比较高。
Listing 2
classHashTable :
def __init__(self):
self.size=11
self.slots= [None]*self.size
self.data= [None]*self.size
Hashfunction 函数是简单地用了余数法,冲突解决采用了+1 线性探测再哈希函数,put 函数约定:除非 self.slots 中包括这个键值,否则这个槽位就认为是空的。它计算出的哈希值如果非空,就迭代 rehash 函数,直到找到一个空槽位。如果一个非空的槽位上已经有键值,就用新数据代替原数据。
Listing 3
def put(self,key,data):
hashvalue =self.hashfunction(key,len(self.slots))
if self.slots[hashvalue]==None:
self.slots[hashvalue]= key
self.data[hashvalue]= data
else :
if self.slots[hashvalue]== key:
self.data[hashvalue]= data #replace
else :
nextslot =self.rehash(hashvalue,len(self.slots))
while self.slots[nextslot]!=None and \
self.slots[nextslot]!= key:
nextslot =self.rehash(nextslot,len(self.slots))
if self.slots[nextslot]==None:
self.slots[nextslot]=key
self.data[nextslot]=data
else :
self.data[nextslot]= data #replace
def hashfunction(self,key,size):
return key%size
def rehash(self,oldhash,size):
return (oldhash+1)%size
Listing4 中,get 函数从计算哈希值开始,如果这个值不是一个起始的槽位,rehash 就去查找另一个可能的位置。注意第 15 行检查有没有返回最早的槽位,如果是,查找将停止,因为那表明已经找过所有的槽位,元素不存在。
HashTable 类的最后一个方法提供了一个附加的字典函数。我们重载了__getitem__和 __setitem__方法来实现“[ ]”符号的使用。这也意味着,一旦 HashTable 对象创建,熟悉的索引方法就可用了。其他方法用作练习。
def get(self,key):
startslot =self.hashfunction(key,len(self.slots))
data =None
stop =False
found =False
position = startslot
while self.slots[position]!=None and \
not found andnot stop:
if self.slots[position]== key:
found =True
data =self.data[position]
else :
position=self.rehash(position,len(self.slots))
if position == startslot:
stop =True
return data
def __getitem__(self,key):
return self.get(key)
def __setitem__(self,key,data):
self.put(key,data)
对下会话显示了 HashTable 类的使用,先创建一个哈希表,存入一些数据。
>>> H=HashTable()
>>> H[54]="cat"
>>> H[26]="dog"
>>> H[93]="lion"
>>> H[17]="tiger"
>>> H[77]="bird"
>>> H[31]="cow"
>>> H[44]="goat"
>>> H[55]="pig"
>>> H[20]="chicken"
>>> H.slots
[77, 44, 55, 20, 26, 93, 17, None, None, 31, 54]
>>> H.data
['bird', 'goat', 'pig', 'chicken', 'dog', 'lion',
'tiger', None, None, 'cow', 'cat']
然后访问并修改一些元素,注意键值为 20 的数据被替换。
>>> H[20]
'chicken'
>>> H[17]
'tiger'
>>> H[20]='duck'
>>> H[20]
'duck'
>>> H.data
['bird', 'goat', 'pig', 'duck', 'dog', 'lion',
'tiger', None, None, 'cow', 'cat']
>> print(H[99])
None
完全的哈希表例子代码:
class HashTable: def __init__(self): self.size = 11 self.slots = [None] * self.size self.data = [None] * self.size def put(self,key,data): hashvalue = self.hashfunction(key,len(self.slots)) if self.slots[hashvalue] == None: self.slots[hashvalue] = key self.data[hashvalue] = data else: if self.slots[hashvalue] == key: self.data[hashvalue] = data #replace else: nextslot = self.rehash(hashvalue,len(self.slots)) while self.slots[nextslot] != None and \ self.slots[nextslot] != key: nextslot = self.rehash(nextslot,len(self.slots)) if self.slots[nextslot] == None: self.slots[nextslot]=key self.data[nextslot]=data else: self.data[nextslot] = data #replace def hashfunction(self,key,size): return key%size def rehash(self,oldhash,size): return (oldhash+1)%size def get(self,key): startslot = self.hashfunction(key,len(self.slots)) data = 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 data = self.data[position] else: position=self.rehash(position,len(self.slots)) if position == startslot: stop = True return data def __getitem__(self,key): return self.get(key) def __setitem__(self,key,data): self.put(key,data) H=HashTable() H[54]="cat" H[26]="dog" H[93]="lion" H[17]="tiger" H[77]="bird" H[31]="cow" H[44]="goat" H[55]="pig" H[20]="chicken" print(H.slots) print(H.data) print(H[20]) print(H[17]) H[20]='duck' print(H[20]) print(H[99])
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论