TreeMap与TreeSet的源码分析
1、TreeMap源码
1、属性部分:
- 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> {
- K key;
- V value;
- Entry<K,V> left;
- Entry<K,V> right;
- Entry<K,V> parent;
- boolean color = BLACK;
- ...
- 重写了equals、hashCode、toString方法等
2、构造器部分:
- public TreeMap() {//无参构造
- comparator = null;
- }
- public TreeMap(Comparator<? super K> comparator) {//带比较器构造
- this.comparator = comparator;
- }
- public TreeMap(Map<? extends K, ? extends V> m)
- public TreeMap(SortedMap<K, ? extends V> m)
3、put方法:
- 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;//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);
- }
- //无自带比较器,使用默认的比较机制:
- else {
- if (key == null)
- throw new NullPointerException();
- @SuppressWarnings("unchecked")
- Comparable<? super K> k = (Comparable<? super K>) key;
- do {
- parent = t;
- cmp = k.compareTo(t.key);//注意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);
- if (cmp < 0)
- parent.left = e;
- else
- parent.right = e;
- fixAfterInsertion(e);
- size++;
- modCount++;
- return null;
- }
注意:
<1>:首先,如果想往TreeMap中存放Entry<K,V>,那么其K必须是实现compareTo方法的,那么K所对应的类需要implements comparable接口。当然常用类中已经重写了这个方法,所以我们可以直接使用:TreeMap.put(int a,String b)等;
<2>:TreeMap是基于红黑树的数据结构,TreeMap中判断新入元素的存储位置时,只需要通过compareTo方法判断两个对象的Key是否相同:相同,则更新Value,返回旧值Value;不同,则插在左或右子节点上,不同于HashMap通过Key的hashCode判断存储位置,所以即使在TreeMap中没有hashCode和equals方法的重写,对于put也没有影响。
<3>:put入新节点后,TreeMap需要调整整个红黑树的结构。后续学习......;
2、TreeSet的add源码
public boolean add(E e) { return m.put(e, PRESENT)==null; }
看到add只需要接收一个参数e,m是一个 private transient NavigableMap<E,Object> m; ,接口,其实现类是TreeMap,因此知道,TreeSet的add通过调用TreeMap的put方法实现添加节点操作,但是由于add只接收一个形参e,故TreeSet生成了一个PRESENT以构成<K,V>的形式,PRESENT是 private static final Object PRESENT = new Object(); 完全是用来凑得嘛。
但是一定要注意:TreeMap的put中当通过comparedTo判断两个节点的Key相等时,会更新Value。而TreeSet的Value并没有什么作用,故可Key还是原来的Key,并没有发生改变。
总结:如果要插入新元素到TreeMap或TreeSet中:
1、TreeMap中若newKey.compareTo(oldkey)返回值是0,那么Key不变,更新Value的值为newValue,返回oldValue。
2、TreeSet中,简单可以理解为不更新(因为我们只用Key)。
实例:
- public class C1 implements Comparable {
- String attr1="attr";
- static int attr2=2;//注意static
- public C1(String attr1,int attr2){
- this.attr1=attr1;
- this.attr2=attr2;
- }
- public String getAttr1() {
- return attr1;
- }
- public void setAttr1(String attr1) {
- this.attr1 = attr1;
- }
- public int getAttr2() {
- return attr2;
- }
- public void setAttr2(int attr2) {
- this.attr2 = attr2;
- }
- @Override
- public int compareTo(Object that) {
- // return ((C1)that).attr2-((C1)this).getAttr2();
- return 0;
- }
- public String toString(){return "attr1="+attr1+",attr2="+attr2+";";}
- public boolean equals(Object that){
- return attr1==((C1)that).getAttr1();
- }
- public int hashCode(){return attr2;}
- public static void main(String[] args) {
- Set set=new TreeSet();
- C1 c1=new C1("sttr",4);
- set.add(c1);
- C1 c2=new C1("sttr",5);
- set.add(c2);
- set.add(new C1("sttr",5));
- set.add(new C1("sttr",3));
- set.add(new C1("sttr2",2));
- System.out.println(set);
- }
- }
- [attr1=sttr,attr2=2;]
- //为什么是2?注意attr2是static的,最后一个new C1(..)会改变该所有对象的attr2值。TreeSet没有不会更新Key(就是这个对象new C1(..))
结果1
- [attr1=sttr,attr2=4;]
- //正常,没有更新
结果2
- //compareTo第一行,attr2不带static
- [attr1=sttr,attr2=5;, attr1=sttr,attr2=4;, attr1=sttr,attr2=3;, attr1=sttr2,attr2=2;]
结果3
- //compareTo第一行,attr2带static
- [attr1=sttr,attr2=2;]
结果4
TreeMap与TreeSet的源码分析的更多相关文章
- TreeMap实现原理及源码分析之JDK8
转载 Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例 一.TreeMap 简单介绍 什么是Map? 在数组中我们通过数组下标来对数组内容进行索引的,而在Map中我们通过对象来对 ...
- TreeMap实现原理及源码分析
TreeMap是一个有序的key-value集合,基于红黑树(Red-Black tree)实现.该映射根据其键的自然顺序进行排序,或者根据创建时提供的Comparator进行排序. 对于TreeMa ...
- Java集合源码分析(六)TreeSet<E>
TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...
- 死磕 java集合之TreeSet源码分析
问题 (1)TreeSet真的是使用TreeMap来存储元素的吗? (2)TreeSet是有序的吗? (3)TreeSet和LinkedHashSet有何不同? 简介 TreeSet底层是采用Tree ...
- 集合之TreeSet(含JDK1.8源码分析)
一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...
- Java集合源码分析(十)——TreeSet
简介 TreeSet就是一个集合,里面不能有重复的元素,但是元素是有序的. TreeSet其实就是调用了TreeMap实现的,所以,它也不是线程安全的.可以实现自然排序或者根据传入的Comparato ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- 【集合框架】JDK1.8源码分析之TreeMap(五)
一.前言 当我们需要把插入的元素进行排序的时候,就是时候考虑TreeMap了,从名字上来看,TreeMap肯定是和树是脱不了干系的,它是一个排序了的Map,下面我们来着重分析其源码,理解其底层如何实现 ...
- TreeMap 源码分析
简介 TreeMap最早出现在JDK 1.2中,是 Java 集合框架中比较重要一个的实现.TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey.get.p ...
随机推荐
- java-poi 批量导入excel数据
1,首先,前端发送MultipartFile类型文件,后端接收 2,分别创建多个ImportParams对象(easypoi),对应工作蒲 注意:pom中 要有相对应的配置 <!-- easyp ...
- java宝典笔记(一)
第四章java基础知识 4.1基本概念 一.java优点 1.面向对象(封装.继承.多态) 2.可移植性.平台无关,一次编译,到处运行.Windows,Linux,macos等.java为解释性语言, ...
- 思科VTP协议(后面有配置案例)
一.VTP相关理论介绍 1.1 VTP(VLAN trunking protocol)协议是用来在整个交换网络中分发和同步VLAN数据库的,是一个二层协议,思科私有协议. 1.2 VTP域是由一台或者 ...
- mysql安装后,过一段时间,在命令行无法启动
这种问题主要是MYsql没有启动起来,可以在启动管理中开启mysql此服务即可解决
- Golang 包管理机制
Golang 包管理机制 1. 历史 在go1.11之前, 并没有官方的包管理机制(Godep算个半官方), 主流的包管理机制有: GoVendor Glide Godep 在go1.11之后, 官方 ...
- 什么是闭包?(python)
闭包,又称闭包函数或闭合函数,和嵌套函数类似.不同之处在于,闭包函数的外部函数返回的不是一个具体的值,而是一个函数.一般情况下,返回的函数会赋值给一个变量,便于反复调用. def outer(out) ...
- C#内联函数 特性 MethodImplOptions.AggressiveInlining)
[MethodImpl(MethodImplOptions.AggressiveInlining)] 内联函数 Impl:implement的缩写 内联函数 在计算机科学中,内联函数(有时称作在线函数 ...
- 【C# 线程】内存模型(C#)---非常重要 【多线程、并发、异步的基础知识】
内存模型概述 MSDN:理论与实践中的 C# 内存模型 MSDN:理论与实践中的 C# 内存模型,第 2 部分 内存模型就是内存一致性模型. 以下内如来自维基百科 内存一致性模型列表 线性一致性(Li ...
- yum报错 , yum相关配置信息,yum重装
docker源的问题 yum有很多错,比如网络问题,dns问题,timeout 错,还有不知道什么错误 网上有很多,网络问题,dns问题,但是我ping www.baidu.com通,所以不是这个问题 ...
- Python:GUI库tkinter(二)
学习自: Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) - 洪卫 - 博客园 Tkinter简明教程 - 知乎 TkDocs_官方文档 一个Tkinter库较为全面的总结,很 ...