Java 散列表 散列表定义_数组

 

 1、列表

(1)内部机制:实现、冲突和散列函数

 

2、散列函数

(1)散列函数总是将相同的输入映射到相同的索引;将不同的输入映射到不同的索引。

(2)散列函数的数组长度是已知的,只返回有效的索引。

 

3、散列表(hash table)

(1)定义:结合散列函数和数组创建的一种数据结构,也称为散列映射、映射、字典、关联数组和字典。

(2)区别:数组和链表都被直接映射到内存,散列表是使用散列函数来确认元素的存储位置。

(3)组成:键、值,将键映射到值。【散列表很适用于模拟映射关系】

(4)散列表的查找、插入和删除速度很快;散列表是无序的,键值对的添加顺序无关紧要。

(5)平均情况下,散列表的各种操作时间为O(1),O(1)被称为常量时间,意味着不管散列表多大,所需的时间都是相同的。

         最糟糕的情况,散列表所有操作的运行时间都为O(n)——线性时间。

Java 散列表 散列表定义_散列表_02

Java 散列表 散列表定义_散列函数_03

 

   因此,在平均情况下,散列表的查找(获取给定索引处的值)速度和数组是一样的,二插入和删除速度和链表是一样的,兼具了两者的优点。但在最糟糕的情况下,散列表的各种操作速度都是很慢的,故而需要避开最糟糕情况,需要避开冲突。

 

 3、应用案例

(1)DNS解析(DNS resolution):网址硬是IP地址

(2)DEMO

# 创建一个字典,用大括号
dict={}

# 添加一些数据
dict["Ann"]=16

# 查找一些数据,get函数返回获取到的数据或者None
value=dict["Tom"]

(3)例子1

# 检查用户是否投过票
voted={}

def check_voter(name):
    if voted.get(name):
        print("Kick them out!")
    else:
        voted[name]=True
        print("Let them vote")

check_voter("Tom")
check_voter("Milk")
check_voter("Milk")

(4)例子2

# Fackbook网址访问
cache={}

def get_page(url):
    if cache.get(url):
        # 返回缓冲的数据
        return cache[url]    
    else:
        data=get_data_from_server(url)
        # 先将数据保存到缓存中
        cache[url]=data
        return data

(5)适用于:①模拟映射关系;②防止重复;③缓存/记住数据,以免服务器在通过处理来生成它们

 

4、冲突(collision)

(1)定义:给两个键分配相同位置

(2)解决方法:如果两个键映射到同一个位置,就在这个位置存储一个链表。

(3)散列表存储的链表很长,起散列表速度将下降。因此,使用散列函数很重要,使得链表不会很长,进而最大限度地减少冲突。

(4)避免冲突需要条件:①较低的填装因子;②良好的散列函数。

  <1>填装因子=散列表包含的元素数/位置总数

     =>填装因子度量的是散列表中多少位置是空的,填装因子大于1意味着超过数组的位置数,此时则需要调整长度(resizing),增加散列表的位置。

     =>一旦填装因子大于0.7,就调整散列表的长度。平均而言,考虑到调整长度所需的时间,但列表操作所需的时间为O(1)。

     =>填装因袭越低,发生冲突的可能性越小,散列表的性能越高。

  <2>良好的散列函数:让数组中的值呈现均匀分布。【可研究于SHA函数,最后一章做简要介绍】

 

 

Java 散列表 散列表定义_Java 散列表_04

 

Java 散列表 散列表定义_Java 散列表_05

Java 散列表 散列表定义_Java 散列表_06

 

Java 散列表 散列表定义_Java 散列表_07

 

5.1 一致

5.2 不一致

5.3 不一致

5.4 一致

5.5  散列函数C和D可实现均匀分布

5.6  散列函数B和D可实现均匀分布 

5.7  散列函数C和D可实现均匀分布

# B:会有重复的
print(len("Fun Home")) # 8
print(len("Watchmen")) # 8

 

Java 散列表 散列表定义_数组_08