扩容是元素还是数组_技术连载:数据结构-哈希表、哈希函数、哈希冲突、扩容机制...

前面已经连载完数组、链表、栈、队列以及各自在面试中的考察点,今天来学习哈希表;

哈希表

我对哈希表的理解,本质上是键值对构成的集合;最大的特点是根据key查找value的时间复杂度为1。

原因是:从存储结构上来讲,充分利用了数组按照位置查找,时间复杂度为O(1)的特点;

键值对的位置是通过hash函数对key求哈希值来确定的;

bdb1a62aca7559f31809f29f79e4aaf0.png

存储结构

哈希函数

所有的函数都是完成输入到输出的映射,哈希函数完成的是由key到位置的映射;

即输入时key,输出时其在数组的位置;

设计哈希函数时应注意 以下几点:

  • 函数计算不能过于复杂,这会影响增删查的性能
  • 函数的返回值是int类型,并将尽可能的随机&均匀分布
  • 相同的key必须要得到相同的返回,不同的key最大程度的保证其返回值不同

java的hash函数计算非常巧妙,借助位运算与hashCode实现,而不是直接取模:

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

哈希冲突解决方式

hash冲突:两个不同的key经过hash函数计算之后,得到了同样的位置,这时应该如何存储。

1.开放寻址法

假如hash计算之后,应该存储与第3个位置,但是第三个位置已经有元素,这时候进行加1,即看看第4个位置是否有元素;依次进行直到找到空闲位置。

除了加1之外,还可以加1^2,如果被占用,可以加2^2;依次类推...

或者是经过二次hash等;

开放寻址法的缺点是,但查找元素时,如果hash计算的位置有元素,不一定是查找的元素,需要进行对比;如果不是,则需要按照开放寻址的思路,直到查找至空闲位置为止;

另外删除元素时不能直接删除,否则上面的查找逻辑就会出问题,需要标记为删除。

2. 拉链法

遇见冲突之后,采用链表数据结构;如下图所示:

d29ebe5c598105ed9ff7bcc500bd3e55.png

拉链法

这时查找元素时,首先确定对应位置;然后进行链表遍历。

扩容机制

关于装载因子,指的是数组已使用的个数与数组长度比值,比如数组长度是10,已经有6个位置放置元素,那么装载因子是6/10 = 0.6;

当装载因子大于设定的阈值之后,需要扩容;

哈希表的扩容不同于一般的数据扩容,需要涉及到扩容之后位置的重新计算

java语言中采用的是,当需要扩容时,直接扩容至当前容量的两倍;

扩容时需要注意不要超过最大容量;

核心代码如下:

... ...else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold... ...Node[] newTab = (Node[])new Node[newCap];table = newTab;...//新位置计算newTab[e.hash & (newCap - 1)] = e;
50f55c15cc5bb043efa8cb926cb5fc91.png

实际上,插入元素如果遇见扩容时,效率时非常慢的;

====

技术连载:开篇词

技术连载:连载提纲设计思路

技术连载:数据结构 - 数组

技术连载:数据结构 - 数组常见面试题汇总

技术连载:数据结构 - 链表

技术连载:数据结构 - 链表相关的高频面试题汇总

技术连载:数据结构 - 栈

技术连载:数据结构 - 栈在面试中的应用

技术连载:数据结构 - 队列及其变种(循环、双端、阻塞、并发)

技术连载:数据结构 - 从源码出发分析java中的队列实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值