1.散列函数:将输入映射到数字;需要满足的要求是:
1)它必须是一致的,即当输入相同时,输出也是相同的;
2)将不同的输入映射到不同的数字;
2. 散列表也被称为散列映射、映射、字典和关联数组;任何一门语言都提供了散列的实现,其中python提供字典来创建散列表,散列表由键和值组成。
3. 散列函数的应用:
1)用于查找,例如创建电话簿;
// 创建字典
>>>phone_book = {}
>>>phone_book["Lee"] = 1234567
>>>phone_book["Lee"]
1234567
2)防止重复,散列表可检测到当前的散列表中是否已有键,散列表不允许有两个以上相同的键;
// 创建散列表,用于记录投票人
voted={}
def check_voter(name):
if voted.get(name):
print("kick them out!")
else:
voted[name] = True
print("Let them vote!")
#测试上面的函数:
>>>check_voter("Tom")
Let them vote!
>>>check-voter("Tom")
>>>kick them out!
3)将散列表用作缓存,缓存是一种常用的加速方式,所有的大型网站都使用缓存,而缓存的数据则存储在散列表中。
// Web服务器缓存案例
cache = {}
def get_page(url):
if cache.get(url): #检测网站服务器是否缓存了该资源,若已缓存,则返回该网页内容
return cache[url]
else: #若未检测到服务器缓存,则从服务器中请求该资源,并将其写入在散列表中,下次再有该资源的请求时,直接发送缓存数据,不需要再让服务器进行处理
date = get_data_from_server(url)
cache(url) = data
return data
4.散列表的性能:
1)理论上散列函数总是将不同的键映射到数组的不同位置,但是实际上可能会出现将不同的键映射到数组中的相同位置,从而出现“冲突”(collision):给两个或多个键分配的位置相同。而避免冲突最简单的方式是在这个位置存储一个链表。但,如果散列表总存储的链表很长,散列表的速度将急剧下降。
因此,使用散列函数最理想的情况是将散列函数均匀的映射到散列表中的不同位置,减少冲突。
2)在平均情况下,散列表执行的各种操作的时间都为O(1),即称常量时间,也就是所需的时间相同。
在平均情形下,散列表的查找(获取给定索引出的值)速度与数组一样快,而插入和删除速度与链表一样快。因此它兼顾两者的优点。但是在最糟糕的情形下(散列表中的所有元素都在数组中的某个链表中,而数组中的其他位置都出于空闲状态),散列表的各种操作都很慢,性能会大大折扣。
3)保证散列表高性能的要素是:
A. 较低的填装因子,定义填装因子:散列表中包含的元素数/位置总数;同时,经验告知,一旦填装因子的值大于0.7,就该调整散列表的长度。
B. 良好的散列函数,良好的散列函数可以让数组中的值呈现均匀分布