HashMap、TreeMap、HashTable的比较

HashMap

概述

HashMap是基于哈希表(散列表),实现Map接口的双列集合,数据结构是“链表散列”,也就是数组+链表 ,key唯一的value可以重复,允许存储null 键null 值,元素无序HashMap不是线程安全的

哈希表

数组:通过索引,时间复杂度O(1),通过给定值查找,需要遍历数组,自已对比复杂度为O(1) 二分查找插值查找,复杂度为O(logn)
线性链表:增 删除仅处理结点,时间复杂度O(1)查找需要遍历也就是O(n)
哈希表:哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1)哈希表的主干就是数组

hash冲突

如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突,也叫哈希碰撞。前面我们提到过,哈希函数的设计至关重要,好的哈希函数会尽可能地保证 计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式

链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好.
在这里插入图片描述
HashMap的底层就是一个数组,数组中每一项有事一个链表,当新建一个HashMap时候,就会初始化一个数组,也就是上面的table ,Entry结构就是static的包含key value 还有一个next的指针,指向下一个元素的引用,也就构成了链表

HashMap的容量

当 HashMap 中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的,所以为了提高查询的效率,就要对HashMap的数组进行扩容,在HashMap数组扩容之后,最消耗性能的点是:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是 resize(rehash)
loadFactor指的是负载因子 HashMap能够承受住自身负载(大小或容量)的因子,loadFactor的默认值为 0.75认情况下,数组大小为 16,那么当HashMap中元素个数超过 160.75=12 的时候,就把数组的大小扩展为 216=32,即扩大一倍,并且总是2的n次方(这样数据在数组的分布比较均匀,也就是说减少碰撞的几率,减少了链表的遍历,提升效率),然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知 HashMap 中元素的个数,那么预设元素的个数能够有效的提高 HashMap 的性能

HashMap和TreeMap比较

(1)HashMap:适用于在Map中插入、删除和定位元素。
(2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
(3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.
(4)HashMap 非线程安全 TreeMap 非线程安全
(5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。

在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。

发布了14 篇原创文章 · 获赞 0 · 访问量 545

猜你喜欢

转载自blog.csdn.net/hello_v_world/article/details/104008110