哈希表(散列表)

一,什么是哈希表

由于哈希表一般用数组和链表实现,所以先了解一下数组和链表的基本特征:
数组:采用一段连续的存储单元来存储数据。
     对于指定下标的查找,时间复杂度为O(1), 因为对于数组来说,第n个下标的地址为 数组首地址+n*数组元素的存储空间,所以查找指定下标的数据,可以通过一次计算获取;
    通过给定值进行查找,需要遍历数组,逐一比对给定关键字和数组元素,时间复杂度为O(n),对于一般的插入删除操作,涉及到数组元素的移动,其复杂度为O(n)

链表:采用不连续的存储单元来存储数据,链表元素之间的关系由链表元素中的next指针维护.
    对于链表的新增,删除等操作(在找到指定操作位置后),仅需处理结点间的next即可,时间复杂度为O(1),而查找操作需要遍历链表,复杂度为O(n)
总结来说,数组是查询快速而插入,删除困难,链表则相反.

什么是哈希表

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

记录的存储位置=f(关键字)

这里的对应关系f称为散列函数,又称为哈希(Hash函数),采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。

这样我们在查询的时候就可以直接根据f(key)来获取value所在的位置,从而实现O(1)的时间复杂度.

但是,这里有个问题,我们都知道,数组的空间大小是有限的,所以必然会出现一种情况,那就是f(k1) == f(k2),即两个不同的key得出的hash值是一样的,这种情况就是哈希冲突

处理冲突的方法

开放定址法

Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)
其中m为表长,di为增量序列
如果di值可能为1,2,3,…m-1,称线性探测再散列。
如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,…kk,-kk(k<=m/2)
称二次探测再散列。
如果di取值可能为伪随机数列。称伪随机探测再散列。
如现在有这样一个哈希表:

01234
abc

现在要插入一个元素d,其f(key) = 2.
如果是 线性探测再散列,则会往2位置后找到一个空闲的存储空间,把d插入到4位置中,
如果是 二次探测再散列,则先判断3是否为空,再判断1是否为空,直到找到一个空闲的存储空间,这里就把d插到1中

再哈希法
当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。

链地址法
将f(key)相同的value存储在一个链表中.
在这里插入图片描述

负载因子

哈希表也有一些缺点:它是基于数组的,数组创建后难于扩展某些哈希表被基本填满时,性能下降得非常严重,因为,每一个数组元素的链表都非常的长,而链表的查询性能为O(n),这就使得每次查询元素的时间都非常缓慢.所以在哈希表中的元素足够多的时候,就需要扩充哈希表,那什么时候要扩充哈希表呢,这就涉及到负载因子

负载因子 = 填入表中的元素个数 / 哈希表的长度

一般当负载因子>0.7,就要对哈希表进行扩充.

哈希表的优缺点

优点:不论哈希表中有多少数据,查找、插入、删除(有时包括删除)只需要接近常量的时间即0(1)的时间级。实际上,这只需要几条机器指令。

哈希表运算得非常快,在计算机程序中,如果需要在一秒种内查找上千条记录通常使用哈希表(例如拼写检查器)哈希表的速度明显比树快,树的操作通常需要O(N)的时间级。哈希表不仅速度快,编程实现也相对容易。

如果不需要有序遍历数据,并且可以提前预测数据量的大小。那么哈希表在速度和易用性方面是无与伦比的。

缺点:它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以程序员必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值