散列表基本概念

散列表概念:

散列表 = 散列函数+数组(有时还要结合链表)实现的一种数据结构。

散列函数:将输入映射到数字。并且输入相同,映射的数字相同。输入不同映射的数字不同。

散列表的存储原理:对输入A生成唯一的hash,该hash对应到数组中的一个索引,在该索引上存放数据data,底层采用数组存储,意味着,获取数据时,只需要输入A,经过散列函数就可以获取对应的索引,从而立刻返回data.

一些别名:映射,程序中的实现(HashTable)

应用场景:

  • 缓存,通过将url存入散列表。
  • 防止重复,比如投票时,将人名和投票记录保存在散列表。
  • 模拟映射关系:比如商品名称和价格的映射
冲突:

理想情况是散列函数总是将不同的键映射到数组的不同位置。但几乎不可能编写出这样的散列函数。比如通过商品的名称首字母分配数组的位置。比如将a开头的放在第一个位置,将b开头的放在第二个位置…,你会很快发现,有商品的首字母就会冲突。

解决冲突的最简单方法就是在冲突的位置存储一个链表。如下:

在这里插入图片描述

如果链表不是很长,我们还是会很快查到要查的商品。

填装因子:

填装因子=散列表元素个数 / 位置总数

比如:散列数组有5个位置,其中只有两个位置有元素,则占用率即填装因子是 2/5

填装因子大于1,意味着数组位置不够用,需要调整长度(resizing).一般是将数组增长为一倍。一般的经验,一旦填装因子大于0.7,就调整散列表的长度。

小结:

​ 1.填装因子越低,发生冲突的可能性就越小,散列表的性能越高。

​ 2.调整散列表需要很大开销,所以应该尽量避免。

​ 3.良好的散列函数,能让数组中的值均匀分布。

性能:

散列表的时间复杂度:

操作平均情况最糟情况
查找O(1)O(n)
插入O(1)O(n)
删除O(1)O(n)

O(1)被称为常量时间,它并不意味着马上,而是不管散列表多大,所需的时间都相同。所以在平均情况下,散列表和数组一样快,而插入和删除速度和链表一样快。因此兼具两者的优点。

下面是数组和链表的时间复杂度:

数组链表
读取O(1)O(n)
插入O(n)O(1)
删除O(n)O(1)

小结:

 所以如果考虑设计散列函数,查询单次时间等因素,要考虑进数据的量级,只有数据的量很大,散列函数很合理的情况下,散列函数的性能才能发挥到极致。

python示例代码:

几乎所有的编程语言都提供了散列表的实现。比如python创建一个散列表如下:

book = dict()
book["apple"] = 0.64
book["milk"] = 1.49
book["avocado"] = 1.43

#打印整个散列表
print(book)
#查询apple的价格
print(book["apple"])

 程序屏蔽了散列函数的具体实现,我们只需要传入键和值,就会通过散列表保存,查询时,传入键就可以获取对应的值。

总结:

0.散列函数和数组结合可以创建散列表。

1.散列函数很重要,填装因子是散列函数性能的一个重要指标。

2.如果散列表存储的链表很长,速度将很慢,时间复杂度会从O(1)退化到O(n)。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值