数据结构与算法-散列表

散列表

我们前面已经说过数组这个数据结构,他非常的方便,使用连续的内存和下标来操作元素。

但是这难以满足一些其他的需求,比如我们需要将两个对象进行一一对应,没错我们常用的字典就是其中的一种类型。

字典这种结构使用键(key)---值(value)的对应关系,我们可以根据键获得对应的值。

a = {"liu":98,"zhang":99}
a["liu"]

# 98

 

我们可以假设的思考一下该如何实现这种结构。我们首先来思考最简单的方法,使用两个数组一一对应,每次输入一个键的时候则找到对应的位置,并获取另一个数组中同位置的元素,大概意思就是下图:

然而效率应该是比较低的,因为我们需要遍历所有元素找到该键对应的值,而且这个方法需要两个数组。我们干脆使用一个数组,每个元素存储字典的一对键和值。

虽然数组变为一个了,但是元素的查找还是很费劲,需要一一遍历。我们知道数组可以使用下标访问,那么我们能不能把问题继续转化一下。我们知道所有数据在计算机中都是数字,可以被用来计算。那么,我们是不是也可以将键转换为数字,将得到的数字作为下标呢?

然而一个不可避免的问题就是,尽管字典要求是键不能相同,但是总会有那么小的机会使得相同的键的f(键)的数值是一样的。所以我们不能都仅仅依靠f(键)来定位下标,还需要将键也存储起来,除此之外遍历的时候也需要知道每组的键和值不是。所以一个字典的基本样子是这样的:

跟上一个构想不同的是,我们的元素寻找不需要遍历,可以直接根据键计算得出,方便了不少呢。

 

首先,通过函数f将键转换为数字下标,然后将值存储在矩阵对应的下标出,这样我们实现了一个非常有趣的突破:

1. 仅需要一个数组

2  可以根据键直接定位值,复杂度为O(1)

当然我们也看到了这种方法的一些问题:

1. 数组初始化的大小是多少?

2. 不同的键需要得到不同的下标,这样才能安全的使用字典。关键在于我们函数f如何设置,才能合理的将不同的键尽可能的映射为不同的数字下标

 

哈希函数

我们的散列表,又称为哈希(hash)表,进而这个函数被称为哈希函数,使用中通常是H来表示。

hash的英文原意是“混杂”、“拼凑”、“重新表述”的意思,比较符合这个数据结构的含义吧。

哈尔函数的关键在于,不同的键尽可能的对应不用的下标值,通常采用的方法有一下几种:

  • 直接定址法

例如:每日的订单,由于编号不重复,哈希函数可以取关键字自身的后几位部分。

 

  • 除留余数法

当数字值过大时,我们也可以尝试取关键字的除法余数作为哈希值

H(key)=key MOD p (p<=m)  

其中数组长度为m p为小于m的数字,这样的得到的余数一定在m范围内

 

  • 数字分析法

数学分析法的关键在于,分析数据中相同和不同的部分,在截取数据作为哈希值时要避免重复出现概率高的部分,使用较低的部分作为哈希值。

举个例子,学校的所有学生的编号为:入学年号+生日+班级+班级序号

2001-19951103-07-52

2005-19971012-14-12

这其中如果只能取四位作为哈希值,我想大家也会适当的抉择一下,哪些留下来是比较好的

  • 平方取中法

取关键字平方后的中间几位为哈希地址。

  • 折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。

例如:每一种西文图书都有一个国际标准图书编号,它是一个10位的十进制数字,若要以它作关键字建立一个哈希表,当馆藏书种类不到10,000时,可采用此法构造一个四位数的哈希函数。

  • 随机数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即

H(key)=random(key),其中random为随机函数。通常用于关键字长度不等时采用此法。

 

Python中的字典

首先是一个小的总结,(字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组,因为会自动扩容,不会让很多元素都被占用),数组的每个单元叫做 bucket。每个 bucket 有两部分:一个是键对象的引用,一个是值对象的引用。所有 bucket 结构和大小一致,我们可以通过偏移量来读取指定 bucket。当数组大小被占用到一定程度时,就会自动扩容,并将所有的数据复制到新的数组中)

我们仅简单的说了说概念,现在来看一下实际的字典是什么样的,我们还和数组做了比对

我们的a是一个字典,存储的是键值对,说明存储中键和值都是一起存储的。而b是一个列表,仅是由下标来标识的。然而上文说过,散列表说不定就会发生不同键得到同一个数值,导致冲突问题。为应对这个问题,提出了好几个比较有成效的方法,具体的会在下一篇会在讲解。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值