zoukankan      html  css  js  c++  java
  • Java TreeMap 和 LinkedHashMap【笔记】

    Java TreeMap 和 LinkedHashMap【笔记】

    TreeMap

    TreeMap基本结构

    TreeMap 底层的数据结构就是红黑树,和 HashMap 的红黑树结构一样

    与HashMap不同的是,TreeMap 利用了红黑树左节点小,右节点大的性质,根据 key 进行排序,使每个元素能够插入到红黑树大小适当的位置,维护了 key 的大小关系,适用于 key 需要排序的场景

    TreeMap 常见属性

    //比较器,如果外部有传进来 Comparator 比较器,首先用外部的
    //如果外部比较器为空,则使用 key 自己实现的 Comparable#compareTo 方法
    //比较手段和上面日常工作中的比较 demo 是一致的
    private final Comparator<? super K> comparator;
    
    //红黑树的根节点
    private transient Entry<K,V> root;
    
    //红黑树的已有元素大小
    private transient int size = 0;
    
    //树结构变化的版本号,用于迭代过程中的快速失败场景
    private transient int modCount = 0;
    
    //红黑树的节点
    static final class Entry<K,V> implements Map.Entry<K,V> {}
    

    TreeMap 新增节点

    第一步,判断红黑树的节点是否为空,为空的话,新增的节点直接作为根节点

    代码:

    Entry<K,V> t = root;
    if (t == null) {
        // compare 方法限制了 key 不能为 null
        compare(key, key); 
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    

    第二步,自旋找到key应该新增的位置,然后挂在那个节点的头上,通过 compare 来比较 key 的大小,然后根据红黑树左小右大的特性,进行判断,找到应该新增节点的父节点

    代码:

    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
           do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    

    第三步,在父节点的左边或右边插入新增节点

    代码:

    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    

    第四步,着色旋转,使红黑树达到平衡,结束

    我们可以发现,在新增节点时,利用了红黑树左小右大的特性,从根节点不断往下查找,直到找到节点是 null 为止,在查找的过程中,发现 key 值已经存在的话,就直接覆盖,且TreeMap 是禁止 key 是 null 值的

    LinkedHashMap(没咋理解)

    LinkedHashMap基础结构

    LinkedHashMap 本身是继承 HashMap 的,所以它拥有 HashMap 的所有特性,再此基础上,还提供了两大特性

    第一大特性,按照插入顺序进行访问

    链表特性

    LinkedHashMap 的数据结构,怎么说呢,就像是把 LinkedList 的每个元素换成了 HashMap 的 Node,LinkedHashMap 像是两者的结合体,不过也正是因为增加了这些结构,才能把 Map 的元素都串联起来,形成一个链表,而既然是个链表,那就可以保证顺序了

    按照顺序新增

    在LinkedHashMap 初始化时,我们默认 accessOrder 为 false,意思就是会按照插入顺序提供访问,插入方法使用的是父类 HashMap 的 put 方法,不过覆写了 put 方法执行中调用的 newNode以及newTreeNode 和 afterNodeAccess 方法,put 方法中的newNode以及newTreeNode 方法,可以控制新增节点追加到链表的尾部,这样每次新节点都追加到尾部,即可保证插入顺序了

    按照顺序访问

    LinkedHashMap 只提供了单向访问,即按照插入的顺序从头到尾进行访问,不能像 LinkedList 那样可以做到双向访问,因此主要通过迭代器进行访问,在迭代器初始化的时候,默认从头节点开始访问,在迭代的过程中,不断访问当前节点的 after 节点即可

    Map 对 key、value 和 entity 都提供出了迭代的方法,假设我们需要迭代 entity,就可使用 LinkedHashMap.entrySet().iterator() 这种写法直接返回 LinkedHashIterator ,LinkedHashIterator 是迭代器,我们调用迭代器的 nextNode 方法就可以得到下一个节点

    先前在新增节点时,就已经使用put 方法中的newNode以及newTreeNode 方法来维护元素之间的插入顺序,所以迭代访问时非常简单,只需要不断的访问当前节点的下一个节点即可

    第二大特性,实现了访问最少最先删除功能,其目的是把很久都没有访问的 key 自动删除。

    这种策略其实就是 LRU(Least recently used,最近最少使用),简单来说,在链表中的LRU,就是经常访问的元素会被追加到队尾,这样不经常访问的数据自然就被前移,慢慢靠近队头,然后我们可以通过设置删除策略,比如当 Map 元素个数大于多少时,把头节点删除,这就实现了最少最先的删除

    一些问题:

    HashMap、TreeMap、LinkedHashMap 三者异同?

    相同点:

    1.三者在特定的情况下,都会使用红黑树;
    2.底层的 hash 算法相同;
    3.在迭代的过程中,如果 Map 的数据结构被改动,都会报相同的错(ConcurrentModificationException)

    不同点:

    数据结构

    HashMap 数据结构以数组为主,查询非常快
    TreeMap 数据结构以红黑树为主,利用了红黑树左小右大的特点,可以实现 key 的排序
    LinkedHashMap 在 HashMap 的基础上增加了链表的结构,实现了插入顺序访问和最少访问删除两种策略
    且因为数据结构不一样,三者的上层包装的 api 略有差别

    应用场景

    TreeMap 适合需要根据 key 进行排序的场景
    LinkedHashMap 适合按照插入顺序访问,或需要删除最少访问元素的场景
    剩余场景我们使用 HashMap 即可,我们工作中大部分场景基本都在使用 HashMap

    LinkedHashMap 中的 LRU 是什么意思?是怎么实现的?

    LRU ,英文全称:Least recently used,中文叫做最近最少访问,在 LinkedHashMap 中,也叫做最少访问删除策略

    我们可以通过 removeEldestEntry 方法设定一定的策略,使最少被访问的元素,在适当的时机被删除,原理是在 put 方法执行的最后,LinkedHashMap 会去检查这种策略,如果满足策略,就删除头节点

    保证头节点就是最少访问的元素的原理是:LinkedHashMap 在 get 的时候,都会把当前访问的节点,移动到链表的尾部,慢慢的,就会使头部的节点都是最少被访问的元素

    感谢观看,文笔有限,博客不出彩,还请多多见谅
  • 相关阅读:
    【转】揭秘令牌桶
    各空白字符说明
    【转】Python正则表达式指南
    python的urlparse
    【转】HTTP Header 详解
    ElasticSearch(六)底层索引控制
    ElasticeSearch(五)分布式索引架构
    Elasticsearch(四)优化用户体验
    ElasticSearch(三)不仅仅是查询
    ElasticSearch(二) 关于DSL
  • 原文地址:https://www.cnblogs.com/jokingremarks/p/14488000.html
Copyright © 2011-2022 走看看