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 的时候,都会把当前访问的节点,移动到链表的尾部,慢慢的,就会使头部的节点都是最少被访问的元素

Java TreeMap 和 LinkedHashMap【笔记】的更多相关文章
- [Java] TreeMap - 源代码学习笔记
		
TreeMap 实现了 SortedMap 和 NavigableMap 接口,所有本文还会记录 SortedMap 和 NavigableMap 的阅读笔记. SortedMap 1. 排序的比较应 ...
 - Java笔记(八)TreeMap & TreeSet & LinkedHashMap
		
TreeMap & TreeSet & LinkedHashMap 一.TreeMap HashMap缺陷:键值对之间没有特定的顺序.在TreeMap中, 键值对之间按键有序,Tree ...
 - 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap
		
参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...
 - Java性能调优笔记
		
Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...
 - 从头认识java-15.7 Map(7)-TreeMap与LinkedHashMap
		
这一章节我们来讨论一下Map两个比較经常使用的实现:TreeMap与LinkedHashMap. 1.TreeMap 特性:依照key来排序 package com.ray.ch14; import ...
 - JAVA编程思想读书笔记(二)--容器
		
接上篇JAVA编程思想读书笔记(一) 第八章.对象的容纳 No1: java提供了四种类型的集合类:Vector(矢量).BitSet(位集).Stack(堆栈).Hashtable(散列表) No2 ...
 - Java二次复习笔记(1)
		
Java二次复习笔记(1) Java采用的默认字符编码集是Unicode. byte=byte+byte报错,值为int,而byte+=byte不报错.同样short = short+short报错, ...
 - JAVA GUI编程学习笔记目录
		
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
 - Java编程思想重点笔记(Java开发必看)
		
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
 
随机推荐
- ROS2学习之旅(1)——初识ROS2
			
本系列用来记录ROS2的学习过程,有错误或者不合理的地方请大家指正.由于博主具有ROS1的学习经历,会添加一些与ROS1的一些对比,当然这对于ROS2本身的学习内容没有丝毫影响,欢迎大家积极与我在评论 ...
 - 【重学Java】Set集合
			
Set集合 Set集合概述和特点[应用] 无序不可重复 没有索引,不能使用普通for循环遍历.可以使用迭代器或者增强foreach语句遍历 TreeSet集合 TreeSet集合概述和特点[应用] 无 ...
 - CentOS-Docker搭建Nacos-v1.3.2(单点)
			
说明:从v1.3.1版本开始支持自定义mysql-8.x 通用属性配置(v1.3.2) name description option MODE cluster模式/standalone模式 clus ...
 - php结合redis实现高并发下的抢购、秒杀功能 (转)
			
抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易 ...
 - linux学习之路第三天(vim和vi使用)
			
vi和vim编辑器 vi和vim的三种常见模式 1.正常模式 在正常模式下,我们可以使用快捷键 以vim打开一个档案就直接进入一般模式了(这是默认的模式).在这个模式中,你可以使用 上下左右按键来移动 ...
 - Linux下如何使用Rsync备份服务器重要数据
			
Rsync介绍: Rsync英文全称Remote synchronization,从软件的名称就可以看出来,Rsync具有可使本地和远程两台主机之间的数据快速复制同步镜像,远程备份的功能,这个功能类似 ...
 - mysql中函数cast使用
			
CAST函数语法规则是:Cast(字段名 as 转换的类型 ),其中类型可以为: CHAR[(N)] 字符型DATE 日期型DATETIME 日期和时间型DECIMAL float型SIGNED in ...
 - asp网页防止乱码
			
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> <%Session.CodePage=65001%> ...
 - 【剑指offer】52. 两个链表的第一个公共节点
			
剑指 Offer 52. 两个链表的第一个公共节点 知识点:链表: 题目描述 输入两个链表,找出它们的第一个公共节点. 如下面的两个链表: 示例 示例1: 输入:intersectVal = 8, l ...
 - pip install 默认安装路径修改
			
一.使用命令查看pip默认安装目录 python -m site 这里的USER_BASE和USER_SITE其实就是默认的启用Python通过pip自动下载的脚本和依赖安装包的基础路径. 接着使用命 ...