HashMap、LinkedHashMap、TreeMap三者的区别


前言

HashMap、LinkedHashMap 和 TreeMap 都是 Java 集合中用于存储键值对的 Map 接口的实现类,但它们在底层数据结构、元素顺序、性能以及使用场景等方面存在明显的区别,以下为各个方面的区别:
在这里插入图片描述

底层数据结构

  • HashMap:JDK 8 及以后的版本中,HashMap底层采用数组 + 链表 + 红黑树的数据结构。数组作为哈希表的基础存储结构,每个数组元素称为一个桶(bucket)。当发生哈希冲突时,会将相同哈希值的元素以链表的形式存储在桶中。当链表长度超过 8 且数组长度大于 64 时,链表会转换为红黑树,以提高查找效率。
  • LinkedHashMap:继承自HashMap,它在 HashMap的基础上增加了一个双向链表,用于维护元素的插入顺序或访问顺序。这个双向链表将所有的键值对连接起来,使得元素可以按照特定的顺序进行遍历。
  • TreeMap:底层使用红黑树(一种自平衡的二叉搜索树)来存储键值对。红黑树的每个节点包含一个键值对,并且根据键的自然顺序或者指定的比较器顺序进行排序。

元素顺序

  • HashMap:不保证元素的插入顺序,也不保证元素的顺序会随着时间的推移保持不变。在进行遍历操作时,元素的顺序是不确定的。
  • LinkedHashMap:可以维护元素的插入顺序,即按照元素插入的先后顺序进行遍历。此外,它还可以通过构造函数指定按照访问顺序(access - order)进行排序,最近访问的元素会被移动到链表的尾部。
  • TreeMap:会根据键的自然顺序或者指定的比较器顺序对元素进行排序。在进行遍历操作时,元素会按照键的排序顺序依次被访问。

性能

  • HashMap:插入、查找和删除操作的平均时间复杂度为O(1),但在最坏情况下(所有元素都存储在同一个链表中),时间复杂度会退化为O(n) 。由于 HashMap 不需要维护元素的顺序,因此在不考虑元素顺序的场景下,它的性能是最好的。
  • LinkedHashMap:插入、查找和删除操作的时间复杂度同样为O(1),因为它继承自 HashMap,底层的哈希表操作性能与 HashMap 相同。但由于需要维护双向链表,会额外消耗一些空间和时间用于链表的维护。
  • TreeMap:插入、查找和删除操作的时间复杂度为O(log n),因为红黑树的插入、查找和删除操作都需要进行树的平衡调整,以保证树的高度始终保持在O(log n)级别。相比于 HashMap 和 LinkedHashMap,TreeMap 的性能相对较低。

使用场景

  • HashMap:适用于不需要维护元素顺序,只需要快速进行插入、查找和删除操作的场景。例如,缓存系统、数据统计等。
  • LinkedHashMap:适用于需要维护元素插入顺序或者访问顺序的场景。例如,实现 LRU(Least Recently Used,最近最少使用)缓存时,可以使用 LinkedHashMap 并将其访问顺序设置为 true,这样当缓存满时,最近最少访问的元素会自动被移除。
  • TreeMap:适用于需要根据键的排序顺序进行遍历或者查找的场景。例如,对数据进行排序统计、范围查找等。

代码示例

public static void main(String[] args) {
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("cz", 3);
        hashMap.put("ae", 1);
        hashMap.put("br", 2);
        System.out.println("HashMap: " + hashMap);

        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("cz", 3);
        linkedHashMap.put("ae", 1);
        linkedHashMap.put("br", 2);
        System.out.println("LinkedHashMap: " + linkedHashMap);

        TreeMap<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("cz", 3);
        treeMap.put("ae", 1);
        treeMap.put("br", 2);
        System.out.println("TreeMap: " + treeMap);

        System.out.println("hashMap");
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println("linkedHashMap");
        for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println("TreeMap");
        for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
}

总结

|-- HashMap、LinkedHashMap、TreeMap的区别 
|   |-- 底层数据结构 
|   |   |-- HashMap 
|   |   |   |-- 数组 + 链表 + 红黑树 
|   |   |   |-- 哈希冲突存链表,长超8且数组长超64转红黑树 
|   |   |-- LinkedHashMap 
|   |   |   |-- 继承HashMap 
|   |   |   |-- 增加双向链表维护顺序 
|   |   |-- TreeMap 
|   |       |-- 红黑树 
|   |       |-- 按键排序存键值对 
|   |-- 元素顺序 
|   |   |-- HashMap 
|   |   |   |-- 不保证插入顺序 
|   |   |   |-- 遍历顺序不确定 
|   |   |-- LinkedHashMap 
|   |   |   |-- 可维护插入顺序 
|   |   |   |-- 可按访问顺序排序 
|   |   |-- TreeMap 
|   |       |-- 按键自然或指定比较器顺序排序 
|   |       |-- 遍历按键排序顺序 
|   |-- 性能 
|   |   |-- HashMap 
|   |   |   |-- 平均O(1),最坏O(n) 
|   |   |   |-- 不考虑顺序性能最佳 
|   |   |-- LinkedHashMap 
|   |   |   |-- O(1) 
|   |   |   |-- 维护链表有额外开销 
|   |   |-- TreeMap 
|   |       |-- O(log n) 
|   |       |-- 性能相对低 
|   |-- 使用场景 
|   |   |-- HashMap 
|   |   |   |-- 不维护顺序,快速操作 
|   |   |   |-- 缓存、统计等 
|   |   |-- LinkedHashMap 
|   |   |   |-- 维护插入或访问顺序 
|   |   |   |-- LRU缓存等 
|   |   |-- TreeMap 
|   |       |-- 按键排序遍历或查找 
|   |       |-- 排序统计、范围查找等 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值