前言
hash表是编程中常用的数据结构,也是时间复杂度较低的数据结构,一般来说从hash表中取数据的时间复杂度定义为接近常量O(1),为什么取数据如此高效呢,数据是怎么存的呢?接下来来分析下
正文
hash表的内部数据结构为数组,但存储数据并不是顺序存储的,而是由hash算法+分配索引算法来分配索引
比如我要存储int类型的数据,数据为1-10,hash算法为他自身即为hash值,分配算法为求余算法,这时申请一个长度为10的数组,图示如下
而如果数据是[1,2,3,7,8,9,11,12,13,14],则图示如下
结合图和上述算法可以观察得到:
1的hash为1,hash对10求余得1,所以将1放在第1个索引位
11的hash为11,hash对10求余得1,所以也将11放在第1个索引位
此时就发生了hash冲突,hash冲突是无法避免的,如果冲突了可以将指定位置放上一个新的数据结构来存储冲突的一些数据,比如常用的链表
可以观察到第二个图中出现了数据重叠的现象,也出现了有的位置没有存到数据的现象,而继续往大小为10的数组中插入数据,就会令hash冲突越来越严重,导致查询效率越来越低
而一个好的hash算法+分配索引算法可以有效避免hash冲突,而有时需要根据自身需要存储的数据来自定义hash算法来降低hash冲突
而由于上述原因,数组大小为10存储10条数据就会不可避免的出现hash冲突,导致效率降低,所以一般hash表不会将数据存满数组大小,一般会设置一个负载因子(比例),如HashMap的比例为75%,既100大小的hash表最多只存75条数据,但这个比例还是看具体需求,因为设置的大了容易造成hash冲突降低查找等一系列操作的效率,设置的小了会白白浪费内存
优缺点
下面分析一下优缺点
优点:
1.查询速度快,时间复杂度接近常量O(1)
因为其查询可以直接通过hash值拿到索引,省去了遍历对比的时间
2.插入快
基于数组,没什么说的
3.删除快
基于数组
缺点:
1.在使用之前需要确定大概存储的数量
因为数组是无法动态增加的,所以hash表无法简单扩容
ps:HashMap内部使用了hash表作为数据结构,其可以扩容,其内部原理是重新申请一个更大的数组,并根据新数组大小来重新计算索引,其实开销也不小,所以最好是创建时就确认大小
2.无序
因为其内部的hash索引算法,所以其内部存储的数据一般来说是无序的
3.内存占用稍高
因为hash表一般都是将key和value拼成一个对象一起存到一个对象中,而且还有负载因子存在,所以其内存占用比单纯使用数组存储要高
对Kotlin或KMP感兴趣的同学可以进Q群 101786950
如果这篇文章对您有帮助的话
可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)