l 何为Hash?
经常会听到别人说哈希,哈希算法,哈希表,等词语,但是却没有真正的了解什么叫hash,为了分析哈希表的实现原理,就先解释一下什么叫hash。
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。(百度百科)。
l 一共有多少种数据结构?
最基本的数据结构无非就是数组和链表,这两种数据结构的优点缺点,就不必多说,一个便于快速访问,一个便于快速增删。还有其他数据结构呢?大多数人会说,树、图、队列、堆栈、等等。其实这些无非是数组和链表的结合,有没有什么数据结构既有数组的优点,又有链表的优点呢?这就是笔者所要分析的哈希表,它是数组和链表的结合。
l HashMap的原理图
l HashMap的实现
哈希表的put:
首先将存进来一个数据value和一个key,这时存进来的key需要经过一个hash函数,得到一个映射值,这个表示映射值表示在数组的位置,最简单的hash函数是取余法。然后将相应的value和key,封装成一个结点存进数据,
就会有问题,当下一个数据的映射值和上一个一样是怎么处理?这个问题叫hash的冲突。
Hash冲突的解决,一般有两种方法,一种为开散列方法,一种是闭散列的方法,这里介绍一下开散列的方法,当两个及以上的数映射值一样时,可以将后存进来的value和key封装一个结点存进来,让它的指针指向原来数组中的结点。
这样就相当于冲突时,开了一条链子出去一样。
l HashMap的实现
哈希表的get:
和put一样,先将用key计算hsah值,通过hash值访问相应的数组位置,如果此位置开有散列链,这从头结点一直比对,直到找到相应的value和key匹配的结点。
l HashMap的优缺点以及rehash问题
当使用哈希表时,会出现两种情况,一种是每一个存的数据都发生了冲突,都存在了一个数组位置中。一种是全部完全没有冲突。这两种情况就会使HashMap的作用起到了一个链表,或者一个数组的作用。
所以选择一个好的hash函数很重要,关系到HashMap存储和取的效率问题。
HashMap中的散列程度可以用hash因子表示。一般来说当hash因子较大时,这样的hash函数选取较好。
Rehash问题,就是当HashMap中的数组长度较小,存的数据量过多是,就需要开辟一个更长的数组,将原来的数据一个一个取出来重新计算hash值,在存放。这就是rehash问题。每一次rehash时会使HashMap的性能降低。
HashMap的线程不安全性,这个问题也是HashMap的一个缺点,在两个线程中使用同一个HashMap的时候,如果某一个线程中发生了rehash操作,那么另一个线程中就会发生不确定错误。