JAVA集合源码分析系列:TreeMap源码分析
来源:互联网 发布:淘宝产品会自动下架吗 编辑:程序博客网 时间:2024/05/21 17:05
TreeMap源码分析
treemap的数据结构基础是红黑树。
可以到如下复习一下红黑树:
http://blog.csdn.net/a910626/article/details/54378874
节点
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; /** * Make a new cell with given key, value, and parent, and with * {@code null} child links, and BLACK color. */ // 根据给定的键、值、父节点构造一个节点,颜色是默认的黑色 Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } /** * Returns the key. * * @return the key */ // 获取节点的key public K getKey() { return key; } /** * Returns the value associated with the key. * * @return the value associated with the key */ // 获取节点的value public V getValue() { return value; } /** * Replaces the value currently associated with the key with the given * value. * * @return the value associated with the key before this method was * called */ // 修改并返回当前节点的value(返回的是旧的value) public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } // 判断节点相等的方法(两个节点为同一类型且key值和value值都相等时两个节点相等) public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return valEquals(key,e.getKey()) && valEquals(value,e.getValue()); } // 节点的哈希值计算方法 public int hashCode() { int keyHash = (key==null ? 0 : key.hashCode()); int valueHash = (value==null ? 0 : value.hashCode()); return keyHash ^ valueHash; } public String toString() { return key + "=" + value; } }
Entry类比较简单,实现了树节点的必要内容,提供了hashCode方法等。
TreeMap的父类和实现的接口
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
TreeMap继承自AbstractMap,AbstractMap实现了Map接口。
TreeMap实现了NavigableMap接口?
TreeMap实现了Cloneable接口
TreeMap实现了Serializable接口
构造函数
public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; }
就不说了
属性
/** * The comparator used to maintain order in this tree map, or * null if it uses the natural ordering of its keys. * * @serial */ // 用于保持顺序的比较器,如果为空的话使用自然顺序保持key的顺序 private final Comparator<? super K> comparator; // 根节点 private transient Entry<K,V> root; /** * The number of entries in the tree */ // 树中节点数量 private transient int size = 0; /** * The number of structural modifications to the tree. */ // ??? private transient int modCount = 0;
行为
下面从put/get方法开始,逐个分析TreeMap的方法。
put方法
public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { compare(key, key); // type (and possibly null) check // 如果根节点为null,将传入的键值对构造成根节点(根节点没有父节点,所以传入的父节点为null) 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; // 使用比较器比较父节点和插入键值对的key值的大小 cmp = cpr.compare(key, t.key); // 插入的key较大 if (cmp < 0) t = t.left; // 插入的key较小 else if (cmp > 0) t = t.right; // key值相等,替换并返回t节点的value(put方法结束) else return t.setValue(value); } while (t != null); } // 没有比较器 else { // key为null,抛出空指针异常 if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; // 与if里面的do while类似,只是比较的方式不同 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); } // 没有找到key相同的节点才会有下面的操作 // 根据传入的键值对和找到的父节点创建新节点 Entry<K,V> e = new Entry<>(key, value, parent); // 根据最后一次的判断结果确认新节点是父节点的左孩子还是右孩子 if (cmp < 0) parent.left = e; else // 对加入新节点的树进行调整 parent.right = e; fixAfterInsertion(e); // 记录size和modcount size++; modCount++; // 因为是插入新节点,所以返回的是null return null; }
首先一点通性是TreeMap的put方法和其他Map的put方法一样,向Map中加入键值对,若原先“键(key)”已经存在则替换“值(value)”,并返回原先的值。
在put(K key,V value)方法的末尾调用了fixAfterInsertion(Entry
get方法
public V get(Object key) { Entry<K,V> p = getEntry(key); return (p==null ? null : p.value); }
get(Object key)通过key获取对应的value,它通过调用getEntry(Object key)获取节点,若节点为null则返回null,否则返回节点的value值。下面是getEntry(Object key)的内容,来看它是怎么寻找节点的。
final Entry<K,V> getEntry(Object key) { // Offload comparator-based version for sake of performance // 如果有比较器,返回getEntryUsingComparator的结果 if (comparator != null) return getEntryUsingComparator(key); // 查找的key为null,抛出空指针 if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; // 获取根节点 Entry<K,V> p = root; // 对树进行遍历查找节点 while (p != null) { // 把key和当前节点的key进行比较 int cmp = k.compareTo(p.key); // key小于当前节点的key if (cmp < 0) // p移动到左节点上 p = p.left; // key小于当前节点的key else if (cmp > 0) // p移动到右节点上 p = p.right; // key值相等则当前节点就是要找的节点 else return p; } return null; }
上面主要是处理实现了可比较接口的情况,而有比较器的情况在getEntryUsingComparator(Object key)中处理了,下面来看处理的代码。
final Entry<K,V> getEntryUsingComparator(Object key) { K k = (K) key; // 获取比较器Comparator<? super K> cpr = comparator;// 其实在调用此方法的get(Object key)中已经对比较器为null的情况进行判断,这里是防御性的判断if (cpr != null) { // 获取根节点 Entry<K,V> p = root; // 遍历树 while (p != null) { // 获取key和当前节点的key的比较结果 int cmp = cpr.compare(k, p.key); // 查找的key值较小 if (cmp < 0) // p“移动”到左孩子 p = p.left; // 查找的key值较大 else if (cmp > 0) // p“移动”到右节点 p = p.right; // key值相等 else // 返回找到的节点 return p; }}// 没找到key值对应的节点,返回null return null;}
更多方法就不再深入啦
应用场景
我们知道treemap的底层数据结构是红黑树,红黑树的优点是什么:插入、查找、删除效率综合来说都比二叉排序树、平衡二叉树要好一些。
与HashMap相比,TreeMap的key是有序的。
参考资料
http://www.importnew.com/16679.html
http://www.cnblogs.com/hzmark/archive/2013/01/02/TreeMap-Base.html
http://blog.csdn.net/hustyangju/article/details/27214251
https://www.nowcoder.com/questionTerminal/16ff3fe9d0e748ffb37212fdc280bef9
- Java集合系列之TreeMap源码分析
- JAVA集合源码分析系列:TreeMap源码分析
- Java集合之TreeMap源码分析
- Java集合之TreeMap源码分析
- 《Java源码分析》:TreeMap
- 《Java源码分析》:TreeMap
- java源码分析05-TreeMap
- Java集合:TreeMap使用详解及源码分析
- java源码分析之集合框架TreeMap 12
- java 中的集合(十四) TreeMap源码分析
- java集合(6):TreeMap源码分析(jdk1.8)
- Java集合框架09--TreeMap和源码分析(一)
- 【Java8源码分析】集合框架-TreeMap
- JAVA集合源码分析系列:ArrayList源码分析
- JAVA集合源码分析系列:LinkedList源码分析
- JAVA集合源码分析系列:HashMap源码分析
- JAVA集合源码分析系列:HashSet源码分析
- JAVA集合源码分析系列:TreeSet源码分析
- Linux进程隐藏
- Super Pow--C++ Clean and Short Solution
- Oralce和Innodb MVCC关键机制
- JAVA集合源码分析系列:TreeSet源码分析
- UPnP基本原理以及在NAT中的应用
- JAVA集合源码分析系列:TreeMap源码分析
- nyoj55懒省事的小明
- it项目经理面试题
- 用Java语言编写文件的复制
- JAVA常用类
- M文件与M函数
- Linux命令总结
- 第十二周上机实践项目(1)
- Shell 传递参数