【Java8源码分析】集合框架-TreeMap
来源:互联网 发布:阿里云机房在哪里 编辑:程序博客网 时间:2024/05/16 08:52
一、红黑树原理
TreeMap是基于红黑树实现的。
一棵高度为h的二叉搜索树,它可以支持任何一种基本动态集合操作,其时间复杂度均为O(h)。当h较小时,执行会比较快。红黑树是许多“平衡”搜索树中的一种。
(1)性质
树中的结点有5个属性:color,key,key,left,right和p,满足以下五大性质:
- 每个结点或是Red,或是Black
- 根结点是Black的
- 每个叶结点NIL是Black的
- 如果一个结点是Red,则它的两个结点都是black
- 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的Black结点
(2)旋转
一棵含有n个关键字的红黑树上,搜索树操作插入和删除话费时间在O(lgn)。这两个操作对树做了修改,可能违反红黑性质,为维护这些性质,需改变树中结点颜色以及指针结构,一般通过旋转操作。
二、存储结构
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; Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } 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; } }
三、代码分析
(1)属性域
// 比较器 private final Comparator<? super K> comparator; // 根节点 private transient Entry<K,V> root; private transient int size = 0; // 实现fast-fail机制,跟ArrayList、LinkedList类似 private transient int modCount = 0;
(2)构造函数
// 构造函数 public TreeMap() { comparator = null; } // 带比较器 public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; // 调用putAll把所有元素添加进去 putAll(m); } public TreeMap(SortedMap<K, ? extends V> m) { comparator = m.comparator(); try { // 此方法为从排序集合中构造TreeMap,复杂度为线性 buildFromSorted(m.size(), m.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } } public void putAll(Map<? extends K, ? extends V> map) { int mapSize = map.size(); // 如果TreeMap为空,且map为SortedMap // 则调用从有序集合中构造TreeMap方法 if (size==0 && mapSize!=0 && map instanceof SortedMap) { Comparator<?> c = ((SortedMap<?,?>)map).comparator(); // 如果比较器一样,才执行,否则调用putAll if (c == comparator || (c != null && c.equals(comparator))) { ++modCount; try { // 调用从Sorted构造 buildFromSorted(mapSize, map.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } return; } } // 其他情况执行以下代码 // 内部调用了put,put为TreeMap的添加元素函数 super.putAll(map); } // 从排序序列中构造TreeMap,线性时间 private void buildFromSorted(int size, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) throws java.io.IOException, ClassNotFoundException { this.size = size; root = buildFromSorted(0, 0, size-1, computeRedLevel(size), it, str, defaultVal); } // 真正的从排序序列中构造TreeMap函数 @SuppressWarnings("unchecked") private final Entry<K,V> buildFromSorted(int level, int lo, int hi, int redLevel, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) throws java.io.IOException, ClassNotFoundException { // 策略:树的根节点肯定是排序序列的中间树 // 递归处理根节点的左树、右树 if (hi < lo) return null; int mid = (lo + hi) >>> 1; Entry<K,V> left = null; if (lo < mid) left = buildFromSorted(level+1, lo, mid - 1, redLevel, it, str, defaultVal); // extract key and/or value from iterator or stream K key; V value; if (it != null) { if (defaultVal==null) { Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next(); key = (K)entry.getKey(); value = (V)entry.getValue(); } else { key = (K)it.next(); value = defaultVal; } } else { // use stream key = (K) str.readObject(); value = (defaultVal != null ? defaultVal : (V) str.readObject()); } Entry<K,V> middle = new Entry<>(key, value, null); // color nodes in non-full bottommost level red if (level == redLevel) middle.color = RED; if (left != null) { middle.left = left; left.parent = middle; } if (mid < hi) { Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel, it, str, defaultVal); middle.right = right; right.parent = middle; } return middle; }
(3)查找
final Entry<K,V> getEntry(Object key) { if (comparator != null) return getEntryUsingComparator(key); // TreeMap的key值不能为null if (key == null) throw new NullPointerException(); // 如果未定义Comparator,则采用key的实现的Comparable @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; Entry<K,V> p = root; 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; } // 带有Comparator比较器的查询,原理跟上面类似 final Entry<K,V> getEntryUsingComparator(Object key) { @SuppressWarnings("unchecked") K k = (K) key; Comparator<? super K> cpr = comparator; if (cpr != null) { Entry<K,V> p = root; while (p != null) { int cmp = cpr.compare(k, p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } } return null; }
(4)添加
public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { // 检查是否为null,再次提醒,key值不能为null compare(key, key); root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; 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 // 如果key值相等,覆盖,返回旧值 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); 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; }
(5)删除
// 删除的函数比较复杂一些,主要需要考虑多种情况 // 具体说明可参考算法导论一书 private void deleteEntry(Entry<K,V> p) { modCount++; size--; // If strictly internal, copy successor's element to p and then make p // point to successor. if (p.left != null && p.right != null) { Entry<K,V> s = successor(p); p.key = s.key; p.value = s.value; p = s; } // p has 2 children // Start fixup at replacement node, if it exists. Entry<K,V> replacement = (p.left != null ? p.left : p.right); if (replacement != null) { // Link replacement to parent replacement.parent = p.parent; if (p.parent == null) root = replacement; else if (p == p.parent.left) p.parent.left = replacement; else p.parent.right = replacement; // Null out links so they are OK to use by fixAfterDeletion. p.left = p.right = p.parent = null; // Fix replacement if (p.color == BLACK) fixAfterDeletion(replacement); } else if (p.parent == null) { // return if we are the only node. root = null; } else { // No children. Use self as phantom replacement and unlink. if (p.color == BLACK) fixAfterDeletion(p); if (p.parent != null) { if (p == p.parent.left) p.parent.left = null; else if (p == p.parent.right) p.parent.right = null; p.parent = null; } } }
四、总结
- TreeMap是根据key进行排序的,它的排序和定位需要依赖比较器或覆写Comparable接口,也因此不需要key覆写hashCode方法和equals方法,就可以排除掉重复的key,而HashMap的key则需要通过覆写hashCode方法和equals方法来确保没有重复的key
- TreeMap的查询、插入、删除效率均没有HashMap高,一般只有要对key排序时才使用TreeMap
- TreeMap的key不能为null,而HashMap的key可以为null
五、参考
http://blog.csdn.net/ns_code/article/details/36421085
阅读全文
0 0
- 【Java8源码分析】集合框架-TreeMap
- 【Java8源码分析】集合框架-ArrayList
- 【Java8源码分析】集合框架-LinkedList
- 【Java8源码分析】集合框架-HashMap
- java源码分析之集合框架TreeMap 12
- Java集合框架09--TreeMap和源码分析(一)
- Java8源码-TreeMap
- Java集合系列之TreeMap源码分析
- Java集合之TreeMap源码分析
- Java集合之TreeMap源码分析
- java集合框架10——TreeMap和源码分析(一)
- java集合框架11——TreeMap和源码分析(二)
- 集合框架-TreeMap集合
- JAVA集合源码分析系列:TreeMap源码分析
- Java 集合框架分析:DelayQueue java8
- Java 集合框架-TreeMap
- Java集合框架:TreeMap
- Java集合:TreeMap使用详解及源码分析
- 爬取微博用户数据
- 并发控制中的封锁
- Linux下进程线程
- (50)组件之AI组件
- Vue项目实战(三)- 组件的注册和使用
- 【Java8源码分析】集合框架-TreeMap
- Windows下安装python版的Word2Vec工具包gensim教程(基于Anaconda)
- hadoop利用FileSystem API 执行hadoop文件读写操作
- Matlab:入门知识小总结(Dir函数)
- Linux与Unix究竟有什么区别呢,孰优孰劣?
- PAT甲级1015
- zookeeper
- 高级网络配置及ipv6网络的管理
- poj2488