1.hashmap查插删改的时间复杂度

是常数,最坏的情况(键值全部冲突)复杂度上升为O(n)

2.哈希函数

一般的说,Hash函数可以划分为如下几类:
1. 加法Hash

2. 位运算Hash

3. 乘法Hash

4. 除法Hash

5. 查表Hash

6. 混合Hash

7.数组Hash

3.哈希冲突的解决办法

一般比较常用的方法有开放地址法:(内容来自百度百科) 
1. 开放寻址法:Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法: 
1.1. di=1,2,3,…,m-1,称线性探测再散列;顺序查看表的下一单元,直至找到某个空单元,或查遍全表。 
1.2. di=1^2,-1^2,2^2,-2^2,⑶^2,…,±(k)^2,(k<=m/2)称二次探测再散列;在表的左右进行跳跃式探测。 
1.3. di=伪随机数序列,称伪随机探测再散列。根据产生的随机数进行探测。

2 再散列法:建立多个hash函数,若是当发生hash冲突的时候,使用下一个hash函数,直到找到可以存放元素的位置。

3 拉链法(链地址法):就是在冲突的位置上简历一个链表,然后将冲突的元素插入到链表尾端,

4 建立公共溢出区:将哈希表分为基本表和溢出表,将与基本表发生冲突的元素放入溢出表中。

4.hashmap的底层实现(stl)

数组+链表(拉链法)

使用一个下标范围比较大的数组来存储元素(桶)

插入过程

  1. 得到key
  2. 通过hash函数得到hash值
  3. 得到桶号(一般都为hash值对桶数求模)
  4. 存放key和value在桶内

其取值过程是:

  1. 得到key
  2. 通过hash函数得到hash值
  3. 得到桶号(一般都为hash值对桶数求模)
  4. 比较桶的内部元素是否与key相等,若都不相等,则没有找到。
  5. 取出相等的记录的value。

stl的实现方法是数组存桶,桶中是一个链表来存在具体的数据

也就是说一个桶中可能有多个hash值相同的数据(key-value)

因此取数据时需要用到比较函数

5.装载因子

当前元素数量除以桶的数量

6.rehash

当装载因子>=1时(默认),认为当前hashmap需要扩容来减少冲突

因此会增加一些桶数(类似vector扩容)

重新计算出的桶数是比当前桶数大的下一个质数

rehash的过程会重新填装原有的元素

7.素数

用素数作为桶号可以在一定程度上减少冲突

在哈希函数计算桶号时会使用求余计算,假设桶数是2次幂比如4和8

那么10%4与10%8结果一致

如果桶数永远是素数,那么rehash时无论什么冲突解决策略下都可以最大可能的减少冲突

8.什么时候用hashmap什么时候用map

hashmap的总体平均速度要快于map,但是不如map稳定

map使用红黑树(二叉查找树)存放数据,速度是稳定的log2 N

查找速度, 数据量, 内存使用

hashmap平均速度快,map稳定

hashmap适合大数据量,但内存占用更多

 

参考文献

https://zhuanlan.zhihu.com/p/88319168

https://blog.csdn.net/fsfsfsdfsdfdr/article/details/82697289

https://blog.csdn.net/u010025211/article/details/46653519

https://www.cnblogs.com/barrywxx/p/10739871.html