TreeMap的源码学习
TreeMap的源码学习
一)、TreeMap的特点
根据key值进行排序。
二)、按key值排序的两种排序算法实现
1).在构造方法中传入比较器
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
比较器comparator实现Comparator接口,实现compare(T o1, T o2)方法;
int compare(T o1, T o2);
2).key值实现Comparable接口,重写 compareTo(key k)方法
T implements Comparable<T>{
@override
public int compareTo(T k)
}
注: 对于TreeMap而言,排序是一个必须进行的过程,要正常使用TreeMap必须制 定排序规则,加入Comparator或key对象实现Comparable接口,若没有制定 比较规则则会抛出java.lang.ClassCastException。
因为String对象默认实现了Comparable接口,实现了comparaTo方法,使用String类型作为key值,不用进行排序。
三)、TreeMap的数据结构
红黑树:Entry<k, v>
Entry<k ,v> 对象的属性:
K key;
V value;
Entry<k, v> left;
Entry<k, v> right;
Entry<k, v> parent;
boolean color = BLACK;
红黑树是一种平衡查找树.
四)、TreeMap的主要属性
//比较器
private final Comparator<? super K> comparator;
//树的根节点
private transient Entry<K,V> root;
//节点个数即元素个数
private transient int size = 0;
//修改次数
private transient int modCount = 0;
//用于构造红黑树
private static final boolean RED = false;
private static final boolean BLACK = true;
五)、TreeMap的put(K key, V value)方法
步骤:
1).获取root节点,判断是否第一次添加元素 ,若是第一次添加元素则将该元素设为根节点。
2).如若不是第一次添加,根据key值,调用比较规则从根节点开始比较左右子树直至到达叶子节点,根据key的比较结果决定放置到叶子节点的左树位置或右树位置,> 0放置右树, < 0 放置右树。
3).fixAfterInsertion修改插入元素后树的结构,转为红黑树。
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("a","v");
public V put(K key, V value) {
//获取根节点
Entry<K,V> t = root;
//若根节点为空,直接将元素设为树的根节点,不用遍历左右子树
if (t == null) {
compare(key, key); // type (and possibly null) check
//将元素设为树的根节点
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
//根据排序规则将元素插入到树结构中
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
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);
}
//使用key 实现Comparable的compareTo()规则
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
/**
如果Key没有加入比较器或没有实现Comparable这里就
抛出java.lang,ClassCastException
*/
Comparable<? super K> k = (Comparable<? super K>) key;
//一直比较左右子树的key值,直至到达叶子节点
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
//根据返回的比较结果决定插入节点的位置
Entry<K,V> e = new Entry<>(key, value, parent);
//< 0 作为节点的左子树
if (cmp < 0)
parent.left = e;
// > 0 作为节点的右子树
else
parent.right = e;
//调整插入元素的树结构,转为红黑树
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
六)、TreeMap的get(K key)方法
步骤:
1).获取根节点
2).从根节点开始比较左右子树的key值
3).若树中某一节点的key值与查找的key值相等,则返回对应的Entry<k, v>对象
treeMap.get("a");
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
//判断是否存在比较器,若有比较器,则使用比较器的比较规则
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
//没有比较器使用comparale的compareTo()规则
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
//从根节点遍历左右子树,若key值相等,则返回当前节点对象
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
注:TreeMap的功能比HashMap的功能强大, 实现了sortedMap接口,可以对元素 进行排序,单TreeMap的性能却略低于HashMap,当需要对集合进行排序操作可使用TreeMap.
TreeMap的源码学习的更多相关文章
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- Dubbo源码学习--集群负载均衡算法的实现
相关文章: Dubbo源码学习文章目录 前言 Dubbo 的定位是分布式服务框架,为了避免单点压力过大,服务的提供者通常部署多台,如何从服务提供者集群中选取一个进行调用, 就依赖Dubbo的负载均衡策 ...
- HashMap的源码学习以及性能分析
HashMap的源码学习以及性能分析 一).Map接口的实现类 HashTable.HashMap.LinkedHashMap.TreeMap 二).HashMap和HashTable的区别 1).H ...
- jQuery源码学习感想
还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...
- MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)
前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...
- MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)
前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)
前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)
前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...
- 我的angularjs源码学习之旅2——依赖注入
依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...
随机推荐
- python中的__call__函数
简单实例: class TmpTest: def __init__(self, x, y): self.x = x self.y = y def __call__(self, x, y): self. ...
- 工厂模式在mvc模型中的应用
在web开发中我们常用mvc模式进行web应用的开发 当应用进入service 层的时候我们根据不同的业务多逻辑进行处理 当有数据进入controller的时候 public class Virtua ...
- 基于 HTML5 + WebGL 的 3D 可视化挖掘机
前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...
- JavaScript 变量作用域和声明提升
一.变量作用域 说到这个概念,不有自主的想到this,scope 这两个关键字. JavaScript的this总是指向一个明确的对象,这个对象是在执行的时候动态绑定的.通俗的说就是谁调用我,我的th ...
- 微信小程序和微信小程序之间的跳转和传参示例代码附讲解
一:微信小程序跳转 使用限制 需要用户触发跳转 从 2.3.0 版本开始,若用户未点击小程序页面任意位置,则开发者将无法调用此接口自动跳转至其他小程序. 需要用户确认跳转 从 2.3.0 版本开始,在 ...
- [最新方法]终于解决了 Ubuntu 14.04 网络图标不见了 的问题|Ubuntu14.04 网络图标消失
解决 Ubuntu 14.04 网络图标不见了 消失的问题 这个问题困扰了我大半年了.但是我就硬是不想重新装系统.搜索研究一番发现,这个问题是nm-applet的问题. 然后偶然发现nm-ap ...
- 微信支付 get_brand_wcpay_request fail,Undefined variable: openid
本文将为您描述微信H5支付,微信JSAPI支付返回支付签名验证失败的解决方法 微信JSAPI支付时报这个错误 查看错误详情 alert(JSON.stringify(res)) 微信商户平台相关设置: ...
- Mysql数据库(三)Mysql表结构管理
一.MySQL数据类型 1.数字类型 (1)整数数据类型包括TINYINT/BIT/BOOL/SMALLINT/MEDIUMINT/INT/BIGINT (2)浮点数据类型包括FLOAT/DOUBLE ...
- 小白初入Python人工智能
想要了解人工智能首先要知道“百度大脑”(https://ai.baidu.com/?track=cp:aipinzhuan|pf:pc|pp:AIpingtai|pu:title|ci:|kw:100 ...
- 设计模式C++描述----22.访问者(Visitor)模式
一. 访问者模式 定义:表示一个作用于某对象结构中的各元素的操作.它你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 结构如下: 二. 举例 假设有一项科学实验,是用来对比两种种子在不同环 ...